#ifdef SEC_TSP_FACTORY_TEST #define BUFFER_MAX ((256 * 1024) - 16) enum { TYPE_RAW_DATA = 0x30, // only for winner, etc 0x31 TYPE_FILTERED_RAW_DATA = 0x31, // only for winner TYPE_BASELINE_DATA = 0x32, TYPE_STRENGTH_DATA = 0x33, }; enum { BUILT_IN = 0, UMS, }; enum ito_error_type { ITO_FORCE_SHRT_GND = 0x60, ITO_SENSE_SHRT_GND = 0x61, ITO_FORCE_SHRT_VDD = 0x62, ITO_SENSE_SHRT_VDD = 0x63, ITO_FORCE_SHRT_FORCE = 0x64, ITO_SENSE_SHRT_SENSE = 0x65, ITO_FORCE_OPEN = 0x66, ITO_SENSE_OPEN = 0x67, ITO_KEY_OPEN = 0x68 }; #define FTS_COMP_DATA_HEADER_SIZE 16 enum fts_nvm_data_type { /* Write Command */ FTS_NVM_OFFSET_FAC_RESULT = 1, FTS_NVM_OFFSET_CAL_COUNT, FTS_NVM_OFFSET_DISASSEMBLE_COUNT, FTS_NVM_OFFSET_TUNE_VERSION, FTS_NVM_OFFSET_CAL_POSITION, FTS_NVM_OFFSET_HISTORY_QUEUE_COUNT, FTS_NVM_OFFSET_HISTORY_QUEUE_LASTP, FTS_NVM_OFFSET_HISTORY_QUEUE_ZERO, FTS_NVM_OFFSET_CAL_FAIL_FLAG, FTS_NVM_OFFSET_CAL_FAIL_COUNT, }; struct fts_nvm_data_map { int type; int offset; int length; }; #define NVM_CMD(mtype, moffset, mlength) .type = mtype, .offset = moffset, .length = mlength /* This Flash Meory Map is FIXED by STM firmware * Do not change MAP. */ struct fts_nvm_data_map nvm_data[] = { {NVM_CMD(0, 0x00, 0),}, {NVM_CMD(FTS_NVM_OFFSET_FAC_RESULT, 0x00, 1),}, /* SEC */ {NVM_CMD(FTS_NVM_OFFSET_CAL_COUNT, 0x01, 1),}, /* SEC */ {NVM_CMD(FTS_NVM_OFFSET_DISASSEMBLE_COUNT, 0x02, 1),}, /* SEC */ {NVM_CMD(FTS_NVM_OFFSET_TUNE_VERSION, 0x03, 2),}, /* SEC */ {NVM_CMD(FTS_NVM_OFFSET_CAL_POSITION, 0x05, 1),}, /* SEC */ {NVM_CMD(FTS_NVM_OFFSET_HISTORY_QUEUE_COUNT, 0x06, 1),}, /* SEC */ {NVM_CMD(FTS_NVM_OFFSET_HISTORY_QUEUE_LASTP, 0x07, 1),}, /* SEC */ {NVM_CMD(FTS_NVM_OFFSET_HISTORY_QUEUE_ZERO, 0x08, 20),}, /* SEC */ {NVM_CMD(FTS_NVM_OFFSET_CAL_FAIL_FLAG, 0x1C, 1),}, /* SEC */ {NVM_CMD(FTS_NVM_OFFSET_CAL_FAIL_COUNT, 0x1D, 1),}, /* SEC */ }; #define FTS_NVM_OFFSET_ALL 31 static void fw_update(void *device_data); static void get_fw_ver_bin(void *device_data); static void get_fw_ver_ic(void *device_data); static void get_config_ver(void *device_data); static void get_threshold(void *device_data); static void module_off_master(void *device_data); static void module_on_master(void *device_data); static void get_chip_vendor(void *device_data); static void get_chip_name(void *device_data); static void run_jitter_test(void *device_data); static void run_mutual_jitter(void *device_data); static void run_self_jitter(void *device_data); static void run_jitter_delta_test(void *device_data); static void get_wet_mode(void *device_data); static void get_x_num(void *device_data); static void get_y_num(void *device_data); static void get_checksum_data(void *device_data); static void check_fw_corruption(void *device_data); static void run_reference_read(void *device_data); static void get_reference(void *device_data); static void run_rawcap_read(void *device_data); static void run_rawcap_read_all(void *device_data); static void get_rawcap(void *device_data); static void run_lp_single_ended_rawcap_read(void *device_data); static void run_lp_single_ended_rawcap_read_all(void *device_data); static void run_low_frequency_rawcap_read(void *device_data); static void run_low_frequency_rawcap_read_all(void *device_data); static void run_high_frequency_rawcap_read(void *device_data); static void run_high_frequency_rawcap_read_all(void *device_data); static void run_delta_read(void *device_data); static void get_delta(void *device_data); static void run_rawdata_read_all(void *device_data); #ifdef TCLM_CONCEPT static void get_pat_information(void *device_data); static void set_external_factory(void *device_data); static void tclm_test_cmd(void *device_data); static void get_calibration(void *device_data); #endif static void run_ix_data_read(void *device_data); static void run_ix_data_read_all(void *device_data); static void run_self_raw_read(void *device_data); static void run_factory_miscalibration(void *device_data); static void run_miscalibration(void *device_data); static void run_self_raw_read_all(void *device_data); static void run_trx_short_test(void *device_data); static void check_connection(void *device_data); static void get_cx_data(void *device_data); static void run_active_cx_data_read(void *device_data); static void run_multi_mutual_cx_data_read(void *device_data); static void run_cx_data_read(void *device_data); static void get_cx_all_data(void *device_data); static void run_cx_gap_data_x_all(void *device_data); static void run_cx_gap_data_y_all(void *device_data); static void run_rawdata_gap_data_rx_all(void *device_data); static void run_rawdata_gap_data_tx_all(void *device_data); static void run_prox_intensity_read_all(void *device_data); static void get_strength_all_data(void *device_data); static void set_tsp_test_result(void *device_data); static void get_tsp_test_result(void *device_data); static void increase_disassemble_count(void *device_data); static void get_disassemble_count(void *device_data); static void get_osc_trim_error(void *device_data); static void get_osc_trim_info(void *device_data); static void run_snr_non_touched(void *device_data); static void run_snr_touched(void *device_data); /* static void run_elvss_test(void *device_data); */ #ifdef CONFIG_GLOVE_TOUCH static void glove_mode(void *device_data); #endif static void clear_cover_mode(void *device_data); static void report_rate(void *device_data); #if !defined(CONFIG_SAMSUNG_PRODUCT_SHIP) static void interrupt_control(void *device_data); #endif static void set_wirelesscharger_mode(void *device_data); static void set_grip_data(void *device_data); static void dead_zone_enable(void *device_data); static void drawing_test_enable(void *device_data); static void spay_enable(void *device_data); static void aot_enable(void *device_data); static void aod_enable(void *device_data); static void singletap_enable(void *device_data); static void set_aod_rect(void *device_data); static void get_aod_rect(void *device_data); static void fod_enable(void *device_data); static void set_fod_rect(void *device_data); static void external_noise_mode(void *device_data); static void brush_enable(void *device_data); static void set_touchable_area(void *device_data); static void debug(void *device_data); static void factory_cmd_result_all(void *device_data); static void factory_cmd_result_all_imagetest(void *device_data); static void run_force_calibration(void *device_data); static void set_factory_level(void *device_data); static void fix_active_mode(void *device_data); static void touch_aging_mode(void *device_data); static void run_sram_test(void *device_data); static void set_rear_selfie_mode(void *device_data); static void ear_detect_enable(void *device_data); static void pocket_mode_enable(void *device_data); static void set_sip_mode(void *device_data); static void set_note_mode(void *device_data); static void set_game_mode(void *device_data); static void not_support_cmd(void *device_data); static ssize_t fts_scrub_position(struct device *dev, struct device_attribute *attr, char *buf); struct sec_cmd ft_commands[] = { {SEC_CMD("fw_update", fw_update),}, {SEC_CMD("get_fw_ver_bin", get_fw_ver_bin),}, {SEC_CMD("get_fw_ver_ic", get_fw_ver_ic),}, {SEC_CMD("get_config_ver", get_config_ver),}, {SEC_CMD("get_threshold", get_threshold),}, {SEC_CMD("module_off_master", module_off_master),}, {SEC_CMD("module_on_master", module_on_master),}, {SEC_CMD("module_off_slave", not_support_cmd),}, {SEC_CMD("module_on_slave", not_support_cmd),}, {SEC_CMD("get_chip_vendor", get_chip_vendor),}, {SEC_CMD("get_chip_name", get_chip_name),}, {SEC_CMD("run_jitter_test", run_jitter_test),}, {SEC_CMD("run_mutual_jitter", run_mutual_jitter),}, {SEC_CMD("run_self_jitter", run_self_jitter),}, {SEC_CMD("run_jitter_delta_test", run_jitter_delta_test),}, {SEC_CMD("get_wet_mode", get_wet_mode),}, {SEC_CMD("get_module_vendor", not_support_cmd),}, {SEC_CMD("get_x_num", get_x_num),}, {SEC_CMD("get_y_num", get_y_num),}, {SEC_CMD("get_checksum_data", get_checksum_data),}, {SEC_CMD("get_crc_check", check_fw_corruption),}, {SEC_CMD("run_reference_read", run_reference_read),}, {SEC_CMD("get_reference", get_reference),}, {SEC_CMD("run_rawcap_read", run_rawcap_read),}, {SEC_CMD("run_rawcap_read_all", run_rawcap_read_all),}, {SEC_CMD("get_rawcap", get_rawcap),}, {SEC_CMD("run_lp_single_ended_rawcap_read", run_lp_single_ended_rawcap_read),}, {SEC_CMD("run_lp_single_ended_rawcap_read_all", run_lp_single_ended_rawcap_read_all),}, {SEC_CMD("run_low_frequency_rawcap_read", run_low_frequency_rawcap_read),}, {SEC_CMD("run_low_frequency_rawcap_read_all", run_low_frequency_rawcap_read_all),}, {SEC_CMD("run_high_frequency_rawcap_read", run_high_frequency_rawcap_read),}, {SEC_CMD("run_high_frequency_rawcap_read_all", run_high_frequency_rawcap_read_all),}, {SEC_CMD("run_delta_read", run_delta_read),}, {SEC_CMD("get_delta", get_delta),}, {SEC_CMD("run_cs_raw_read_all", run_rawcap_read_all),}, {SEC_CMD("run_prox_intensity_read_all", run_prox_intensity_read_all),}, {SEC_CMD("run_cs_delta_read_all", get_strength_all_data),}, {SEC_CMD("run_rawdata_read_all_for_ghost", run_rawdata_read_all),}, #ifdef TCLM_CONCEPT {SEC_CMD("get_pat_information", get_pat_information),}, {SEC_CMD("set_external_factory", set_external_factory),}, {SEC_CMD("tclm_test_cmd", tclm_test_cmd),}, {SEC_CMD("get_calibration", get_calibration),}, #endif {SEC_CMD("run_ix_data_read", run_ix_data_read),}, {SEC_CMD("run_ix_data_read_all", run_ix_data_read_all),}, {SEC_CMD("run_self_raw_read", run_self_raw_read),}, {SEC_CMD("run_self_raw_read_all", run_self_raw_read_all),}, {SEC_CMD("run_factory_miscalibration", run_factory_miscalibration),}, {SEC_CMD("run_miscalibration", run_miscalibration),}, {SEC_CMD("run_trx_short_test", run_trx_short_test),}, {SEC_CMD("check_connection", check_connection),}, {SEC_CMD("get_cx_data", get_cx_data),}, {SEC_CMD("run_active_cx_data_read", run_active_cx_data_read),}, {SEC_CMD("run_multi_mutual_cx_data_read", run_multi_mutual_cx_data_read),}, {SEC_CMD("run_cx_data_read", run_cx_data_read),}, {SEC_CMD("run_cx_data_read_all", get_cx_all_data),}, {SEC_CMD("get_cx_all_data", get_cx_all_data),}, {SEC_CMD("run_cx_gap_data_rx_all", run_cx_gap_data_x_all),}, {SEC_CMD("run_cx_gap_data_tx_all", run_cx_gap_data_y_all),}, {SEC_CMD("run_rawdata_gap_data_rx_all", run_rawdata_gap_data_rx_all),}, {SEC_CMD("run_rawdata_gap_data_tx_all", run_rawdata_gap_data_tx_all),}, {SEC_CMD("get_strength_all_data", get_strength_all_data),}, {SEC_CMD("set_tsp_test_result", set_tsp_test_result),}, {SEC_CMD("get_tsp_test_result", get_tsp_test_result),}, {SEC_CMD("increase_disassemble_count", increase_disassemble_count),}, {SEC_CMD("get_disassemble_count", get_disassemble_count),}, {SEC_CMD("get_osc_trim_error", get_osc_trim_error),}, {SEC_CMD("get_osc_trim_info", get_osc_trim_info),}, {SEC_CMD("run_snr_non_touched", run_snr_non_touched),}, {SEC_CMD("run_snr_touched", run_snr_touched),}, /* {SEC_CMD("run_elvss_test", run_elvss_test),}, */ #ifdef CONFIG_GLOVE_TOUCH {SEC_CMD_H("glove_mode", glove_mode),}, #endif {SEC_CMD_H("clear_cover_mode", clear_cover_mode),}, {SEC_CMD("report_rate", report_rate),}, #if !defined(CONFIG_SAMSUNG_PRODUCT_SHIP) {SEC_CMD("interrupt_control", interrupt_control),}, #endif {SEC_CMD("set_wirelesscharger_mode", set_wirelesscharger_mode),}, {SEC_CMD("set_grip_data", set_grip_data),}, {SEC_CMD("dead_zone_enable", dead_zone_enable),}, {SEC_CMD("drawing_test_enable", drawing_test_enable),}, {SEC_CMD_H("spay_enable", spay_enable),}, {SEC_CMD_H("aot_enable", aot_enable),}, {SEC_CMD_H("aod_enable", aod_enable),}, {SEC_CMD_H("singletap_enable", singletap_enable),}, {SEC_CMD("set_aod_rect", set_aod_rect),}, {SEC_CMD("get_aod_rect", get_aod_rect),}, {SEC_CMD_H("fod_enable", fod_enable),}, {SEC_CMD("set_fod_rect", set_fod_rect),}, {SEC_CMD_H("external_noise_mode", external_noise_mode),}, {SEC_CMD_H("brush_enable", brush_enable),}, {SEC_CMD_H("set_touchable_area", set_touchable_area),}, {SEC_CMD("debug", debug),}, {SEC_CMD("factory_cmd_result_all", factory_cmd_result_all),}, {SEC_CMD("factory_cmd_result_all_imagetest", factory_cmd_result_all_imagetest),}, {SEC_CMD("run_force_calibration", run_force_calibration),}, {SEC_CMD("set_factory_level", set_factory_level),}, {SEC_CMD("fix_active_mode", fix_active_mode),}, {SEC_CMD("touch_aging_mode", touch_aging_mode),}, {SEC_CMD("run_sram_test", run_sram_test),}, {SEC_CMD_H("set_rear_selfie_mode", set_rear_selfie_mode),}, {SEC_CMD_H("ear_detect_enable", ear_detect_enable),}, {SEC_CMD_H("pocket_mode_enable", pocket_mode_enable),}, {SEC_CMD("set_sip_mode", set_sip_mode),}, {SEC_CMD_H("set_note_mode", set_note_mode),}, {SEC_CMD("set_game_mode", set_game_mode),}, {SEC_CMD("not_support_cmd", not_support_cmd),}, }; /* read param */ static ssize_t hardware_param_show(struct device *dev, struct device_attribute *attr, char *buf) { struct sec_cmd_data *sec = dev_get_drvdata(dev); struct fts_ts_info *info = container_of(sec, struct fts_ts_info, sec); char buff[516]; char tbuff[128]; char temp[128]; memset(buff, 0x00, sizeof(buff)); /* ito_check */ memset(tbuff, 0x00, sizeof(tbuff)); snprintf(tbuff, sizeof(tbuff), "\"TITO\":\"%02X%02X%02X%02X\",", info->ito_test[0], info->ito_test[1], info->ito_test[2], info->ito_test[3]); strlcat(buff, tbuff, sizeof(buff)); /* muli_count */ memset(tbuff, 0x00, sizeof(tbuff)); snprintf(tbuff, sizeof(tbuff), "\"TMUL\":\"%d\",", info->multi_count); strlcat(buff, tbuff, sizeof(buff)); /* wet_mode */ memset(tbuff, 0x00, sizeof(tbuff)); snprintf(tbuff, sizeof(tbuff), "\"TWET\":\"%d\",", info->wet_count); strlcat(buff, tbuff, sizeof(buff)); /* noise_mode */ memset(tbuff, 0x00, sizeof(tbuff)); snprintf(tbuff, sizeof(tbuff), "\"TNOI\":\"%d\",", info->noise_count); strlcat(buff, tbuff, sizeof(buff)); /* comm_err_count */ memset(tbuff, 0x00, sizeof(tbuff)); snprintf(tbuff, sizeof(tbuff), "\"TCOM\":\"%d\",", info->comm_err_count); strlcat(buff, tbuff, sizeof(buff)); /* module_id */ memset(tbuff, 0x00, sizeof(tbuff)); snprintf(tbuff, sizeof(tbuff), "\"TMOD\":\"ST%02X%04X%02X%c%01X\",", info->panel_revision, info->fw_main_version_of_ic, info->test_result.data[0], #ifdef TCLM_CONCEPT info->tdata->tclm_string[info->tdata->nvdata.cal_position].s_name, info->tdata->nvdata.cal_count & 0xF); #else '0',0); #endif strlcat(buff, tbuff, sizeof(buff)); /* vendor_id */ memset(tbuff, 0x00, sizeof(tbuff)); if (info->board->firmware_name) { memset(temp, 0x00, sizeof(temp)); snprintf(temp, 9, "%s", info->board->firmware_name + 8); snprintf(tbuff, sizeof(tbuff), "\"TVEN\":\"STM_%s\",", temp); } else { snprintf(tbuff, sizeof(tbuff), "\"TVEN\":\"STM\","); } strlcat(buff, tbuff, sizeof(buff)); /* checksum */ memset(tbuff, 0x00, sizeof(tbuff)); snprintf(tbuff, sizeof(tbuff), "\"TCHK\":\"%d\",", info->checksum_result); strlcat(buff, tbuff, sizeof(buff)); /* all_touch_count */ memset(tbuff, 0x00, sizeof(tbuff)); snprintf(tbuff, sizeof(tbuff), "\"TTCN\":\"%d\",\"TACN\":\"%d\",\"TSCN\":\"%d\",", info->all_finger_count, info->all_aod_tap_count, info->all_spay_count); strlcat(buff, tbuff, sizeof(buff)); /* xenosensor_detect_count */ memset(tbuff, 0x00, sizeof(tbuff)); snprintf(tbuff, sizeof(tbuff), "\"TXEN\":\"%02d/%02d_%02d:%02d:%02d_%d,%d_%d\",", (info->xenosensor_detect_count > 0) ? info->xenosensor_time.tm_mon + 1 : info->xenosensor_time.tm_mon, info->xenosensor_time.tm_mday, info->xenosensor_time.tm_hour, info->xenosensor_time.tm_min, info->xenosensor_time.tm_sec, info->xenosensor_detect_x, info->xenosensor_detect_y, info->xenosensor_detect_count); strlcat(buff, tbuff, sizeof(buff)); input_info(true, &info->client->dev, "%s: %s\n", __func__, buff); return snprintf(buf, SEC_CMD_BUF_SIZE, "%s", buff); } /* clear param */ static ssize_t hardware_param_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct sec_cmd_data *sec = dev_get_drvdata(dev); struct fts_ts_info *info = container_of(sec, struct fts_ts_info, sec); info->multi_count = 0; info->wet_count = 0; info->noise_count = 0; info->comm_err_count = 0; info->checksum_result = 0; info->all_finger_count = 0; info->all_aod_tap_count = 0; info->all_spay_count = 0; info->xenosensor_detect_count = 0; memset(&info->xenosensor_time, 0, sizeof(info->xenosensor_time)); info->xenosensor_detect_x = 0; info->xenosensor_detect_y = 0; return count; } static ssize_t read_ambient_info_show(struct device *dev, struct device_attribute *attr, char *buf) { struct sec_cmd_data *sec = dev_get_drvdata(dev); struct fts_ts_info *info = container_of(sec, struct fts_ts_info, sec); input_info(true, &info->client->dev, "\"TAMB_MAX\":\"%d\",\"TAMB_MAX_TX\":\"%d\",\"TAMB_MAX_RX\":\"%d\"" "\"TAMB_MIN\":\"%d\",\"TAMB_MIN_TX\":\"%d\",\"TAMB_MIN_RX\":\"%d\"", info->rawcap_max, info->rawcap_max_tx, info->rawcap_max_rx, info->rawcap_min, info->rawcap_min_tx, info->rawcap_min_rx); return snprintf(buf, SEC_CMD_BUF_SIZE, "\"TAMB_MAX\":\"%d\",\"TAMB_MAX_TX\":\"%d\",\"TAMB_MAX_RX\":\"%d\"," "\"TAMB_MIN\":\"%d\",\"TAMB_MIN_TX\":\"%d\",\"TAMB_MIN_RX\":\"%d\"", info->rawcap_max, info->rawcap_max_tx, info->rawcap_max_rx, info->rawcap_min, info->rawcap_min_tx, info->rawcap_min_rx); } static ssize_t sensitivity_mode_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct sec_cmd_data *sec = dev_get_drvdata(dev); struct fts_ts_info *info = container_of(sec, struct fts_ts_info, sec); unsigned char wbuf[3] = { 0 }; unsigned long value = 0; int ret = 0; if (count > 2) return -EINVAL; ret = kstrtoul(buf, 10, &value); if (ret != 0) return ret; if (info->fts_power_state == FTS_POWER_STATE_POWERDOWN) { input_err(true, &info->client->dev, "%s: [ERROR] Touch is stopped\n", __func__); return -EPERM; } wbuf[0] = FTS_CMD_SENSITIVITY_MODE; switch (value) { case 0: wbuf[1] = 0xFF; /* disable */ break; case 1: wbuf[1] = 0x24; /* enable */ wbuf[2] = 0x01; info->sensitivity_mode = 1; break; case 2: wbuf[1] = 0x24; /* flex mode enable */ wbuf[2] = 0x02; info->sensitivity_mode = 2; break; default: break; } ret = fts_write_reg(info, wbuf, 3); if (ret < 0) { input_err(true, &info->client->dev, "%s: write failed. ret: %d\n", __func__, ret); return ret; } fts_delay(30); input_info(true, &info->client->dev, "%s: %ld\n", __func__, value); return count; } static ssize_t sensitivity_mode_show(struct device *dev, struct device_attribute *attr, char *buf) { struct sec_cmd_data *sec = dev_get_drvdata(dev); struct fts_ts_info *info = container_of(sec, struct fts_ts_info, sec); u8 *rbuf; u8 reg_read = FTS_READ_SENSITIVITY_VALUE; int ret, i; s16 value[10]; u8 count = 9; char *buffer; ssize_t len; if (info->fts_power_state == FTS_POWER_STATE_POWERDOWN) { input_err(true, &info->client->dev, "%s: [ERROR] Touch is stopped\n", __func__); return -EPERM; } if (info->sensitivity_mode == 2) /* flex mode */ count = 12; rbuf = kzalloc(count * 2, GFP_KERNEL); if (!rbuf) return -ENOMEM; buffer = kzalloc(SEC_CMD_BUF_SIZE, GFP_KERNEL); if (!buffer) { kfree(rbuf); return -ENOMEM; } ret = info->fts_read_reg(info, ®_read, 1, rbuf, count * 2); if (ret < 0) { kfree(rbuf); kfree(buffer); input_err(true, &info->client->dev, "%s: read failed ret = %d\n", __func__, ret); return ret; } for (i = 0; i < count; i++) { char temp[16]; memset(temp, 0x00, 16); value[i] = rbuf[i * 2] + (rbuf[i * 2 + 1] << 8); snprintf(temp, 16, "%d,", value[i]); strlcat(buffer, temp, SEC_CMD_BUF_SIZE); } input_info(true, &info->client->dev, "%s: %s\n", __func__, buffer); len = snprintf(buf, SEC_CMD_BUF_SIZE, "%s", buffer); kfree(rbuf); kfree(buffer); return len; } /* * read_support_feature function * returns the bit combination of specific feature that is supported. */ static ssize_t read_support_feature(struct device *dev, struct device_attribute *attr, char *buf) { struct sec_cmd_data *sec = dev_get_drvdata(dev); struct fts_ts_info *info = container_of(sec, struct fts_ts_info, sec); char buff[SEC_CMD_STR_LEN] = { 0 }; u32 feature = 0; if (info->board->enable_settings_aot) feature |= INPUT_FEATURE_ENABLE_SETTINGS_AOT; if (info->board->sync_reportrate_120) feature |= INPUT_FEATURE_ENABLE_SYNC_RR120; if (info->board->support_open_short_test) feature |= INPUT_FEATURE_SUPPORT_OPEN_SHORT_TEST; if (info->board->support_mis_calibration_test) feature |= INPUT_FEATURE_SUPPORT_MIS_CALIBRATION_TEST; snprintf(buff, sizeof(buff), "%d", feature); input_info(true, &info->client->dev, "%s: %s\n", __func__, buff); return snprintf(buf, SEC_CMD_BUF_SIZE, "%s", buff); } #ifdef FTS_SUPPORT_SPONGELIB #ifdef CONFIG_TOUCHSCREEN_DUAL_FOLDABLE ssize_t get_lp_dump(struct device *dev, struct device_attribute *attr, char *buf) { struct sec_cmd_data *sec = dev_get_drvdata(dev); struct fts_ts_info *info; u8 string_data[10] = {0, }; u16 current_index; u8 dump_format, dump_num; u16 dump_start, dump_end; int i, j, ret; u16 addr; u8 buffer[30]; u8 position = FTS_SPONGE_LP_DUMP_DATA_FORMAT_10_LEN; if (!sec) return -ENODEV; info = container_of(sec, struct fts_ts_info, sec); if (!info->lp_dump) return -ENOMEM; if (!info->use_sponge) return -ENODEV; if (info->fts_power_state == FTS_POWER_STATE_POWERDOWN) { input_err(true, &info->client->dev, "%s: [ERROR] Touch is stopped\n", __func__); goto read_buf; } if (info->reset_is_on_going) { input_err(true, &info->client->dev, "%s: reset is ongoing\n", __func__); goto read_buf; } if (info->lp_dump_readmore == 0) goto read_buf; fts_interrupt_set(info, INT_DISABLE); addr = FTS_CMD_SPONGE_LP_DUMP; ret = info->fts_read_from_sponge(info, addr, string_data, 4); if (ret < 0) { input_err(true, &info->client->dev, "%s: Failed to read from Sponge, addr=0x%X\n", __func__, addr); if (buf) snprintf(buf, SEC_CMD_BUF_SIZE, "NG, Failed to read from Sponge, addr=0x%X", addr); fts_interrupt_set(info, INT_ENABLE); goto out; } dump_format = string_data[0]; dump_num = string_data[1]; dump_start = FTS_CMD_SPONGE_LP_DUMP + 4; dump_end = dump_start + (dump_format * (dump_num - 1)); if (dump_format > 10) { input_err(true, &info->client->dev, "%s: abnormal data:0x%X, 0x%X\n", __func__, string_data[0], string_data[1]); if (buf) snprintf(buf, SEC_CMD_BUF_SIZE, "%s", "NG, Failed to read from dump format"); fts_interrupt_set(info, INT_ENABLE); goto out; } current_index = (string_data[3] & 0xFF) << 8 | (string_data[2] & 0xFF); if (current_index > dump_end || current_index < dump_start) { input_err(true, &info->client->dev, "Failed to Sponge LP log %d\n", current_index); if (buf) snprintf(buf, SEC_CMD_BUF_SIZE, "NG, Failed to Sponge LP log, current_index=%d", current_index); fts_interrupt_set(info, INT_ENABLE); goto out; } input_info(true, &info->client->dev, "%s: DEBUG format=%d, num=%d, start=%d, end=%d, current_index=%d\n", __func__, dump_format, dump_num, dump_start, dump_end, current_index); for (i = dump_num - 1 ; i >= 0 ; i--) { u16 string_addr; int value, j; if (current_index < (dump_format * i)) string_addr = (dump_format * dump_num) + current_index - (dump_format * i); else string_addr = current_index - (dump_format * i); if (string_addr < dump_start) string_addr += (dump_format * dump_num); addr = string_addr; ret = info->fts_read_from_sponge(info, addr, string_data, dump_format); if (ret < 0) { input_err(true, &info->client->dev, "%s: Failed to read from Sponge, addr=0x%X\n", __func__, addr); if (buf) snprintf(buf, SEC_CMD_BUF_SIZE, "NG, Failed to read from Sponge, addr=0x%X", addr); fts_interrupt_set(info, INT_ENABLE); goto out; } value = 0; for (j = 0; j < 10; j++) value += string_data[j]; if (value == 0) continue; info->lp_dump[info->lp_dump_index] = (string_addr >> 8) & 0xFF; info->lp_dump[info->lp_dump_index + 1] = string_addr & 0xFF; for (j = 0; j < 10; j += 2) { info->lp_dump[info->lp_dump_index + 2 + j] = string_data[j + 1]; info->lp_dump[info->lp_dump_index + 2 + j + 1] = string_data[j]; } info->lp_dump_index += position; if (info->lp_dump_index >= position * FTS_SPONGE_LP_DUMP_LENGTH) info->lp_dump_index = 0; } fts_interrupt_set(info, INT_ENABLE); read_buf: if (buf) { int pos = info->lp_dump_index; for (i = 0; i < FTS_SPONGE_LP_DUMP_LENGTH; i++) { if (pos >= FTS_SPONGE_LP_DUMP_DATA_FORMAT_10_LEN * FTS_SPONGE_LP_DUMP_LENGTH) pos = 0; if (info->lp_dump[pos] == 0 && info->lp_dump[pos + 1] == 0) { pos += position; continue; } snprintf(buffer, sizeof(buffer), "%d: ", info->lp_dump[pos] << 8 | info->lp_dump[pos + 1]); strlcat(buf, buffer, PAGE_SIZE); memset(buffer, 0x00, sizeof(buffer)); for (j = 0; j < 10; j++) { snprintf(buffer, sizeof(buffer), "%02x", info->lp_dump[pos + 2 + j]); strlcat(buf, buffer, PAGE_SIZE); memset(buffer, 0x00, sizeof(buffer)); } snprintf(buffer, sizeof(buffer), "\n"); strlcat(buf, buffer, PAGE_SIZE); memset(buffer, 0x00, sizeof(buffer)); pos += position; } } out: info->lp_dump_readmore = 0; if (buf) { if (strlen(buf) == 0) snprintf(buf, SEC_CMD_BUF_SIZE, "%s", "empty"); return strlen(buf); } return ret; } #else static ssize_t get_lp_dump(struct device *dev, struct device_attribute *attr, char *buf) { struct sec_cmd_data *sec = dev_get_drvdata(dev); struct fts_ts_info *info = container_of(sec, struct fts_ts_info, sec); u8 string_data[10] = {0, }; u16 current_index; u16 dump_start, dump_end, dump_cnt; int i, ret, dump_area, dump_gain; unsigned char *sec_spg_dat; u8 dump_clear_packet = 0x01; u16 addr; if (!info->use_sponge) return -ENODEV; if (info->fts_power_state == FTS_POWER_STATE_POWERDOWN) { input_err(true, &info->client->dev, "%s: [ERROR] Touch is stopped\n", __func__); return snprintf(buf, SEC_CMD_BUF_SIZE, "%s", "TSP turned off"); } /* preparing dump buffer */ sec_spg_dat = vmalloc(FTS_MAX_SPONGE_DUMP_BUFFER); if (!sec_spg_dat) { input_err(true, &info->client->dev, "%s : Failed!!\n", __func__); return snprintf(buf, SEC_CMD_BUF_SIZE, "vmalloc failed"); } memset(sec_spg_dat, 0, FTS_MAX_SPONGE_DUMP_BUFFER); fts_interrupt_set(info, INT_DISABLE); addr = FTS_CMD_SPONGE_LP_DUMP_CUR_IDX; ret = info->fts_read_from_sponge(info, addr, string_data, 2); if (ret < 0) { input_err(true, &info->client->dev, "%s: Failed to read from Sponge, addr=0x%X\n", __func__, addr); snprintf(buf, SEC_CMD_BUF_SIZE, "NG, Failed to read from Sponge, addr=0x%X", addr); goto out; } if (info->sponge_inf_dump) dump_gain = 2; else dump_gain = 1; current_index = (string_data[1] & 0xFF) << 8 | (string_data[0] & 0xFF); dump_start = FTS_CMD_SPONGE_LP_DUMP_EVENT; dump_end = dump_start + (info->sponge_dump_format * ((info->sponge_dump_event * dump_gain) - 1)); if (current_index > dump_end || current_index < dump_start) { input_err(true, &info->client->dev, "Failed to Sponge LP log %d\n", current_index); snprintf(buf, SEC_CMD_BUF_SIZE, "NG, Failed to Sponge LP log, current_index=%d", current_index); goto out; } /* legacy get_lp_dump */ input_info(true, &info->client->dev, "%s: DEBUG format=%d, num=%d, start=%d, end=%d, current_index=%d\n", __func__, info->sponge_dump_format, info->sponge_dump_event, dump_start, dump_end, current_index); for (i = (info->sponge_dump_event * dump_gain) - 1 ; i >= 0 ; i--) { u16 data0, data1, data2, data3, data4; char buff[30] = {0, }; u16 string_addr; if (current_index < (info->sponge_dump_format * i)) string_addr = (info->sponge_dump_format * info->sponge_dump_event * dump_gain) + current_index - (info->sponge_dump_format * i); else string_addr = current_index - (info->sponge_dump_format * i); if (string_addr < dump_start) string_addr += (info->sponge_dump_format * info->sponge_dump_event * dump_gain); addr = string_addr; ret = info->fts_read_from_sponge(info, addr, string_data, info->sponge_dump_format); if (ret < 0) { input_err(true, &info->client->dev, "%s: Failed to read from Sponge, addr=0x%X\n", __func__, addr); snprintf(buf, SEC_CMD_BUF_SIZE, "NG, Failed to read from Sponge, addr=0x%X", addr); goto out; } data0 = (string_data[1] & 0xFF) << 8 | (string_data[0] & 0xFF); data1 = (string_data[3] & 0xFF) << 8 | (string_data[2] & 0xFF); data2 = (string_data[5] & 0xFF) << 8 | (string_data[4] & 0xFF); data3 = (string_data[7] & 0xFF) << 8 | (string_data[6] & 0xFF); data4 = (string_data[9] & 0xFF) << 8 | (string_data[8] & 0xFF); if (data0 || data1 || data2 || data3 || data4) { if (info->sponge_dump_format == 10) { snprintf(buff, sizeof(buff), "%d: %04x%04x%04x%04x%04x\n", string_addr, data0, data1, data2, data3, data4); } else { snprintf(buff, sizeof(buff), "%d: %04x%04x%04x%04x\n", string_addr, data0, data1, data2, data3); } strlcat(buf, buff, PAGE_SIZE); } } if (info->sponge_inf_dump) { if (current_index >= info->sponge_dump_border) { dump_cnt = ((current_index - (info->sponge_dump_border)) / info->sponge_dump_format) + 1; dump_area = 1; addr = info->sponge_dump_border; } else { dump_cnt = ((current_index - FTS_CMD_SPONGE_LP_DUMP_EVENT) / info->sponge_dump_format) + 1; dump_area = 0; addr = FTS_CMD_SPONGE_LP_DUMP_EVENT; } ret = info->fts_read_from_sponge(info, addr, sec_spg_dat, dump_cnt * info->sponge_dump_format); if (ret < 0) { input_err(true, &info->client->dev, "%s: Failed to read sponge\n", __func__); goto out; } for (i = 0 ; i <= dump_cnt ; i++) { int e_offset = i * info->sponge_dump_format; char ibuff[30] = {0, }; u16 edata[5]; edata[0] = (sec_spg_dat[1 + e_offset] & 0xFF) << 8 | (sec_spg_dat[0 + e_offset] & 0xFF); edata[1] = (sec_spg_dat[3 + e_offset] & 0xFF) << 8 | (sec_spg_dat[2 + e_offset] & 0xFF); edata[2] = (sec_spg_dat[5 + e_offset] & 0xFF) << 8 | (sec_spg_dat[4 + e_offset] & 0xFF); edata[3] = (sec_spg_dat[7 + e_offset] & 0xFF) << 8 | (sec_spg_dat[6 + e_offset] & 0xFF); edata[4] = (sec_spg_dat[9 + e_offset] & 0xFF) << 8 | (sec_spg_dat[8 + e_offset] & 0xFF); if (edata[0] || edata[1] || edata[2] || edata[3] || edata[4]) { snprintf(ibuff, sizeof(ibuff), "%03d: %04x%04x%04x%04x%04x\n", i + (info->sponge_dump_event * dump_area), edata[0], edata[1], edata[2], edata[3], edata[4]); sec_tsp_sponge_log(ibuff); } } info->sponge_dump_delayed_flag = false; ret = fts_write_to_sponge(info, FTS_CMD_SPONGE_DUMP_FLUSH, &dump_clear_packet, 1); if (ret < 0) input_err(true, &info->client->dev, "%s: Failed to clear sponge dump\n", __func__); } out: vfree(sec_spg_dat); fts_interrupt_set(info, INT_ENABLE); return strlen(buf); } #endif #endif static ssize_t prox_power_off_show(struct device *dev, struct device_attribute *attr, char *buf) { struct sec_cmd_data *sec = dev_get_drvdata(dev); struct fts_ts_info *info = container_of(sec, struct fts_ts_info, sec); input_info(true, &info->client->dev, "%s: %d\n", __func__, info->prox_power_off); return snprintf(buf, SEC_CMD_BUF_SIZE, "%d", info->prox_power_off); } static ssize_t prox_power_off_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct sec_cmd_data *sec = dev_get_drvdata(dev); struct fts_ts_info *info = container_of(sec, struct fts_ts_info, sec); int ret, data; ret = kstrtoint(buf, 10, &data); if (ret < 0) return ret; input_info(true, &info->client->dev, "%s: %d\n", __func__, data); info->prox_power_off = data; return count; } static ssize_t protos_event_show(struct device *dev, struct device_attribute *attr, char *buf) { struct sec_cmd_data *sec = dev_get_drvdata(dev); struct fts_ts_info *info = container_of(sec, struct fts_ts_info, sec); input_info(true, &info->client->dev, "%s: %d\n", __func__, info->hover_event); return snprintf(buf, SEC_CMD_BUF_SIZE, "%d", info->hover_event != 3 ? 0 : 3); } static ssize_t protos_event_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct sec_cmd_data *sec = dev_get_drvdata(dev); struct fts_ts_info *info = container_of(sec, struct fts_ts_info, sec); int ret; u8 data[2]; ret = kstrtou8(buf, 8, &data[1]); if (ret < 0) return ret; data[0] = FTS_CMD_SET_EAR_DETECT; ret = fts_write_reg(info, data, 2); input_info(true, &info->client->dev, "%s: set %d: ret:%d\n", __func__, data[1], ret); return count; } static ssize_t fts_fod_info_show(struct device *dev, struct device_attribute *attr, char *buf) { struct sec_cmd_data *sec = dev_get_drvdata(dev); struct fts_ts_info *info = container_of(sec, struct fts_ts_info, sec); if (!info->board->support_fod) { input_err(true, &info->client->dev, "%s: fod is not supported\n", __func__); return snprintf(buf, SEC_CMD_BUF_SIZE, "NG"); } input_info(true, &info->client->dev, "%s: x:%d/%d y:%d/%d size:%d\n", __func__, info->fod_x, info->ForceChannelLength, info->fod_y, info->SenseChannelLength, info->fod_vi_size); return snprintf(buf, SEC_CMD_BUF_SIZE, "%d,%d,%d,%d,%d\n", info->fod_x, info->fod_y, info->fod_vi_size, info->ForceChannelLength, info->SenseChannelLength); } static ssize_t fts_fod_position_show(struct device *dev, struct device_attribute *attr, char *buf) { struct sec_cmd_data *sec = dev_get_drvdata(dev); struct fts_ts_info *info = container_of(sec, struct fts_ts_info, sec); char buff[3] = { 0 }; int i; if (!info->board->support_fod) { input_err(true, &info->client->dev, "%s: fod is not supported\n", __func__); return snprintf(buf, SEC_CMD_BUF_SIZE, "NG"); } if (!info->fod_vi_size) { input_err(true, &info->client->dev, "%s: fod vi size is 0\n", __func__); return snprintf(buf, SEC_CMD_BUF_SIZE, "NG"); } if (!info->fod_vi_data) { input_err(true, &info->client->dev, "%s: fod vi data is null\n", __func__); return snprintf(buf, SEC_CMD_BUF_SIZE, "NG"); } for (i = 0; i < info->fod_vi_size; i++) { snprintf(buff, 3, "%02X", info->fod_vi_data[i]); strlcat(buf, buff, SEC_CMD_BUF_SIZE); } return strlen(buf); } #ifdef CONFIG_TOUCHSCREEN_DUAL_FOLDABLE static ssize_t dualscreen_policy_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct sec_cmd_data *sec = dev_get_drvdata(dev); struct fts_ts_info *info = container_of(sec, struct fts_ts_info, sec); int ret, value; if (!info->board->support_flex_mode) return count; ret = kstrtoint(buf, 10, &value); if (ret < 0) return ret; input_info(true, &info->client->dev, "%s: power_state[%d] %sfolding\n", __func__, info->fts_power_state, info->flip_status_current ? "": "un"); if (info->fts_power_state == FTS_POWER_STATE_POWERDOWN && info->flip_status_current == FTS_STATUS_UNFOLDING) { cancel_delayed_work(&info->switching_work); schedule_work(&info->switching_work.work); } return count; } #endif static DEVICE_ATTR(hw_param, 0664, hardware_param_show, hardware_param_store); static DEVICE_ATTR(read_ambient_info, 0444, read_ambient_info_show, NULL); static DEVICE_ATTR(sensitivity_mode, 0664, sensitivity_mode_show, sensitivity_mode_store); static DEVICE_ATTR(scrub_pos, 0444, fts_scrub_position, NULL); static DEVICE_ATTR(support_feature, 0444, read_support_feature, NULL); #ifdef FTS_SUPPORT_SPONGELIB static DEVICE_ATTR(get_lp_dump, 0444, get_lp_dump, NULL); #endif static DEVICE_ATTR(prox_power_off, 0664, prox_power_off_show, prox_power_off_store); static DEVICE_ATTR(virtual_prox, 0664, protos_event_show, protos_event_store); static DEVICE_ATTR(fod_info, 0444, fts_fod_info_show, NULL); static DEVICE_ATTR(fod_pos, 0444, fts_fod_position_show, NULL); #ifdef CONFIG_TOUCHSCREEN_DUAL_FOLDABLE static DEVICE_ATTR(dualscreen_policy, 0664, NULL, dualscreen_policy_store); #endif static struct attribute *sec_touch_facotry_attributes[] = { &dev_attr_scrub_pos.attr, &dev_attr_hw_param.attr, &dev_attr_read_ambient_info.attr, &dev_attr_sensitivity_mode.attr, &dev_attr_support_feature.attr, #ifdef FTS_SUPPORT_SPONGELIB &dev_attr_get_lp_dump.attr, #endif &dev_attr_prox_power_off.attr, &dev_attr_virtual_prox.attr, &dev_attr_fod_info.attr, &dev_attr_fod_pos.attr, #ifdef CONFIG_TOUCHSCREEN_DUAL_FOLDABLE &dev_attr_dualscreen_policy.attr, #endif NULL, }; static struct attribute_group sec_touch_factory_attr_group = { .attrs = sec_touch_facotry_attributes, }; static ssize_t fts_get_cmoffset_dump(struct fts_ts_info *info, char *buf, u8 position) { u8 regaddr[4] = { 0 }; u8 *rbuff; int ret, i, j, size = info->SenseChannelLength * info->ForceChannelLength; u32 signature; if (info->fts_power_state == FTS_POWER_STATE_POWERDOWN) { input_err(true, &info->client->dev, "%s: Touch is stopped\n", __func__); return -EPERM; } if (info->fts_power_state == FTS_POWER_STATE_LOWPOWER) { input_err(true, &info->client->dev, "%s: Touch is LP mode\n", __func__); return -EPERM; } if (info->reset_is_on_going) { input_err(true, &info->client->dev, "%s: Reset is ongoing!\n", __func__); return -EPERM; } if (info->sec.cmd_is_running) { input_err(true, &info->client->dev, "%s: cmd is running\n", __func__); return -EBUSY; } rbuff = kzalloc(size, GFP_KERNEL); if (!rbuff) { input_err(true, &info->client->dev, "%s: alloc failed\n", __func__); return -ENOMEM; } info->fts_command(info, FTS_CMD_CLEAR_ALL_EVENT, true); fts_interrupt_set(info, INT_DISABLE); fts_release_all_finger(info); /* Request SEC factory debug data from flash */ regaddr[0] = 0xA4; regaddr[1] = 0x06; regaddr[2] = 0x92; regaddr[3] = position; ret = fts_fw_wait_for_echo_event(info, regaddr, 4, 0); if (ret < 0) { snprintf(buf, info->proc_cmoffset_size, "NG, failed to request data, %d", ret); goto out; } /* read header info */ regaddr[0] = 0xA6; regaddr[1] = 0x00; regaddr[2] = 0x00; ret = info->fts_read_reg(info, ®addr[0], 3, rbuff, 8); if (ret < 0) { input_err(true, &info->client->dev, "%s: read header failed. ret: %d\n", __func__, ret); snprintf(buf, info->proc_cmoffset_size, "NG, failed to read header, %d", ret); goto out; } signature = rbuff[3] << 24 | rbuff[2] << 16 | rbuff[1] << 8 | rbuff[0]; input_info(true, &info->client->dev, "%s: position:%d, signature:%08X (%X), validation:%X, try count:%X\n", __func__, position, signature, SEC_OFFSET_SIGNATURE, rbuff[4], rbuff[5]); if (signature != SEC_OFFSET_SIGNATURE) { input_err(true, &info->client->dev, "%s: cmoffset[%d], signature is mismatched\n", __func__, position); snprintf(buf, info->proc_cmoffset_size, "signature mismatched %08X\n", signature); goto out; } /* read history data */ regaddr[0] = 0xA6; regaddr[1] = 0x00; regaddr[2] = (u8)info->SenseChannelLength; ret = info->fts_read_reg(info, ®addr[0], 3, rbuff, size); if (ret < 0) { input_err(true, &info->client->dev, "%s: read data failed. ret: %d\n", __func__, ret); snprintf(buf, info->proc_cmoffset_size, "NG, failed to read data %d", ret); goto out; } memset(buf, 0x00, info->proc_cmoffset_size); for (i = 0; i < info->ForceChannelLength; i++) { char buff[4] = { 0 }; for (j = 0; j < info->SenseChannelLength; j++) { snprintf(buff, sizeof(buff), " %d", rbuff[i * info->SenseChannelLength + j]); strlcat(buf, buff, info->proc_cmoffset_size); } snprintf(buff, sizeof(buff), "\n"); strlcat(buf, buff, info->proc_cmoffset_size); } out: input_err(true, &info->client->dev, "%s: pos:%d, buf size:%zu\n", __func__, position, strlen(buf)); fts_interrupt_set(info, INT_ENABLE); kfree(rbuff); return strlen(buf); } static void enter_factory_mode(struct fts_ts_info *info, bool fac_mode) { if (info->fts_power_state == FTS_POWER_STATE_POWERDOWN) return; info->fts_systemreset(info, 50); fts_release_all_finger(info); if (fac_mode) { // Auto-Tune without saving fts_execute_autotune(info, false); fts_delay(50); } fts_set_scanmode(info, info->scan_mode); fts_delay(50); } static int fts_check_index(struct fts_ts_info *info) { struct sec_cmd_data *sec = &info->sec; char buff[SEC_CMD_STR_LEN] = { 0 }; int node; if (sec->cmd_param[0] < 0 || sec->cmd_param[0] >= info->SenseChannelLength || sec->cmd_param[1] < 0 || sec->cmd_param[1] >= info->ForceChannelLength) { snprintf(buff, sizeof(buff), "%s", "NG"); sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); sec->cmd_state = SEC_CMD_STATUS_FAIL; input_err(true, &info->client->dev, "%s: parameter error: %u,%u\n", __func__, sec->cmd_param[0], sec->cmd_param[1]); node = -1; return node; } node = sec->cmd_param[1] * info->SenseChannelLength + sec->cmd_param[0]; input_info(true, &info->client->dev, "%s: node = %d\n", __func__, node); return node; } static ssize_t fts_scrub_position(struct device *dev, struct device_attribute *attr, char *buf) { struct sec_cmd_data *sec = dev_get_drvdata(dev); struct fts_ts_info *info = container_of(sec, struct fts_ts_info, sec); char buff[SEC_CMD_STR_LEN] = { 0 }; input_info(true, &info->client->dev, "%s: %d %d %d\n", __func__, info->scrub_id, info->scrub_x, info->scrub_y); snprintf(buff, sizeof(buff), "%d %d %d", info->scrub_id, info->scrub_x, info->scrub_y); info->scrub_x = 0; info->scrub_y = 0; return snprintf(buf, SEC_CMD_BUF_SIZE, "%s\n", buff); } static void not_support_cmd(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct fts_ts_info *info = container_of(sec, struct fts_ts_info, sec); char buff[16] = { 0 }; sec_cmd_set_default_result(sec); snprintf(buff, sizeof(buff), "%s", "NA"); sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); sec->cmd_state = SEC_CMD_STATUS_NOT_APPLICABLE; sec_cmd_set_cmd_exit(sec); input_info(true, &info->client->dev, "%s: %s\n", __func__, buff); } static void fw_update(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct fts_ts_info *info = container_of(sec, struct fts_ts_info, sec); char buff[64] = { 0 }; int retval = 0; sec_cmd_set_default_result(sec); if (info->fts_power_state == FTS_POWER_STATE_POWERDOWN) { input_err(true, &info->client->dev, "%s: [ERROR] Touch is stopped\n", __func__); snprintf(buff, sizeof(buff), "%s", "NG"); sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); sec->cmd_state = SEC_CMD_STATUS_FAIL; return; } retval = fts_fw_update_on_hidden_menu(info, sec->cmd_param[0]); if (retval < 0) { snprintf(buff, sizeof(buff), "%s", "NG"); sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); sec->cmd_state = SEC_CMD_STATUS_FAIL; input_err(true, &info->client->dev, "%s: failed [%d]\n", __func__, retval); } else { snprintf(buff, sizeof(buff), "%s", "OK"); sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); sec->cmd_state = SEC_CMD_STATUS_OK; input_info(true, &info->client->dev, "%s: success [%d]\n", __func__, retval); } } static int fts_get_channel_info(struct fts_ts_info *info) { int rc = -1; u8 regAdd[1] = { FTS_READ_PANEL_INFO }; u8 data[FTS_EVENT_SIZE] = { 0 }; memset(data, 0x0, FTS_EVENT_SIZE); rc = info->fts_read_reg(info, regAdd, 1, data, 11); if (rc < 0) { info->ForceChannelLength = 0; info->SenseChannelLength = 0; input_err(true, &info->client->dev, "%s: Get channel info Read Fail!!\n", __func__); return rc; } info->ForceChannelLength = data[8]; // Number of TX CH info->SenseChannelLength = data[9]; // Number of RX CH if (!(info->ForceChannelLength > 0 && info->ForceChannelLength < FTS_MAX_NUM_FORCE && info->SenseChannelLength > 0 && info->SenseChannelLength < FTS_MAX_NUM_SENSE)) { info->ForceChannelLength = FTS_MAX_NUM_FORCE; info->SenseChannelLength = FTS_MAX_NUM_SENSE; input_err(true, &info->client->dev, "%s: set channel num based on max value, check it!\n", __func__); } info->ICXResolution = (data[0] << 8) | data[1]; // X resolution of IC info->ICYResolution = (data[2] << 8) | data[3]; // Y resolution of IC input_info(true, &info->client->dev, "%s: RX:Sense(%02d) TX:Force(%02d) resolution:(IC)x:%d y:%d, (DT)x:%d,y:%d\n", __func__, info->SenseChannelLength, info->ForceChannelLength, info->ICXResolution, info->ICYResolution, info->board->max_x, info->board->max_y); if (info->ICXResolution > 0 && info->ICXResolution < FTS_MAX_X_RESOLUTION && info->ICYResolution > 0 && info->ICYResolution < FTS_MAX_Y_RESOLUTION && info->board->max_x != info->ICXResolution && info->board->max_y != info->ICYResolution) { info->board->max_x = info->ICXResolution; info->board->max_y = info->ICYResolution; input_err(true, &info->client->dev, "%s: set resolution based on ic value, check it!\n", __func__); } return rc; } static void fts_print_channel(struct fts_ts_info *info, s16 *tx_data, s16 *rx_data) { unsigned char *pStr = NULL; unsigned char pTmp[16] = { 0 }; int len, max_num = 0; int i = 0, k = 0; int tx_count = info->ForceChannelLength; int rx_count = info->SenseChannelLength; if (tx_count > 20) max_num = 10; else max_num = tx_count; if (!max_num) return; len = 7 * (max_num + 1); pStr = vzalloc(len); if (!pStr) return; /* Print TX channel */ memset(pStr, 0x0, len); snprintf(pTmp, sizeof(pTmp), " TX"); strlcat(pStr, pTmp, len); for (k = 0; k < max_num; k++) { snprintf(pTmp, sizeof(pTmp), " %02d", k); strlcat(pStr, pTmp, len); } input_raw_info_d(true, &info->client->dev, "%s\n", pStr); memset(pStr, 0x0, len); snprintf(pTmp, sizeof(pTmp), " +"); strlcat(pStr, pTmp, len); for (k = 0; k < max_num; k++) { snprintf(pTmp, sizeof(pTmp), "------"); strlcat(pStr, pTmp, len); } input_raw_info_d(true, &info->client->dev, "%s\n", pStr); memset(pStr, 0x0, len); snprintf(pTmp, sizeof(pTmp), " | "); strlcat(pStr, pTmp, len); for (i = 0; i < tx_count; i++) { if (i && i % max_num == 0) { input_raw_info_d(true, &info->client->dev, "%s\n", pStr); memset(pStr, 0x0, len); snprintf(pTmp, sizeof(pTmp), " | "); strlcat(pStr, pTmp, len); } snprintf(pTmp, sizeof(pTmp), " %5d", tx_data[i]); strlcat(pStr, pTmp, len); } input_raw_info_d(true, &info->client->dev, "%s\n", pStr); /* Print RX channel */ memset(pStr, 0x0, len); snprintf(pTmp, sizeof(pTmp), " RX"); strlcat(pStr, pTmp, len); for (k = 0; k < max_num; k++) { snprintf(pTmp, sizeof(pTmp), " %02d", k); strlcat(pStr, pTmp, len); } input_raw_info_d(true, &info->client->dev, "%s\n", pStr); memset(pStr, 0x0, len); snprintf(pTmp, sizeof(pTmp), " +"); strlcat(pStr, pTmp, len); for (k = 0; k < max_num; k++) { snprintf(pTmp, sizeof(pTmp), "------"); strlcat(pStr, pTmp, len); } input_raw_info_d(true, &info->client->dev, "%s\n", pStr); memset(pStr, 0x0, len); snprintf(pTmp, sizeof(pTmp), " | "); strlcat(pStr, pTmp, len); for (i = 0; i < rx_count; i++) { if (i && i % max_num == 0) { input_raw_info_d(true, &info->client->dev, "%s\n", pStr); memset(pStr, 0x0, len); snprintf(pTmp, sizeof(pTmp), " | "); strlcat(pStr, pTmp, len); } snprintf(pTmp, sizeof(pTmp), " %5d", rx_data[i]); strlcat(pStr, pTmp, len); } input_raw_info_d(true, &info->client->dev, "%s\n", pStr); vfree(pStr); } void fts_print_frame(struct fts_ts_info *info, short *min, short *max) { int i = 0; int j = 0; u8 *pStr = NULL; u8 pTmp[16] = { 0 }; pStr = kzalloc(BUFFER_MAX, GFP_KERNEL); if (pStr == NULL) return; snprintf(pTmp, 4, " "); strlcat(pStr, pTmp, BUFFER_MAX); for (i = 0; i < info->SenseChannelLength; i++) { snprintf(pTmp, 6, "Rx%02d ", i); strlcat(pStr, pTmp, BUFFER_MAX); } input_raw_info_d(true, &info->client->dev, "%s\n", pStr); memset(pStr, 0x0, 6 * (info->SenseChannelLength + 1)); snprintf(pTmp, 2, " +"); strlcat(pStr, pTmp, BUFFER_MAX); for (i = 0; i < info->SenseChannelLength; i++) { snprintf(pTmp, 6, "------"); strlcat(pStr, pTmp, BUFFER_MAX); } input_raw_info_d(true, &info->client->dev, "%s\n", pStr); for (i = 0; i < info->ForceChannelLength; i++) { memset(pStr, 0x0, 6 * (info->SenseChannelLength + 1)); snprintf(pTmp, 7, "Tx%02d | ", i); strlcat(pStr, pTmp, BUFFER_MAX); for (j = 0; j < info->SenseChannelLength; j++) { snprintf(pTmp, 6, "%5d ", info->pFrame[(i * info->SenseChannelLength) + j]); strlcat(pStr, pTmp, BUFFER_MAX); if (info->pFrame[(i * info->SenseChannelLength) + j] < *min) { *min = info->pFrame[(i * info->SenseChannelLength) + j]; if (info->rawcap_lock) { info->rawcap_min = *min; info->rawcap_min_tx = i; info->rawcap_min_rx = j; } } if (info->pFrame[(i * info->SenseChannelLength) + j] > *max) { *max = info->pFrame[(i * info->SenseChannelLength) + j]; if (info->rawcap_lock) { info->rawcap_max = *max; info->rawcap_max_tx = i; info->rawcap_max_rx = j; } } } input_raw_info_d(true, &info->client->dev, "%s\n", pStr); } input_raw_info_d(true, &info->client->dev, "%s, min:%d, max:%d\n", __func__, *min, *max); kfree(pStr); } int fts_read_frame(struct fts_ts_info *info, u8 type, short *min, short *max) { struct FTS_SyncFrameHeader *pSyncFrameHeader; u8 regAdd[8] = { 0 }; unsigned int totalbytes = 0; u8 *pRead; int rc = 0; int ret = 0; int i = 0; int retry = 10; pRead = kzalloc(info->ForceChannelLength * info->SenseChannelLength * 3 + 1, GFP_KERNEL); if (!pRead) return -ENOMEM; /* Request Data Type */ regAdd[0] = 0xA4; regAdd[1] = 0x06; regAdd[2] = (u8)type; info->fts_write_reg(info, ®Add[0], 3); fts_delay(50); do { regAdd[0] = 0xA6; regAdd[1] = 0x00; regAdd[2] = 0x00; ret = info->fts_read_reg(info, ®Add[0], 3, &pRead[0], FTS_COMP_DATA_HEADER_SIZE); if (ret <= 0) { input_err(true, &info->client->dev, "%s: read failed rc = %d\n", __func__, ret); rc = -3; goto ErrorExit; } pSyncFrameHeader = (struct FTS_SyncFrameHeader *) &pRead[0]; if ((pSyncFrameHeader->header == 0xA5) && (pSyncFrameHeader->host_data_mem_id == type)) break; fts_delay(100); } while (retry--); if (retry == 0) { input_err(true, &info->client->dev, "%s: didn't match header or id. header = %02X, id = %02X\n", __func__, pSyncFrameHeader->header, pSyncFrameHeader->host_data_mem_id); rc = -4; goto ErrorExit; } totalbytes = (info->ForceChannelLength * info->SenseChannelLength * 2); regAdd[0] = 0xA6; regAdd[1] = 0x00; regAdd[2] = FTS_COMP_DATA_HEADER_SIZE + pSyncFrameHeader->dbg_frm_len; ret = info->fts_read_reg(info, ®Add[0], 3, &pRead[0], totalbytes); if (ret <= 0) { input_err(true, &info->client->dev, "%s: read failed rc = %d\n", __func__, ret); rc = -5; goto ErrorExit; } for (i = 0; i < totalbytes / 2; i++) info->pFrame[i] = (short)(pRead[i * 2] + (pRead[i * 2 + 1] << 8)); switch (type) { case TYPE_RAW_DATA: input_raw_info_d(true, &info->client->dev, "%s", "[Raw Data]\n"); break; case TYPE_STRENGTH_DATA: input_raw_info_d(true, &info->client->dev, "%s: [Strength Data]\n", __func__); break; case TYPE_BASELINE_DATA: input_raw_info_d(true, &info->client->dev, "%s: [Baseline Data]\n", __func__); break; } fts_print_frame(info, min, max); ErrorExit: kfree(pRead); return rc; } int fts_read_nonsync_frame(struct fts_ts_info *info, short *min, short *max) { struct FTS_SyncFrameHeader *pSyncFrameHeader; u8 regAdd[8] = { 0 }; unsigned int totalbytes = 0; u8 *pRead; int rc = 0; int ret = 0; int i = 0; int retry = 10; input_info(true, &info->client->dev, "%s\n", __func__); pRead = kzalloc(info->ForceChannelLength * info->SenseChannelLength * 3 + 1, GFP_KERNEL); if (!pRead) return -ENOMEM; /* Request System Information */ regAdd[0] = 0xA4; regAdd[1] = 0x06; regAdd[2] = 0x01; info->fts_write_reg(info, ®Add[0], 3); fts_delay(50); do { regAdd[0] = 0xA6; regAdd[1] = 0x00; regAdd[2] = 0x00; ret = info->fts_read_reg(info, ®Add[0], 3, &pRead[0], FTS_COMP_DATA_HEADER_SIZE); if (ret <= 0) { input_err(true, &info->client->dev, "%s: read failed rc = %d\n", __func__, ret); rc = -3; goto ErrorExit; } pSyncFrameHeader = (struct FTS_SyncFrameHeader *) &pRead[0]; if ((pSyncFrameHeader->header == 0xA5) && (pSyncFrameHeader->host_data_mem_id == 0x01)) break; fts_delay(100); } while (retry--); if (retry == 0) { input_err(true, &info->client->dev, "%s: didn't match header or id. header = %02X, id = %02X\n", __func__, pSyncFrameHeader->header, pSyncFrameHeader->host_data_mem_id); rc = -4; goto ErrorExit; } regAdd[0] = 0xA6; regAdd[1] = 0x00; regAdd[2] = 0x88; // ms screen rawdata ret = info->fts_read_reg(info, ®Add[0], 3, &pRead[0], 2); if (ret <= 0) { input_err(true, &info->client->dev, "%s: read failed rc = %d\n", __func__, ret); rc = -5; goto ErrorExit; } totalbytes = (info->ForceChannelLength * info->SenseChannelLength * 2); regAdd[0] = 0xA6; regAdd[1] = (u8)pRead[1]; regAdd[2] = (u8)pRead[0]; ret = info->fts_read_reg(info, ®Add[0], 3, &pRead[0], totalbytes); if (ret <= 0) { input_err(true, &info->client->dev, "%s: read failed rc = %d\n", __func__, ret); rc = -6; goto ErrorExit; } for (i = 0; i < totalbytes / 2; i++) info->pFrame[i] = (short)(pRead[i * 2] + (pRead[i * 2 + 1] << 8)); fts_print_frame(info, min, max); ErrorExit: kfree(pRead); return rc; } void fts_get_sec_ito_test_result(struct fts_ts_info *info) { struct sec_cmd_data *sec = &info->sec; struct fts_sec_panel_test_result result[10]; u8 regAdd[3] = { 0 }; u8 data[sizeof(struct fts_sec_panel_test_result) * 10 + 2] = { 0 }; int ret, i, max_count = 0; u8 length = sizeof(data); u8 buff[100] = { 0 }; u8 pos_buf[6] = { 0 }; regAdd[0] = 0xA4; regAdd[1] = 0x06; regAdd[2] = 0x94; ret = fts_fw_wait_for_echo_event(info, regAdd, 3, 0); if (ret < 0) { input_err(true, &info->client->dev, "%s: failed to get echo, %d\n", __func__, ret); goto done; } regAdd[0] = 0xA6; regAdd[1] = 0x00; regAdd[2] = 0x00; ret = info->fts_read_reg(info, regAdd, 3, data, length); if (ret < 0) { input_err(true, &info->client->dev, "%s: failed to read data, %d\n", __func__, ret); goto done; } memcpy(result, &data[2], length - 2); memset(info->ito_result, 0x00, FTS_ITO_RESULT_PRINT_SIZE); snprintf(buff, sizeof(buff), "%s: test count - sub:%d, main:%d\n", __func__, data[0], data[1]); input_info(true, &info->client->dev, "%s", buff); strlcat(info->ito_result, buff, FTS_ITO_RESULT_PRINT_SIZE); snprintf(buff, sizeof(buff), "ITO: / TX_GAP_MAX / RX_GAP_MAX\n"); input_info(true, &info->client->dev, "%s", buff); strlcat(info->ito_result, buff, FTS_ITO_RESULT_PRINT_SIZE); for (i = 0; i < 10; i++) { switch (result[i].flag) { case OFFSET_FAC_SUB: snprintf(pos_buf, sizeof(pos_buf), "SUB "); break; case OFFSET_FAC_MAIN: snprintf(pos_buf, sizeof(pos_buf), "MAIN"); break; case OFFSET_FAC_NOSAVE: default: snprintf(pos_buf, sizeof(pos_buf), "NONE"); break; } snprintf(buff, sizeof(buff), "ITO: [%3d] %d-%s / Tx%02d,Rx%02d: %3d / Tx%02d,Rx%02d: %3d\n", result[i].num_of_test, result[i].flag, pos_buf, result[i].tx_of_txmax_gap, result[i].rx_of_txmax_gap, result[i].max_of_tx_gap, result[i].tx_of_rxmax_gap, result[i].rx_of_rxmax_gap, result[i].max_of_rx_gap); input_info(true, &info->client->dev, "%s", buff); strlcat(info->ito_result, buff, FTS_ITO_RESULT_PRINT_SIZE); /* when count is over 200, it restart from 1 */ if (result[i].num_of_test > result[max_count].num_of_test + 100) continue; if (result[i].num_of_test > result[max_count].num_of_test) max_count = i; if (result[i].num_of_test == 1 && result[max_count].num_of_test == 200) max_count = i; } input_info(true, &info->client->dev, "%s: latest test is %d\n", __func__, result[max_count].num_of_test); done: if (sec->cmd_all_factory_state != SEC_CMD_STATUS_RUNNING) return; if (ret < 0) { snprintf(buff, sizeof(buff), "NG"); sec_cmd_set_cmd_result_all(sec, buff, strnlen(buff, sizeof(buff)), "CH_OPEN/SHORT_TEST_X"); sec_cmd_set_cmd_result_all(sec, buff, strnlen(buff, sizeof(buff)), "CH_OPEN/SHORT_TEST_Y"); } else { snprintf(buff, sizeof(buff), "0,%d", result[max_count].max_of_rx_gap); sec_cmd_set_cmd_result_all(sec, buff, strnlen(buff, sizeof(buff)), "CH_OPEN/SHORT_TEST_X"); snprintf(buff, sizeof(buff), "0,%d", result[max_count].max_of_tx_gap); sec_cmd_set_cmd_result_all(sec, buff, strnlen(buff, sizeof(buff)), "CH_OPEN/SHORT_TEST_Y"); } } int fts_set_sec_ito_test_result(struct fts_ts_info *info) { struct sec_cmd_data *sec = &info->sec; u8 regAdd[3] = { 0 }; int ret = -EINVAL; u8 buff[10] = { 0 }; if (!info->factory_position) { input_err(true, &info->client->dev, "%s: not save, factory level = %d\n", __func__, info->factory_position); goto out; } regAdd[0] = 0xC7; regAdd[1] = 0x06; regAdd[2] = info->factory_position; ret = info->fts_write_reg(info, regAdd, 3); if (ret < 0) { input_err(true, &info->client->dev, "%s: failed to write fac position, %d\n", __func__, ret); goto out; } regAdd[0] = 0xA4; regAdd[1] = 0x05; regAdd[2] = 0x04; ret = fts_fw_wait_for_echo_event(info, regAdd, 3, 200); if (ret < 0) { input_err(true, &info->client->dev, "%s: failed to get echo, %d\n", __func__, ret); goto out; } input_info(true, &info->client->dev, "%s: position %d result is saved\n", __func__, info->factory_position); return 0; out: if (sec->cmd_all_factory_state != SEC_CMD_STATUS_RUNNING) return ret; snprintf(buff, sizeof(buff), "NG"); sec_cmd_set_cmd_result_all(sec, buff, strnlen(buff, sizeof(buff)), "CH_OPEN/SHORT_TEST_X"); sec_cmd_set_cmd_result_all(sec, buff, strnlen(buff, sizeof(buff)), "CH_OPEN/SHORT_TEST_Y"); return ret; } int fts_fw_wait_for_jitter_result(struct fts_ts_info *info, u8 *reg, u8 count, s16 *ret1, s16 *ret2) { int rc = 0; u8 regAdd; u8 data[FTS_EVENT_SIZE]; int retry = 0; mutex_lock(&info->wait_for); rc = info->fts_write_reg(info, reg, count); if (rc < 0) { input_err(true, &info->client->dev, "%s: failed to write command\n", __func__); mutex_unlock(&info->wait_for); return rc; } memset(data, 0x0, FTS_EVENT_SIZE); regAdd = FTS_READ_ONE_EVENT; rc = -1; while (info->fts_read_reg(info, ®Add, 1, (u8 *)data, FTS_EVENT_SIZE)) { if (data[0] != 0x00) input_info(true, &info->client->dev, "%s: event %02X, %02X, %02X, %02X, %02X, %02X, %02X, %02X\n", __func__, data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7]); if ((data[0] == FTS_EVENT_JITTER_RESULT) && (data[1] == 0x03)) { // Check Jitter result if (data[2] == FTS_EVENT_JITTER_MUTUAL_MAX) { *ret2 = (s16)((data[3] << 8) + data[4]); input_info(true, &info->client->dev, "%s: Mutual max jitter Strength : %d, RX:%d, TX:%d\n", __func__, *ret2, data[5], data[6]); } else if (data[2] == FTS_EVENT_JITTER_MUTUAL_MIN){ *ret1 = (s16)((data[3] << 8) + data[4]); input_info(true, &info->client->dev, "%s: Mutual min jitter Strength : %d, RX:%d, TX:%d\n", __func__, *ret1, data[5], data[6]); rc = 0; break; } else if (data[2] == FTS_EVENT_JITTER_SELF_TX_P2P){ *ret1 = (s16)((data[3] << 8) + data[4]); input_info(true, &info->client->dev, "%s: Self TX P2P jitter Strength : %d, TX:%d\n", __func__, *ret1, data[6]); } else if (data[2] == FTS_EVENT_JITTER_SELF_RX_P2P){ *ret2 = (s16)((data[3] << 8) + data[4]); input_info(true, &info->client->dev, "%s: Self RX P2P jitter Strength : %d, RX:%d\n", __func__, *ret2, data[5]); rc = 0; break; } } else if (data[0] == FTS_EVENT_ERROR_REPORT) { input_info(true, &info->client->dev, "%s: Error detected %02X,%02X,%02X,%02X,%02X,%02X\n", __func__, data[0], data[1], data[2], data[3], data[4], data[5]); break; } if (retry++ > FTS_RETRY_COUNT * 10) { rc = -1; input_err(true, &info->client->dev, "%s: Time Over (%02X,%02X,%02X,%02X,%02X,%02X)\n", __func__, data[0], data[1], data[2], data[3], data[4], data[5]); break; } fts_delay(20); } mutex_unlock(&info->wait_for); return rc; } static void run_jitter_test(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct fts_ts_info *info = container_of(sec, struct fts_ts_info, sec); char buff[SEC_CMD_STR_LEN] = { 0 }; u8 regAdd[4] = { 0 }; int ret; s16 mutual_min = 0, mutual_max = 0; sec_cmd_set_default_result(sec); if (info->fts_power_state == FTS_POWER_STATE_POWERDOWN || info->fts_power_state == FTS_POWER_STATE_LOWPOWER) { input_err(true, &info->client->dev, "%s: [ERROR] Touch is stopped\n", __func__); snprintf(buff, sizeof(buff), "NG"); sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); sec->cmd_state = SEC_CMD_STATUS_FAIL; return; } info->fts_systemreset(info, 0); fts_release_all_finger(info); fts_interrupt_set(info, INT_DISABLE); /* lock active scan mode */ regAdd[0] = 0xA0; regAdd[1] = 0x03; regAdd[2] = 0x00; info->fts_write_reg(info, ®Add[0], 3); fts_delay(10); // Mutual jitter. regAdd[0] = 0xC7; regAdd[1] = 0x08; regAdd[2] = 0x64; //100 frame regAdd[3] = 0x00; ret = fts_fw_wait_for_jitter_result(info, regAdd, 4, &mutual_min, &mutual_max); if (ret < 0) { input_info(true, &info->client->dev, "%s: failed to read Mutual jitter\n", __func__); goto ERROR; } info->fts_systemreset(info, 0); fts_set_scanmode(info, info->scan_mode); fts_interrupt_set(info, INT_ENABLE); snprintf(buff, sizeof(buff), "%d", mutual_max); if (sec->cmd_all_factory_state == SEC_CMD_STATUS_RUNNING) sec_cmd_set_cmd_result_all(sec, buff, strnlen(buff, sizeof(buff)), "MUTUAL_JITTER"); sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); sec->cmd_state = SEC_CMD_STATUS_OK; input_info(true, &info->client->dev, "%s: %s\n", __func__, buff); return; ERROR: info->fts_systemreset(info, 0); fts_set_scanmode(info, info->scan_mode); fts_interrupt_set(info, INT_ENABLE); snprintf(buff, sizeof(buff), "NG"); if (sec->cmd_all_factory_state == SEC_CMD_STATUS_RUNNING) sec_cmd_set_cmd_result_all(sec, buff, strnlen(buff, sizeof(buff)), "MUTUAL_JITTER"); sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); sec->cmd_state = SEC_CMD_STATUS_FAIL; input_info(true, &info->client->dev, "%s: Fail %s\n", __func__, buff); return; } static void run_mutual_jitter(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct fts_ts_info *info = container_of(sec, struct fts_ts_info, sec); char buff[SEC_CMD_STR_LEN] = { 0 }; u8 regAdd[4] = { 0 }; int ret; s16 mutual_min = 0, mutual_max = 0; sec_cmd_set_default_result(sec); if (info->fts_power_state == FTS_POWER_STATE_POWERDOWN || info->fts_power_state == FTS_POWER_STATE_LOWPOWER) { input_err(true, &info->client->dev, "%s: [ERROR] Touch is stopped\n", __func__); snprintf(buff, sizeof(buff), "NG"); sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); sec->cmd_state = SEC_CMD_STATUS_FAIL; return; } info->fts_systemreset(info, 0); fts_release_all_finger(info); fts_interrupt_set(info, INT_DISABLE); //lock active scan mode. fts_fix_active_mode(info, true); // Mutual jitter. regAdd[0] = 0xC7; regAdd[1] = 0x08; regAdd[2] = 0x64; //100 frame regAdd[3] = 0x00; ret = fts_fw_wait_for_jitter_result(info, regAdd, 4, &mutual_min, &mutual_max); if (ret < 0) { input_info(true, &info->client->dev, "%s: failed to read Mutual jitter\n", __func__); goto ERROR; } info->fts_systemreset(info, 0); fts_set_scanmode(info, info->scan_mode); fts_interrupt_set(info, INT_ENABLE); snprintf(buff, sizeof(buff), "%d,%d", mutual_min, mutual_max); if (sec->cmd_all_factory_state == SEC_CMD_STATUS_RUNNING) sec_cmd_set_cmd_result_all(sec, buff, strnlen(buff, sizeof(buff)), "MUTUAL_JITTER"); sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); sec->cmd_state = SEC_CMD_STATUS_OK; input_raw_info_d(true, &info->client->dev, "%s: %s\n", __func__, buff); return; ERROR: info->fts_systemreset(info, 0); fts_set_scanmode(info, info->scan_mode); fts_interrupt_set(info, INT_ENABLE); snprintf(buff, sizeof(buff), "NG"); if (sec->cmd_all_factory_state == SEC_CMD_STATUS_RUNNING) sec_cmd_set_cmd_result_all(sec, buff, strnlen(buff, sizeof(buff)), "MUTUAL_JITTER"); sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); sec->cmd_state = SEC_CMD_STATUS_FAIL; input_raw_info_d(true, &info->client->dev, "%s: Fail %s\n", __func__, buff); return; } static void run_self_jitter(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct fts_ts_info *info = container_of(sec, struct fts_ts_info, sec); char buff[SEC_CMD_STR_LEN] = { 0 }; u8 regAdd[4] = { 0 }; int ret; s16 tx_p2p = 0, rx_p2p = 0; sec_cmd_set_default_result(sec); if (info->fts_power_state == FTS_POWER_STATE_POWERDOWN || info->fts_power_state == FTS_POWER_STATE_LOWPOWER) { input_err(true, &info->client->dev, "%s: [ERROR] Touch is stopped\n", __func__); snprintf(buff, sizeof(buff), "NG"); sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); sec->cmd_state = SEC_CMD_STATUS_FAIL; return; } info->fts_systemreset(info, 0); fts_release_all_finger(info); fts_interrupt_set(info, INT_DISABLE); /* lock active scan mode */ regAdd[0] = 0xA0; regAdd[1] = 0x03; regAdd[2] = 0x00; info->fts_write_reg(info, ®Add[0], 3); fts_delay(10); /* Self jitter */ regAdd[0] = 0xC7; regAdd[1] = 0x0A; regAdd[2] = 0x64; /* 100 frame */ regAdd[3] = 0x00; ret = fts_fw_wait_for_jitter_result(info, regAdd, 4, &tx_p2p, &rx_p2p); if (ret < 0) { input_info(true, &info->client->dev, "%s: failed to read Self jitter\n", __func__); goto ERROR; } info->fts_systemreset(info, 0); fts_set_scanmode(info, info->scan_mode); fts_interrupt_set(info, INT_ENABLE); snprintf(buff, sizeof(buff), "%d,%d", tx_p2p, rx_p2p); if (sec->cmd_all_factory_state == SEC_CMD_STATUS_RUNNING) sec_cmd_set_cmd_result_all(sec, buff, strnlen(buff, sizeof(buff)), "SELF_JITTER"); sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); sec->cmd_state = SEC_CMD_STATUS_OK; input_raw_info_d(true, &info->client->dev, "%s: %s\n", __func__, buff); return; ERROR: info->fts_systemreset(info, 0); fts_set_scanmode(info, info->scan_mode); fts_interrupt_set(info, INT_ENABLE); snprintf(buff, sizeof(buff), "NG"); if (sec->cmd_all_factory_state == SEC_CMD_STATUS_RUNNING) sec_cmd_set_cmd_result_all(sec, buff, strnlen(buff, sizeof(buff)), "SELF_JITTER"); sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); sec->cmd_state = SEC_CMD_STATUS_FAIL; input_raw_info_d(true, &info->client->dev, "%s: Fail %s\n", __func__, buff); return; } static void run_jitter_delta_test(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct fts_ts_info *info = container_of(sec, struct fts_ts_info, sec); char buff[SEC_CMD_STR_LEN] = { 0 }; u8 reg[4] = { 0 }; int ret; int result = -1; int retry = 0; u8 data[FTS_EVENT_SIZE]; s16 min_of_min = 0; s16 max_of_min = 0; s16 min_of_max = 0; s16 max_of_max = 0; s16 min_of_avg = 0; s16 max_of_avg = 0; sec_cmd_set_default_result(sec); if (info->fts_power_state == FTS_POWER_STATE_POWERDOWN || info->fts_power_state == FTS_POWER_STATE_LOWPOWER) { goto OUT_JITTER_DELTA; } info->fts_systemreset(info, 0); fts_release_all_finger(info); fts_interrupt_set(info, INT_DISABLE); mutex_lock(&info->wait_for); /* lock active scan mode */ reg[0] = 0xA0; reg[1] = 0x03; reg[2] = 0x00; ret = info->fts_write_reg(info, ®[0], 3); if (ret < 0) { input_info(true, &info->client->dev, "%s: failed to set active mode\n", __func__); mutex_unlock(&info->wait_for); goto OUT_JITTER_DELTA; } fts_delay(10); /* jitter delta + 1000 frame*/ reg[0] = 0xC7; reg[1] = 0x08; reg[2] = 0xE8; reg[3] = 0x03; ret = info->fts_write_reg(info, ®[0], 4); if (ret < 0) { input_err(true, &info->client->dev, "%s: failed to write command\n", __func__); mutex_unlock(&info->wait_for); goto OUT_JITTER_DELTA; } memset(data, 0x0, FTS_EVENT_SIZE); reg[0] = FTS_READ_ONE_EVENT; while (info->fts_read_reg(info, ®[0], 1, data, FTS_EVENT_SIZE)) { if ((data[0] == FTS_EVENT_JITTER_RESULT) && (data[1] == 0x03)) { if (data[2] == FTS_EVENT_JITTER_MUTUAL_MAX) { min_of_max = data[3] << 8 | data[4]; max_of_max = data[8] << 8 | data[9]; input_info(true, &info->client->dev, "%s: MAX: min:%d, max:%d\n", __func__, min_of_max, max_of_max); } else if (data[2] == FTS_EVENT_JITTER_MUTUAL_MIN) { min_of_min = data[3] << 8 | data[4]; max_of_min = data[8] << 8 | data[9]; input_info(true, &info->client->dev, "%s: MIN: min:%d, max:%d\n", __func__, min_of_min, max_of_min); } else if (data[2] == FTS_EVENT_JITTER_MUTUAL_AVG) { min_of_avg = data[3] << 8 | data[4]; max_of_avg = data[8] << 8 | data[9]; input_info(true, &info->client->dev, "%s: AVG: min:%d, max:%d\n", __func__, min_of_avg, max_of_avg); result = 0; break; } } else if (data[0] == FTS_EVENT_ERROR_REPORT) { input_info(true, &info->client->dev, "%s: Error detected %02X,%02X,%02X,%02X,%02X,%02X\n", __func__, data[0], data[1], data[2], data[3], data[4], data[5]); break; } /* waiting 10 seconds */ if (retry++ > FTS_RETRY_COUNT * 50) { input_err(true, &info->client->dev, "%s: Time Over (%02X,%02X,%02X,%02X,%02X,%02X)\n", __func__, data[0], data[1], data[2], data[3], data[4], data[5]); break; } fts_delay(20); } mutex_unlock(&info->wait_for); OUT_JITTER_DELTA: info->fts_systemreset(info, 0); fts_set_scanmode(info, info->scan_mode); fts_interrupt_set(info, INT_ENABLE); if (result < 0) snprintf(buff, sizeof(buff), "NG"); else snprintf(buff, sizeof(buff), "%d,%d,%d,%d,%d,%d", min_of_min, max_of_min, min_of_max, max_of_max, min_of_avg, max_of_avg); if (sec->cmd_all_factory_state == SEC_CMD_STATUS_RUNNING) { char buffer[SEC_CMD_STR_LEN] = { 0 }; snprintf(buffer, sizeof(buffer), "%d,%d", min_of_min, max_of_min); sec_cmd_set_cmd_result_all(sec, buffer, strnlen(buffer, sizeof(buffer)), "JITTER_DELTA_MIN"); memset(buffer, 0x00, sizeof(buffer)); snprintf(buffer, sizeof(buffer), "%d,%d", min_of_max, max_of_max); sec_cmd_set_cmd_result_all(sec, buffer, strnlen(buffer, sizeof(buffer)), "JITTER_DELTA_MAX"); memset(buffer, 0x00, sizeof(buffer)); snprintf(buffer, sizeof(buffer), "%d,%d", min_of_avg, max_of_avg); sec_cmd_set_cmd_result_all(sec, buffer, strnlen(buffer, sizeof(buffer)), "JITTER_DELTA_AVG"); } sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); sec->cmd_state = SEC_CMD_STATUS_OK; input_info(true, &info->client->dev, "%s: %s\n", __func__, buff); } void fts_checking_miscal(struct fts_ts_info *info) { u8 regAdd[3] = { 0 }; u8 data[2] = { 0 }; u16 miscal_thd = 0; int ret; short min = 0x7FFF; short max = 0x8000; info->miscal_result = MISCAL_PASS; info->fts_systemreset(info, 0); fts_command(info, FTS_CMD_CLEAR_ALL_EVENT, true); fts_interrupt_set(info, INT_DISABLE); fts_release_all_finger(info); /* get the raw data after C7 02 : mis cal test */ regAdd[0] = 0xC7; regAdd[1] = 0x02; info->fts_write_reg(info, ®Add[0], 2); msleep(300); input_raw_info_d(true, &info->client->dev, "%s: [miscal diff data]\n", __func__); fts_read_nonsync_frame(info, &min, &max); regAdd[0] = 0xC7; regAdd[1] = 0x0B; ret = info->fts_read_reg(info, regAdd, 2, data, 2); if (ret < 0) { input_err(true, &info->client->dev, "%s: failed to read miscal threshold\n", __func__); return; } miscal_thd = data[0] << 8 | data[1]; if (max > miscal_thd) info->miscal_result = MISCAL_FAIL; if (min < -miscal_thd) info->miscal_result = MISCAL_FAIL; fts_set_scanmode(info, info->scan_mode); input_raw_info_d(true, &info->client->dev, "%s: mis cal threshold:%d/%d, min/max :%d/%d, miscal:%s\n", __func__, miscal_thd, -miscal_thd, min, max, info->miscal_result == MISCAL_PASS ? "PASS" : "FAIL"); } int fts_panel_ito_test(struct fts_ts_info *info, int testmode) { u8 cmd = FTS_READ_ONE_EVENT; u8 regAdd[4] = { 0 }; u8 data[FTS_EVENT_SIZE]; int i; bool matched = false; int retry = 0; int result = 0; result = info->fts_systemreset(info, 0); if (result < 0) { input_info(true, &info->client->dev, "%s: fts_systemreset fail (%d)\n", __func__, result); return result; } fts_command(info, FTS_CMD_CLEAR_ALL_EVENT, true); fts_release_all_finger(info); fts_interrupt_set(info, INT_DISABLE); regAdd[0] = 0xA4; regAdd[1] = 0x04; switch (testmode) { case OPEN_TEST: regAdd[2] = 0x00; regAdd[3] = 0x30; break; case OPEN_SHORT_CRACK_TEST: case SAVE_MISCAL_REF_RAW: default: regAdd[2] = 0xFF; regAdd[3] = 0x01; break; } info->fts_write_reg(info, ®Add[0], 4); // ITO test command fts_delay(100); memset(info->ito_test, 0x0, 4); memset(data, 0x0, FTS_EVENT_SIZE); while (info->fts_read_reg(info, &cmd, 1, (u8 *)data, FTS_EVENT_SIZE)) { if ((data[0] == FTS_EVENT_STATUS_REPORT) && (data[1] == 0x01)) { // Check command ECHO - finished for (i = 0; i < 4; i++) { if (data[i + 2] != regAdd[i]) { matched = false; break; } matched = true; } if (matched == true) break; } else if (data[0] == FTS_EVENT_ERROR_REPORT) { info->ito_test[0] = data[0]; info->ito_test[1] = data[1]; info->ito_test[2] = data[2]; info->ito_test[3] = 0x00; result = -ITO_FAIL; switch (data[1]) { case ITO_FORCE_SHRT_GND: input_info(true, &info->client->dev, "%s: Force channel [%d] short to GND\n", __func__, data[2]); result = -ITO_FAIL_SHORT; break; case ITO_SENSE_SHRT_GND: input_info(true, &info->client->dev, "%s: Sense channel [%d] short to GND\n", __func__, data[2]); result = ITO_FAIL_SHORT; break; case ITO_FORCE_SHRT_VDD: input_info(true, &info->client->dev, "%s: Force channel [%d] short to VDD\n", __func__, data[2]); result = -ITO_FAIL_SHORT; break; case ITO_SENSE_SHRT_VDD: input_info(true, &info->client->dev, "%s: Sense channel [%d] short to VDD\n", __func__, data[2]); result = -ITO_FAIL_SHORT; break; case ITO_FORCE_SHRT_FORCE: input_info(true, &info->client->dev, "%s: Force channel [%d] short to force\n", __func__, data[2]); result = -ITO_FAIL_SHORT; break; case ITO_SENSE_SHRT_SENSE: input_info(true, &info->client->dev, "%s: Sennse channel [%d] short to sense\n", __func__, data[2]); result = -ITO_FAIL_SHORT; break; case ITO_FORCE_OPEN: input_info(true, &info->client->dev, "%s: Force channel [%d] open\n", __func__, data[2]); result = -ITO_FAIL_OPEN; break; case ITO_SENSE_OPEN: input_info(true, &info->client->dev, "%s: Sense channel [%d] open\n", __func__, data[2]); result = -ITO_FAIL_OPEN; break; case ITO_KEY_OPEN: input_info(true, &info->client->dev, "%s: Key channel [%d] open\n", __func__, data[2]); result = -ITO_FAIL_OPEN; break; default: input_info(true, &info->client->dev, "%s: unknown event %02x %02x %02x %02x %02x %02x %02x %02x\n", __func__, data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7]); break; } } if (retry++ > 50) { result = -ITO_FAIL; input_err(true, &info->client->dev, "%s: Time over - wait for result of ITO test\n", __func__); break; } fts_delay(20); } if (fts_set_sec_ito_test_result(info) >= 0) fts_get_sec_ito_test_result(info); info->fts_systemreset(info, 0); if (info->flip_enable) { fts_set_cover_type(info, true); } else { info->touch_functions = (info->touch_functions & (~FTS_TOUCHTYPE_BIT_COVER)) | FTS_TOUCHTYPE_DEFAULT_ENABLE; #ifdef CONFIG_GLOVE_TOUCH if (info->glove_enabled) info->touch_functions = info->touch_functions | FTS_TOUCHTYPE_BIT_GLOVE; else info->touch_functions = info->touch_functions & (~FTS_TOUCHTYPE_BIT_GLOVE); #endif } regAdd[0] = FTS_CMD_SET_GET_TOUCHTYPE; regAdd[1] = (u8)(info->touch_functions & 0xFF); regAdd[2] = (u8)(info->touch_functions >> 8); fts_write_reg(info, ®Add[0], 3); fts_delay(10); #ifdef FTS_SUPPORT_TA_MODE if (info->TA_Pluged) { u8 wiredCharger; regAdd[0] = FTS_CMD_SET_GET_CHARGER_MODE; fts_read_reg(info, ®Add[0], 1, &data[0], 1); wiredCharger = data[0] | FTS_BIT_CHARGER_MODE_WIRE_CHARGER; regAdd[1] = { wiredCharger }; fts_write_reg(info, ®Add[0], 2); fts_delay(10); } #endif info->touch_count = 0; fts_set_scanmode(info, info->scan_mode); input_raw_info_d(true, &info->client->dev, "%s: mode:%d [%s] %02X %02X %02X %02X\n", __func__, testmode, result < 0 ? "FAIL" : "PASS", info->ito_test[0], info->ito_test[1], info->ito_test[2], info->ito_test[3]); return result; } static void get_fw_ver_bin(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct fts_ts_info *info = container_of(sec, struct fts_ts_info, sec); char buff[16] = { 0 }; sec_cmd_set_default_result(sec); snprintf(buff, sizeof(buff), "ST%02X%02X%02X%02X", info->ic_name_of_bin, info->project_id_of_bin, info->module_version_of_bin, info->fw_main_version_of_bin & 0xFF); sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); if (sec->cmd_all_factory_state == SEC_CMD_STATUS_RUNNING) sec_cmd_set_cmd_result_all(sec, buff, strnlen(buff, sizeof(buff)), "FW_VER_BIN"); sec->cmd_state = SEC_CMD_STATUS_OK; input_info(true, &info->client->dev, "%s: %s\n", __func__, buff); } static void get_fw_ver_ic(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct fts_ts_info *info = container_of(sec, struct fts_ts_info, sec); char buff[16] = { 0 }; char model_ver[7] = { 0 }; sec_cmd_set_default_result(sec); if (info->fts_power_state == FTS_POWER_STATE_POWERDOWN) { input_err(true, &info->client->dev, "%s: [ERROR] Touch is stopped\n", __func__); snprintf(buff, sizeof(buff), "NG"); sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); if (sec->cmd_all_factory_state == SEC_CMD_STATUS_RUNNING) { sec_cmd_set_cmd_result_all(sec, buff, strnlen(buff, sizeof(buff)), "FW_VER_IC"); sec_cmd_set_cmd_result_all(sec, buff, strnlen(buff, sizeof(buff)), "FW_MODEL"); } sec->cmd_state = SEC_CMD_STATUS_FAIL; return; } fts_get_version_info(info); snprintf(buff, sizeof(buff), "ST%02X%02X%02X%02X", info->ic_name_of_ic, info->project_id_of_ic, info->module_version_of_ic, info->fw_main_version_of_ic & 0xFF); snprintf(model_ver, sizeof(model_ver), "ST%02X%02X", info->ic_name_of_ic, info->project_id_of_ic); sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); if (sec->cmd_all_factory_state == SEC_CMD_STATUS_RUNNING) { sec_cmd_set_cmd_result_all(sec, buff, strnlen(buff, sizeof(buff)), "FW_VER_IC"); sec_cmd_set_cmd_result_all(sec, model_ver, strnlen(model_ver, sizeof(model_ver)), "FW_MODEL"); } sec->cmd_state = SEC_CMD_STATUS_OK; input_info(true, &info->client->dev, "%s: %s\n", __func__, buff); } static void get_config_ver(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct fts_ts_info *info = container_of(sec, struct fts_ts_info, sec); char buff[20] = { 0 }; snprintf(buff, sizeof(buff), "ST_%04X", info->config_version_of_ic); sec_cmd_set_default_result(sec); sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); sec->cmd_state = SEC_CMD_STATUS_OK; input_info(true, &info->client->dev, "%s: %s\n", __func__, buff); } static void get_threshold(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct fts_ts_info *info = container_of(sec, struct fts_ts_info, sec); u8 regAdd[2]; u8 buff[16] = { 0 }; u8 data[5] = { 0 }; u16 finger_threshold = 0; int rc; sec_cmd_set_default_result(sec); if (info->fts_power_state == FTS_POWER_STATE_POWERDOWN) { input_err(true, &info->client->dev, "%s: [ERROR] Touch is stopped\n", __func__); snprintf(buff, sizeof(buff), "NG"); sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); sec->cmd_state = SEC_CMD_STATUS_FAIL; return; } sec->cmd_state = SEC_CMD_STATUS_RUNNING; regAdd[0] = FTS_CMD_SET_GET_TOUCH_MODE_FOR_THRESHOLD; regAdd[1] = 0x00; info->fts_write_reg(info, ®Add[0], 2); fts_delay(50); regAdd[0] = FTS_CMD_SET_GET_TOUCH_THRESHOLD; rc = info->fts_read_reg(info, ®Add[0], 1, data, 2); if (rc <= 0) { input_err(true, &info->client->dev, "%s: Get threshold Read Fail!! [Data : %2X%2X]\n", __func__, data[0], data[1]); snprintf(buff, sizeof(buff), "NG"); sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); sec->cmd_state = SEC_CMD_STATUS_FAIL; return; } finger_threshold = (u16)(data[0] << 8 | data[1]); snprintf(buff, sizeof(buff), "%d", finger_threshold); sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); sec->cmd_state = SEC_CMD_STATUS_OK; input_info(true, &info->client->dev, "%s: %s\n", __func__, buff); } static void module_off_master(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct fts_ts_info *info = container_of(sec, struct fts_ts_info, sec); char buff[3] = { 0 }; int ret = 0; ret = fts_stop_device(info); if (ret == 0) snprintf(buff, sizeof(buff), "OK"); else snprintf(buff, sizeof(buff), "NG"); sec_cmd_set_default_result(sec); sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); if (strncmp(buff, "OK", 2) == 0) sec->cmd_state = SEC_CMD_STATUS_OK; else sec->cmd_state = SEC_CMD_STATUS_FAIL; input_info(true, &info->client->dev, "%s: %s\n", __func__, buff); } static void module_on_master(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct fts_ts_info *info = container_of(sec, struct fts_ts_info, sec); char buff[3] = { 0 }; int ret = 0; ret = fts_start_device(info); if (ret == 0) snprintf(buff, sizeof(buff), "OK"); else snprintf(buff, sizeof(buff), "NG"); sec_cmd_set_default_result(sec); sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); if (strncmp(buff, "OK", 2) == 0) sec->cmd_state = SEC_CMD_STATUS_OK; else sec->cmd_state = SEC_CMD_STATUS_FAIL; input_info(true, &info->client->dev, "%s: %s\n", __func__, buff); } static void get_chip_vendor(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct fts_ts_info *info = container_of(sec, struct fts_ts_info, sec); char buff[16] = { 0 }; snprintf(buff, sizeof(buff), "STM"); sec_cmd_set_default_result(sec); sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); if (sec->cmd_all_factory_state == SEC_CMD_STATUS_RUNNING) sec_cmd_set_cmd_result_all(sec, buff, strnlen(buff, sizeof(buff)), "IC_VENDOR"); sec->cmd_state = SEC_CMD_STATUS_OK; input_info(true, &info->client->dev, "%s: %s\n", __func__, buff); } static void get_chip_name(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct fts_ts_info *info = container_of(sec, struct fts_ts_info, sec); char buff[16] = { 0 }; if (info->firmware_name) memcpy(buff, info->firmware_name + 8, 9); else snprintf(buff, 10, "FTS"); sec_cmd_set_default_result(sec); sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); if (sec->cmd_all_factory_state == SEC_CMD_STATUS_RUNNING) sec_cmd_set_cmd_result_all(sec, buff, strnlen(buff, sizeof(buff)), "IC_NAME"); sec->cmd_state = SEC_CMD_STATUS_OK; input_info(true, &info->client->dev, "%s: %s\n", __func__, buff); } static void get_wet_mode(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct fts_ts_info *info = container_of(sec, struct fts_ts_info, sec); char buff[SEC_CMD_STR_LEN] = { 0 }; u8 regAdd[3] = { 0 }; u8 data[2] = { 0 }; int ret; sec_cmd_set_default_result(sec); if (info->fts_power_state == FTS_POWER_STATE_POWERDOWN) { input_err(true, &info->client->dev, "%s: [ERROR] Touch is stopped\n", __func__); snprintf(buff, sizeof(buff), "NG"); sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); if (sec->cmd_all_factory_state == SEC_CMD_STATUS_RUNNING) sec_cmd_set_cmd_result_all(sec, buff, strnlen(buff, sizeof(buff)), "WET_MODE"); sec->cmd_state = SEC_CMD_STATUS_FAIL; return; } regAdd[0] = 0xC7; regAdd[1] = 0x03; ret = info->fts_read_reg(info, ®Add[0], 2, &data[0], 1); if (ret < 0) { input_err(true, &info->client->dev, "%s: [ERROR] failed to read\n", __func__); snprintf(buff, sizeof(buff), "%s", "NG"); sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); if (sec->cmd_all_factory_state == SEC_CMD_STATUS_RUNNING) sec_cmd_set_cmd_result_all(sec, buff, strnlen(buff, sizeof(buff)), "WET_MODE"); sec->cmd_state = SEC_CMD_STATUS_FAIL; return; } snprintf(buff, sizeof(buff), "%d", data[0]); sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); if (sec->cmd_all_factory_state == SEC_CMD_STATUS_RUNNING) sec_cmd_set_cmd_result_all(sec, buff, strnlen(buff, sizeof(buff)), "WET_MODE"); sec->cmd_state = SEC_CMD_STATUS_OK; input_info(true, &info->client->dev, "%s: %s\n", __func__, buff); } static void get_x_num(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct fts_ts_info *info = container_of(sec, struct fts_ts_info, sec); char buff[16] = { 0 }; sec_cmd_set_default_result(sec); snprintf(buff, sizeof(buff), "%d", info->ForceChannelLength); sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); sec->cmd_state = SEC_CMD_STATUS_OK; input_info(true, &info->client->dev, "%s: %s\n", __func__, buff); } static void get_y_num(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct fts_ts_info *info = container_of(sec, struct fts_ts_info, sec); char buff[16] = { 0 }; sec_cmd_set_default_result(sec); snprintf(buff, sizeof(buff), "%d", info->SenseChannelLength); sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); sec->cmd_state = SEC_CMD_STATUS_OK; input_info(true, &info->client->dev, "%s: %s\n", __func__, buff); } static void get_checksum_data(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct fts_ts_info *info = container_of(sec, struct fts_ts_info, sec); char buff[16] = { 0 }; int rc; u32 checksum_data; sec_cmd_set_default_result(sec); if (info->fts_power_state == FTS_POWER_STATE_POWERDOWN) { input_err(true, &info->client->dev, "%s: [ERROR] Touch is stopped\n", __func__); snprintf(buff, sizeof(buff), "NG"); sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); sec->cmd_state = SEC_CMD_STATUS_FAIL; return; } info->fts_systemreset(info, 0); rc = info->fts_get_sysinfo_data(info, FTS_SI_CONFIG_CHECKSUM, 4, (u8 *)&checksum_data); if (rc < 0) { input_err(true, &info->client->dev, "%s: Get checksum data Read Fail!! [Data : %08X]\n", __func__, checksum_data); snprintf(buff, sizeof(buff), "NG"); sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); sec->cmd_state = SEC_CMD_STATUS_FAIL; return; } fts_reinit(info, false); snprintf(buff, sizeof(buff), "%08X", checksum_data); sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); sec->cmd_state = SEC_CMD_STATUS_OK; input_info(true, &info->client->dev, "%s: %s\n", __func__, buff); } static void check_fw_corruption(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct fts_ts_info *info = container_of(sec, struct fts_ts_info, sec); char buff[16] = { 0 }; int rc; sec_cmd_set_default_result(sec); if (info->fw_corruption) { snprintf(buff, sizeof(buff), "NG"); sec->cmd_state = SEC_CMD_STATUS_FAIL; } else { rc = fts_fw_corruption_check(info); if (rc == -FTS_ERROR_FW_CORRUPTION) { snprintf(buff, sizeof(buff), "NG"); sec->cmd_state = SEC_CMD_STATUS_FAIL; } else { snprintf(buff, sizeof(buff), "OK"); sec->cmd_state = SEC_CMD_STATUS_OK; fts_reinit(info, false); } } info->fw_corruption = false; sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); input_info(true, &info->client->dev, "%s: %s\n", __func__, buff); } static void run_reference_read(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct fts_ts_info *info = container_of(sec, struct fts_ts_info, sec); char buff[SEC_CMD_STR_LEN] = { 0 }; short min = 0x7FFF; short max = 0x8000; sec_cmd_set_default_result(sec); if (info->fts_power_state == FTS_POWER_STATE_POWERDOWN) { input_err(true, &info->client->dev, "%s: [ERROR] Touch is stopped\n", __func__); snprintf(buff, sizeof(buff), "NG"); sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); sec->cmd_state = SEC_CMD_STATUS_FAIL; return; } fts_read_frame(info, TYPE_BASELINE_DATA, &min, &max); snprintf(buff, sizeof(buff), "%d,%d", min, max); sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); sec->cmd_state = SEC_CMD_STATUS_OK; input_info(true, &info->client->dev, "%s: %s\n", __func__, buff); } static void get_reference(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct fts_ts_info *info = container_of(sec, struct fts_ts_info, sec); char buff[SEC_CMD_STR_LEN] = { 0 }; short val = 0; int node = 0; sec_cmd_set_default_result(sec); if (info->fts_power_state == FTS_POWER_STATE_POWERDOWN) { input_err(true, &info->client->dev, "%s: [ERROR] Touch is stopped\n", __func__); snprintf(buff, sizeof(buff), "NG"); sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); sec->cmd_state = SEC_CMD_STATUS_FAIL; return; } node = fts_check_index(info); if (node < 0) return; val = info->pFrame[node]; snprintf(buff, sizeof(buff), "%d", val); sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); sec->cmd_state = SEC_CMD_STATUS_OK; input_info(true, &info->client->dev, "%s: %s\n", __func__, buff); } static void run_rawcap_read(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct fts_ts_info *info = container_of(sec, struct fts_ts_info, sec); char buff[SEC_CMD_STR_LEN] = { 0 }; short min = 0x7FFF; short max = 0x8000; sec_cmd_set_default_result(sec); if (info->fts_power_state == FTS_POWER_STATE_POWERDOWN) { input_err(true, &info->client->dev, "%s: [ERROR] Touch is stopped\n", __func__); snprintf(buff, sizeof(buff), "NG"); sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); if (sec->cmd_all_factory_state == SEC_CMD_STATUS_RUNNING) sec_cmd_set_cmd_result_all(sec, buff, strnlen(buff, sizeof(buff)), "RAW_DATA"); sec->cmd_state = SEC_CMD_STATUS_FAIL; return; } fts_read_frame(info, TYPE_RAW_DATA, &min, &max); snprintf(buff, sizeof(buff), "%d,%d", min, max); sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); if (sec->cmd_all_factory_state == SEC_CMD_STATUS_RUNNING) sec_cmd_set_cmd_result_all(sec, buff, strnlen(buff, sizeof(buff)), "RAW_DATA"); sec->cmd_state = SEC_CMD_STATUS_OK; input_info(true, &info->client->dev, "%s: %s\n", __func__, buff); } static void run_rawcap_read_all(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct fts_ts_info *info = container_of(sec, struct fts_ts_info, sec); char buff[SEC_CMD_STR_LEN] = { 0 }; short min = 0x7FFF; short max = 0x8000; char *all_strbuff; int i, j; sec_cmd_set_default_result(sec); if (info->fts_power_state == FTS_POWER_STATE_POWERDOWN) { input_err(true, &info->client->dev, "%s: [ERROR] Touch is stopped\n", __func__); snprintf(buff, sizeof(buff), "NG"); sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); sec->cmd_state = SEC_CMD_STATUS_FAIL; return; } all_strbuff = kzalloc(info->ForceChannelLength * info->SenseChannelLength * 7 + 1, GFP_KERNEL); if (!all_strbuff) { snprintf(buff, sizeof(buff), "NG"); sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); sec->cmd_state = SEC_CMD_STATUS_FAIL; return; } input_raw_info_d(true, &info->client->dev, "%s\n", __func__); enter_factory_mode(info, true); fts_read_frame(info, TYPE_RAW_DATA, &min, &max); for (j = 0; j < info->ForceChannelLength; j++) { for (i = 0; i < info->SenseChannelLength; i++) { snprintf(buff, sizeof(buff), "%d,", info->pFrame[j * info->SenseChannelLength + i]); strlcat(all_strbuff, buff, info->ForceChannelLength * info->SenseChannelLength * 7); } } enter_factory_mode(info, false); sec->cmd_state = SEC_CMD_STATUS_OK; sec_cmd_set_cmd_result(sec, all_strbuff, strlen(all_strbuff)); input_info(true, &info->client->dev, "%s: %ld\n", __func__, strlen(all_strbuff)); kfree(all_strbuff); } static void run_nonsync_rawcap_read(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct fts_ts_info *info = container_of(sec, struct fts_ts_info, sec); char buff[SEC_CMD_STR_LEN] = { 0 }; short min = 0x7FFF; short max = 0x8000; sec_cmd_set_default_result(sec); if (info->fts_power_state == FTS_POWER_STATE_POWERDOWN) { input_err(true, &info->client->dev, "%s: [ERROR] Touch is stopped\n", __func__); snprintf(buff, sizeof(buff), "NG"); sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); if (sec->cmd_all_factory_state == SEC_CMD_STATUS_RUNNING) sec_cmd_set_cmd_result_all(sec, buff, strnlen(buff, sizeof(buff)), "RAW_DATA"); sec->cmd_state = SEC_CMD_STATUS_FAIL; return; } input_raw_info_d(true, &info->client->dev, "%s\n", __func__); fts_read_nonsync_frame(info, &min, &max); snprintf(buff, sizeof(buff), "%d,%d", min, max); sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); if (sec->cmd_all_factory_state == SEC_CMD_STATUS_RUNNING) sec_cmd_set_cmd_result_all(sec, buff, strnlen(buff, sizeof(buff)), "RAW_DATA"); sec->cmd_state = SEC_CMD_STATUS_OK; input_info(true, &info->client->dev, "%s: %s\n", __func__, buff); } static void run_nonsync_rawcap_read_all(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct fts_ts_info *info = container_of(sec, struct fts_ts_info, sec); char buff[SEC_CMD_STR_LEN] = { 0 }; short min = 0x7FFF; short max = 0x8000; char *all_strbuff; int i, j; sec_cmd_set_default_result(sec); if (info->fts_power_state == FTS_POWER_STATE_POWERDOWN) { input_err(true, &info->client->dev, "%s: [ERROR] Touch is stopped\n", __func__); snprintf(buff, sizeof(buff), "NG"); sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); sec->cmd_state = SEC_CMD_STATUS_FAIL; return; } all_strbuff = kzalloc(info->ForceChannelLength * info->SenseChannelLength * 7 + 1, GFP_KERNEL); if (!all_strbuff) { snprintf(buff, sizeof(buff), "NG"); sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); sec->cmd_state = SEC_CMD_STATUS_FAIL; return; } // enter_factory_mode(info, true); // fts_read_frame(info, TYPE_RAW_DATA, &min, &max); input_raw_info_d(true, &info->client->dev, "%s\n", __func__); fts_read_nonsync_frame(info, &min, &max); for (j = 0; j < info->ForceChannelLength; j++) { for (i = 0; i < info->SenseChannelLength; i++) { snprintf(buff, sizeof(buff), "%d,", info->pFrame[j * info->SenseChannelLength + i]); strlcat(all_strbuff, buff, info->ForceChannelLength * info->SenseChannelLength * 7); } } enter_factory_mode(info, false); sec->cmd_state = SEC_CMD_STATUS_OK; sec_cmd_set_cmd_result(sec, all_strbuff, strlen(all_strbuff)); input_info(true, &info->client->dev, "%s: %ld\n", __func__, strlen(all_strbuff)); kfree(all_strbuff); } static void get_rawcap(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct fts_ts_info *info = container_of(sec, struct fts_ts_info, sec); char buff[SEC_CMD_STR_LEN] = { 0 }; short val = 0; int node = 0; sec_cmd_set_default_result(sec); if (info->fts_power_state == FTS_POWER_STATE_POWERDOWN) { input_err(true, &info->client->dev, "%s: [ERROR] Touch is stopped\n", __func__); snprintf(buff, sizeof(buff), "NG"); sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); sec->cmd_state = SEC_CMD_STATUS_FAIL; return; } node = fts_check_index(info); if (node < 0) return; val = info->pFrame[node]; snprintf(buff, sizeof(buff), "%d", val); sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); sec->cmd_state = SEC_CMD_STATUS_OK; input_info(true, &info->client->dev, "%s: %s\n", __func__, buff); } #if 0 static void get_rawcap_gap_data(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct fts_ts_info *info = container_of(sec, struct fts_ts_info, sec); char buff[SEC_CMD_STR_LEN] = { 0 }; int rx_max = 0, tx_max = 0, ii; for (ii = 0; ii < (info->SenseChannelLength * info->ForceChannelLength); ii++) { /* rx(x) rawcap gap max */ if ((ii + 1) % (info->SenseChannelLength) != 0) rx_max = max(rx_max, (int)abs(info->pFrame[ii + 1] - info->pFrame[ii])); /* tx(y) rawcap gap max */ if (ii < (info->ForceChannelLength - 1) * info->SenseChannelLength) tx_max = max(tx_max, (int)abs(info->pFrame[ii + info->SenseChannelLength] - info->pFrame[ii])); } input_raw_info_d(true, &info->client->dev, "%s: rx max:%d, tx max:%d\n", __func__, rx_max, tx_max); if (sec->cmd_all_factory_state == SEC_CMD_STATUS_RUNNING) { snprintf(buff, sizeof(buff), "%d,%d", 0, rx_max); sec_cmd_set_cmd_result_all(sec, buff, SEC_CMD_STR_LEN, "RAW_DATA_GAP_RX"); snprintf(buff, sizeof(buff), "%d,%d", 0, tx_max); sec_cmd_set_cmd_result_all(sec, buff, SEC_CMD_STR_LEN, "RAW_DATA_GAP_TX"); } } #endif static void run_lp_single_ended_rawcap_read(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct fts_ts_info *info = container_of(sec, struct fts_ts_info, sec); char buff[SEC_CMD_STR_LEN] = { 0 }; u8 regaddr[4] = { 0xA4, 0x0A, 0x01, 0x00 }; int ret; short min = 0x7FFF; short max = 0x8000; sec_cmd_set_default_result(sec); if (info->fts_power_state == FTS_POWER_STATE_POWERDOWN) { input_err(true, &info->client->dev, "%s: [ERROR] Touch is stopped\n", __func__); snprintf(buff, sizeof(buff), "NG"); sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); sec->cmd_state = SEC_CMD_STATUS_FAIL; return; } info->fts_systemreset(info, 0); fts_interrupt_set(info, INT_DISABLE); /* Request to Prepare single ended raw data from flash */ ret = fts_fw_wait_for_echo_event(info, regaddr, 4, 0); if (ret < 0) { input_err(true, &info->client->dev, "%s: timeout, ret: %d\n", __func__, ret); goto out; } // run_nonsync_rawcap_read(sec); input_raw_info_d(true, &info->client->dev, "%s\n", __func__); fts_read_nonsync_frame(info, &min, &max); fts_interrupt_set(info, INT_ENABLE); fts_set_scanmode(info, info->scan_mode); snprintf(buff, sizeof(buff), "%d,%d", min, max); sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); if (sec->cmd_all_factory_state == SEC_CMD_STATUS_RUNNING) sec_cmd_set_cmd_result_all(sec, buff, strnlen(buff, sizeof(buff)), "MUTUAL_RAW"); sec->cmd_state = SEC_CMD_STATUS_OK; input_info(true, &info->client->dev, "%s: %s\n", __func__, buff); return; out: fts_interrupt_set(info, INT_ENABLE); fts_set_scanmode(info, info->scan_mode); snprintf(buff, sizeof(buff), "NG"); sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); if (sec->cmd_all_factory_state == SEC_CMD_STATUS_RUNNING) sec_cmd_set_cmd_result_all(sec, buff, strnlen(buff, sizeof(buff)), "MUTUAL_RAW"); sec->cmd_state = SEC_CMD_STATUS_FAIL; input_info(true, &info->client->dev, "%s: fail : %s\n", __func__, buff); return; } static void run_lp_single_ended_rawcap_read_all(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct fts_ts_info *info = container_of(sec, struct fts_ts_info, sec); char buff[SEC_CMD_STR_LEN] = { 0 }; u8 regaddr[4] = { 0xA4, 0x0A, 0x01, 0x00 }; int ret; sec_cmd_set_default_result(sec); if (info->fts_power_state == FTS_POWER_STATE_POWERDOWN) { input_err(true, &info->client->dev, "%s: [ERROR] Touch is stopped\n", __func__); snprintf(buff, sizeof(buff), "NG"); sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); sec->cmd_state = SEC_CMD_STATUS_FAIL; return; } input_raw_info_d(true, &info->client->dev, "%s\n", __func__); enter_factory_mode(info, true); fts_set_scanmode(info, FTS_SCAN_MODE_SCAN_OFF); fts_delay(30); fts_interrupt_set(info, INT_DISABLE); /* Request to Prepare single ended raw data from flash */ ret = fts_fw_wait_for_echo_event(info, regaddr, 4, 0); if (ret < 0) { input_err(true, &info->client->dev, "%s: timeout, ret: %d\n", __func__, ret); goto out; } fts_interrupt_set(info, INT_ENABLE); // run_rawcap_read_all(sec); run_nonsync_rawcap_read_all(sec); // enter_factory_mode(info, false); fts_set_scanmode(info, info->scan_mode); return; out: fts_interrupt_set(info, INT_ENABLE); // enter_factory_mode(info, false); fts_set_scanmode(info, info->scan_mode); snprintf(buff, sizeof(buff), "NG"); sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); sec->cmd_state = SEC_CMD_STATUS_FAIL; } // Micro Short Test static void run_low_frequency_rawcap_read(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct fts_ts_info *info = container_of(sec, struct fts_ts_info, sec); char buff[SEC_CMD_STR_LEN] = { 0 }; u8 regAdd[4] = { 0xA4, 0x04, 0x00, 0xC0 }; int ret; sec_cmd_set_default_result(sec); if (info->fts_power_state == FTS_POWER_STATE_POWERDOWN) { input_err(true, &info->client->dev, "%s: [ERROR] Touch is stopped\n", __func__); snprintf(buff, sizeof(buff), "NG"); sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); sec->cmd_state = SEC_CMD_STATUS_FAIL; return; } fts_set_scanmode(info, FTS_SCAN_MODE_SCAN_OFF); fts_delay(30); fts_interrupt_set(info, INT_DISABLE); /* Request to Prepare Hight Frequency(ITO) raw data from flash */ ret = fts_fw_wait_for_echo_event(info, regAdd, 4, 30); if (ret < 0) { input_err(true, &info->client->dev, "%s: timeout, ret: %d\n", __func__, ret); goto out; } fts_interrupt_set(info, INT_ENABLE); input_raw_info_d(true, &info->client->dev, "%s\n", __func__); run_nonsync_rawcap_read(sec); fts_set_scanmode(info, info->scan_mode); return; out: fts_interrupt_set(info, INT_ENABLE); fts_set_scanmode(info, info->scan_mode); snprintf(buff, sizeof(buff), "NG"); sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); sec->cmd_state = SEC_CMD_STATUS_FAIL; } static void run_low_frequency_rawcap_read_all(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct fts_ts_info *info = container_of(sec, struct fts_ts_info, sec); char buff[SEC_CMD_STR_LEN] = { 0 }; u8 regAdd[4] = { 0xA4, 0x04, 0x00, 0xC0 }; int ret; sec_cmd_set_default_result(sec); if (info->fts_power_state == FTS_POWER_STATE_POWERDOWN) { input_err(true, &info->client->dev, "%s: [ERROR] Touch is stopped\n", __func__); snprintf(buff, sizeof(buff), "NG"); sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); sec->cmd_state = SEC_CMD_STATUS_FAIL; return; } input_raw_info_d(true, &info->client->dev, "%s\n", __func__); enter_factory_mode(info, true); fts_set_scanmode(info, FTS_SCAN_MODE_SCAN_OFF); fts_delay(30); fts_interrupt_set(info, INT_DISABLE); /* Request to Prepare Hight Frequency(ITO) raw data from flash */ ret = fts_fw_wait_for_echo_event(info, regAdd, 4, 30); if (ret < 0) { input_err(true, &info->client->dev, "%s: timeout, ret: %d\n", __func__, ret); goto out; } fts_interrupt_set(info, INT_ENABLE); // run_rawcap_read_all(sec); run_nonsync_rawcap_read_all(sec); return; out: fts_interrupt_set(info, INT_ENABLE); fts_set_scanmode(info, info->scan_mode); snprintf(buff, sizeof(buff), "NG"); sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); sec->cmd_state = SEC_CMD_STATUS_FAIL; } static void run_high_frequency_rawcap_read(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct fts_ts_info *info = container_of(sec, struct fts_ts_info, sec); char buff[SEC_CMD_STR_LEN] = { 0 }; u8 regAdd[4] = { 0xA4, 0x04, 0xFF, 0x01 }; int ret; int i, j; sec_cmd_set_default_result(sec); if (info->fts_power_state == FTS_POWER_STATE_POWERDOWN) { input_err(true, &info->client->dev, "%s: [ERROR] Touch is stopped\n", __func__); snprintf(buff, sizeof(buff), "NG"); sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); sec->cmd_state = SEC_CMD_STATUS_FAIL; return; } fts_set_scanmode(info, FTS_SCAN_MODE_SCAN_OFF); fts_delay(30); fts_interrupt_set(info, INT_DISABLE); /* Request to Prepare Hight Frequency(ITO) raw data from flash */ ret = fts_fw_wait_for_echo_event(info, regAdd, 4, 100); if (ret < 0) { input_err(true, &info->client->dev, "%s: timeout, ret: %d\n", __func__, ret); goto out; } fts_interrupt_set(info, INT_ENABLE); input_raw_info_d(true, &info->client->dev, "%s\n", __func__); run_nonsync_rawcap_read(sec); fts_set_scanmode(info, info->scan_mode); pr_info("sec_input: %s - correlation\n", __func__); for (i = 0; i < info->ForceChannelLength; i++) { pr_info("sec_input: [%2d] ", i); for (j = 0; j < info->SenseChannelLength; j++) pr_cont("%d, ", info->pFrame[(i * info->SenseChannelLength) + j]); pr_cont("\n"); } return; out: fts_interrupt_set(info, INT_ENABLE); fts_set_scanmode(info, info->scan_mode); snprintf(buff, sizeof(buff), "NG"); sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); sec->cmd_state = SEC_CMD_STATUS_FAIL; } static void run_high_frequency_rawcap_read_all(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct fts_ts_info *info = container_of(sec, struct fts_ts_info, sec); char buff[SEC_CMD_STR_LEN] = { 0 }; u8 regAdd[4] = { 0xA4, 0x04, 0xFF, 0x01 }; int ret; int i, j; sec_cmd_set_default_result(sec); if (info->fts_power_state == FTS_POWER_STATE_POWERDOWN) { input_err(true, &info->client->dev, "%s: [ERROR] Touch is stopped\n", __func__); snprintf(buff, sizeof(buff), "NG"); sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); sec->cmd_state = SEC_CMD_STATUS_FAIL; return; } input_raw_info_d(true, &info->client->dev, "%s\n", __func__); enter_factory_mode(info, true); fts_set_scanmode(info, FTS_SCAN_MODE_SCAN_OFF); fts_delay(30); fts_interrupt_set(info, INT_DISABLE); /* Request to Prepare Hight Frequency(ITO) raw data from flash */ ret = fts_fw_wait_for_echo_event(info, regAdd, 4, 100); if (ret < 0) { input_err(true, &info->client->dev, "%s: timeout, ret: %d\n", __func__, ret); goto out; } fts_interrupt_set(info, INT_ENABLE); // run_rawcap_read_all(sec); run_nonsync_rawcap_read_all(sec); fts_set_scanmode(info, info->scan_mode); pr_info("sec_input: %s - correlation\n", __func__); for (i = 0; i < info->ForceChannelLength; i++) { pr_info("sec_input: [%2d] ", i); for (j = 0; j < info->SenseChannelLength; j++) pr_cont("%d, ", info->pFrame[(i * info->SenseChannelLength) + j]); pr_cont("\n"); } return; out: fts_set_scanmode(info, info->scan_mode); snprintf(buff, sizeof(buff), "NG"); sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); sec->cmd_state = SEC_CMD_STATUS_FAIL; } static void run_delta_read(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct fts_ts_info *info = container_of(sec, struct fts_ts_info, sec); char buff[SEC_CMD_STR_LEN] = { 0 }; short min = 0x7FFF; short max = 0x8000; sec_cmd_set_default_result(sec); if (info->fts_power_state == FTS_POWER_STATE_POWERDOWN) { input_err(true, &info->client->dev, "%s: [ERROR] Touch is stopped\n", __func__); snprintf(buff, sizeof(buff), "NG"); sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); sec->cmd_state = SEC_CMD_STATUS_FAIL; return; } fts_read_frame(info, TYPE_STRENGTH_DATA, &min, &max); snprintf(buff, sizeof(buff), "%d,%d", min, max); sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); sec->cmd_state = SEC_CMD_STATUS_OK; input_info(true, &info->client->dev, "%s: %s\n", __func__, buff); } static void run_prox_intensity_read_all(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct fts_ts_info *info = container_of(sec, struct fts_ts_info, sec); char buff[SEC_CMD_STR_LEN] = { 0 }; int ret; u8 reg[2]; u8 thd_data[4]; u8 sum_data[4]; sec_cmd_set_default_result(sec); if (info->fts_power_state == FTS_POWER_STATE_POWERDOWN) { input_err(true, &info->client->dev, "%s: [ERROR] Touch is stopped\n", __func__); snprintf(buff, sizeof(buff), "NG"); sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); sec->cmd_state = SEC_CMD_STATUS_FAIL; return; } memset(thd_data, 0x00, 4); memset(sum_data, 0x00, 4); /* Threshold */ reg[0] = 0xC7; reg[1] = 0x0C; ret = info->fts_read_reg(info, ®[0], 2, &thd_data[0], 4); if (ret < 0) { input_err(true, &info->client->dev, "%s: failed to read thd_data\n", __func__); snprintf(buff, sizeof(buff), "NG"); sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); sec->cmd_state = SEC_CMD_STATUS_FAIL; return; } /* Sum */ reg[0] = 0xC7; reg[1] = 0x0D; ret = info->fts_read_reg(info, ®[0], 2, &sum_data[0], 4); if (ret < 0) { input_err(true, &info->client->dev, "%s: failed to read sum_data\n", __func__); snprintf(buff, sizeof(buff), "NG"); sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); sec->cmd_state = SEC_CMD_STATUS_FAIL; return; } snprintf(buff, sizeof(buff), "SUM_X:%d THD_X:%d SUM_Y:%d THD_Y:%d", (sum_data[0] << 8) + sum_data[1], (sum_data[2] << 8) + sum_data[3], (thd_data[0] << 8) + thd_data[1], (thd_data[2] << 8) + thd_data[3]); sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); sec->cmd_state = SEC_CMD_STATUS_OK; input_info(true, &info->client->dev, "%s: %s\n", __func__, buff); } static void get_strength_all_data(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct fts_ts_info *info = container_of(sec, struct fts_ts_info, sec); char buff[SEC_CMD_STR_LEN] = { 0 }; short min = 0x7FFF; short max = 0x8000; char *all_strbuff; int i, j; sec_cmd_set_default_result(sec); if (info->fts_power_state == FTS_POWER_STATE_POWERDOWN) { input_err(true, &info->client->dev, "%s: [ERROR] Touch is stopped\n", __func__); snprintf(buff, sizeof(buff), "NG"); sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); sec->cmd_state = SEC_CMD_STATUS_FAIL; return; } all_strbuff = kzalloc(info->ForceChannelLength * info->SenseChannelLength * 7 + 1, GFP_KERNEL); if (!all_strbuff) { input_err(true, &info->client->dev, "%s: alloc failed\n", __func__); snprintf(buff, sizeof(buff), "NG"); sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); sec->cmd_state = SEC_CMD_STATUS_FAIL; return; } fts_read_frame(info, TYPE_STRENGTH_DATA, &min, &max); for (i = 0; i < info->ForceChannelLength; i++) { for (j = 0; j < info->SenseChannelLength; j++) { snprintf(buff, sizeof(buff), "%d,", info->pFrame[(i * info->SenseChannelLength) + j]); strlcat(all_strbuff, buff, info->ForceChannelLength * info->SenseChannelLength * 7); } } sec->cmd_state = SEC_CMD_STATUS_OK; sec_cmd_set_cmd_result(sec, all_strbuff, strlen(all_strbuff)); input_info(true, &info->client->dev, "%s: %ld\n", __func__, strlen(all_strbuff)); kfree(all_strbuff); } static void get_delta(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct fts_ts_info *info = container_of(sec, struct fts_ts_info, sec); char buff[SEC_CMD_STR_LEN] = { 0 }; short val = 0; int node = 0; sec_cmd_set_default_result(sec); if (info->fts_power_state == FTS_POWER_STATE_POWERDOWN) { input_err(true, &info->client->dev, "%s: [ERROR] Touch is stopped\n", __func__); snprintf(buff, sizeof(buff), "NG"); sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); sec->cmd_state = SEC_CMD_STATUS_FAIL; return; } node = fts_check_index(info); if (node < 0) return; val = info->pFrame[node]; snprintf(buff, sizeof(buff), "%d", val); sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); sec->cmd_state = SEC_CMD_STATUS_OK; input_info(true, &info->client->dev, "%s: %s\n", __func__, buff); } int fts_get_hf_data(struct fts_ts_info *info) { u8 regAdd[4] = { 0 }; int ret; short min = 0x7FFF; short max = 0x8000; info->fts_systemreset(info, 0); fts_command(info, FTS_CMD_CLEAR_ALL_EVENT, true); fts_release_all_finger(info); fts_interrupt_set(info, INT_DISABLE); input_info(true, &info->client->dev, "%s\n", __func__); regAdd[0] = 0xA4; regAdd[1] = 0x04; regAdd[2] = 0xFF; regAdd[3] = 0x01; ret = fts_fw_wait_for_echo_event(info, ®Add[0], 4, 100); if (ret < 0) goto out; ret = fts_read_frame(info, TYPE_RAW_DATA, &min, &max); if (ret < 0) input_err(true, &info->client->dev, "%s: failed to get rawdata\n", __func__); out: info->fts_systemreset(info, 0); fts_set_cover_type(info, info->flip_enable); fts_delay(10); if (info->charger_mode) { fts_wirelesscharger_mode(info); fts_delay(10); } if (!info->flip_enable) fts_set_scanmode(info, info->scan_mode); else fts_set_scanmode(info, FTS_SCAN_MODE_SCAN_OFF); return ret; } static void run_rawdata_read_all(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct fts_ts_info *info = container_of(sec, struct fts_ts_info, sec); char buff[SEC_CMD_STR_LEN] = { 0 }; #ifdef CONFIG_TOUCHSCREEN_DUAL_FOLDABLE input_raw_data_clear(MAIN_TOUCH); #endif info->rawdata_read_lock = true; input_raw_info_d(true, &info->client->dev, "%s: start (noise:%d, wet:%d, tc:%d, folding:%s)##\n", __func__, info->touch_noise_status, info->wet_mode, info->touch_count, info->flip_status_current ? "close" : "open"); run_rawcap_read(sec); run_self_raw_read(sec); fts_checking_miscal(info); run_cx_data_read(sec); run_ix_data_read(sec); fts_panel_ito_test(info, OPEN_SHORT_CRACK_TEST); fts_get_hf_data(info); run_mutual_jitter(sec); info->rawdata_read_lock = false; snprintf(buff, sizeof(buff), "OK"); sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); sec->cmd_state = SEC_CMD_STATUS_OK; input_raw_info_d(true, &info->client->dev, "%s: %s\n", __func__, buff); } void fts_run_rawdata_read_all(struct fts_ts_info *info) { struct sec_cmd_data *sec = &info->sec; run_rawdata_read_all(sec); } #ifdef TCLM_CONCEPT static void get_pat_information(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct fts_ts_info *info = container_of(sec, struct fts_ts_info, sec); char buff[50] = { 0 }; sec_cmd_set_default_result(sec); #ifdef CONFIG_SEC_FACTORY if (info->factory_position == 1) { sec_tclm_initialize(info->tdata); fts_tclm_data_read(info->client, SEC_TCLM_NVM_ALL_DATA); } #endif /* fixed tune version will be saved at excute autotune */ snprintf(buff, sizeof(buff), "C%02XT%04X.%4s%s%c%d%c%d%c%d", info->tdata->nvdata.cal_count, info->tdata->nvdata.tune_fix_ver, info->tdata->tclm_string[info->tdata->nvdata.cal_position].f_name, (info->tdata->tclm_level == TCLM_LEVEL_LOCKDOWN) ? ".L " : " ", info->tdata->cal_pos_hist_last3[0], info->tdata->cal_pos_hist_last3[1], info->tdata->cal_pos_hist_last3[2], info->tdata->cal_pos_hist_last3[3], info->tdata->cal_pos_hist_last3[4], info->tdata->cal_pos_hist_last3[5]); sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); sec->cmd_state = SEC_CMD_STATUS_OK; input_info(true, &info->client->dev, "%s: %s\n", __func__, buff); } static void set_external_factory(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct fts_ts_info *info = container_of(sec, struct fts_ts_info, sec); char buff[SEC_CMD_STR_LEN] = { 0 }; sec_cmd_set_default_result(sec); info->tdata->external_factory = true; snprintf(buff, sizeof(buff), "OK"); sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); sec->cmd_state = SEC_CMD_STATUS_OK; input_info(true, &info->client->dev, "%s: %s\n", __func__, buff); } #endif static void fts_read_ix_data(struct fts_ts_info *info, bool allnode) { struct sec_cmd_data *sec = &info->sec; char buff[SEC_CMD_STR_LEN] = { 0 }; int rc; u16 max_tx_ix_sum = 0; u16 min_tx_ix_sum = 0xFFFF; u16 max_rx_ix_sum = 0; u16 min_rx_ix_sum = 0xFFFF; u8 *data; u8 regAdd[FTS_EVENT_SIZE]; u8 dataID; u16 force_ix_data[100]; u16 sense_ix_data[100]; int buff_size, j; char *mbuff = NULL; int num, n, a, fzero; char cnum; int i = 0; u16 comp_start_tx_addr, comp_start_rx_addr; unsigned int rx_num, tx_num; data = kzalloc((info->ForceChannelLength + info->SenseChannelLength) * 2 + 1, GFP_KERNEL); if (!data) return; sec_cmd_set_default_result(sec); if (info->fts_power_state == FTS_POWER_STATE_POWERDOWN) { input_err(true, &info->client->dev, "%s: [ERROR] Touch is stopped\n", __func__); snprintf(buff, sizeof(buff), "NG"); sec->cmd_state = SEC_CMD_STATUS_FAIL; goto out; } info->fts_command(info, FTS_CMD_CLEAR_ALL_EVENT, true); // Clear FIFO fts_release_all_finger(info); fts_interrupt_set(info, INT_DISABLE); // Request compensation data type dataID = 0x52; regAdd[0] = 0xA4; regAdd[1] = 0x06; regAdd[2] = dataID; // SS - CX total rc = fts_fw_wait_for_echo_event(info, ®Add[0], 3, 0); if (rc < 0) { input_err(true, &info->client->dev, "%s: failed to request data\n", __func__); snprintf(buff, sizeof(buff), "NG"); sec->cmd_state = SEC_CMD_STATUS_FAIL; fts_interrupt_set(info, INT_ENABLE); goto out; } fts_interrupt_set(info, INT_ENABLE); // Read Header regAdd[0] = 0xA6; regAdd[1] = 0x00; regAdd[2] = 0x00; rc = info->fts_read_reg(info, ®Add[0], 3, &data[0], FTS_COMP_DATA_HEADER_SIZE); if (rc < 0) { input_err(true, &info->client->dev, "%s: failed to read header\n", __func__); snprintf(buff, sizeof(buff), "NG"); sec->cmd_state = SEC_CMD_STATUS_FAIL; goto out; } if ((data[0] != 0xA5) && (data[1] != dataID)) { input_err(true, &info->client->dev, "%s: header mismatch\n", __func__); snprintf(buff, sizeof(buff), "NG"); sec->cmd_state = SEC_CMD_STATUS_FAIL; goto out; } tx_num = data[4]; rx_num = data[5]; /* Read TX IX data */ comp_start_tx_addr = (u16)FTS_COMP_DATA_HEADER_SIZE; regAdd[0] = 0xA6; regAdd[1] = (u8)(comp_start_tx_addr >> 8); regAdd[2] = (u8)(comp_start_tx_addr & 0xFF); rc = info->fts_read_reg(info, ®Add[0], 3, &data[0], tx_num * 2); if (rc < 0) { input_err(true, &info->client->dev, "%s: failed to read TX IX data\n", __func__); snprintf(buff, sizeof(buff), "NG"); sec->cmd_state = SEC_CMD_STATUS_FAIL; goto out; } for (i = 0; i < tx_num; i++) { force_ix_data[i] = data[2 * i] | data[2 * i + 1] << 8; if (max_tx_ix_sum < force_ix_data[i]) max_tx_ix_sum = force_ix_data[i]; if (min_tx_ix_sum > force_ix_data[i]) min_tx_ix_sum = force_ix_data[i]; } /* Read RX IX data */ comp_start_rx_addr = (u16)(FTS_COMP_DATA_HEADER_SIZE + (tx_num * 2)); regAdd[0] = 0xA6; regAdd[1] = (u8)(comp_start_rx_addr >> 8); regAdd[2] = (u8)(comp_start_rx_addr & 0xFF); rc = info->fts_read_reg(info, ®Add[0], 3, &data[0], rx_num * 2); if (rc < 0) { input_err(true, &info->client->dev, "%s: failed to read RX IX\n", __func__); snprintf(buff, sizeof(buff), "NG"); sec->cmd_state = SEC_CMD_STATUS_FAIL; goto out; } for (i = 0; i < rx_num; i++) { sense_ix_data[i] = data[2 * i] | data[2 * i + 1] << 8; if (max_rx_ix_sum < sense_ix_data[i]) max_rx_ix_sum = sense_ix_data[i]; if (min_rx_ix_sum > sense_ix_data[i]) min_rx_ix_sum = sense_ix_data[i]; } fts_print_channel(info, force_ix_data, sense_ix_data); input_raw_info_d(true, &info->client->dev, "%s: MIN_TX_IX_SUM : %d MAX_TX_IX_SUM : %d\n", __func__, min_tx_ix_sum, max_tx_ix_sum); input_raw_info_d(true, &info->client->dev, "%s: MIN_RX_IX_SUM : %d MAX_RX_IX_SUM : %d\n", __func__, min_rx_ix_sum, max_rx_ix_sum); if (allnode == true) { buff_size = (info->ForceChannelLength + info->SenseChannelLength + 2) * 5; mbuff = kzalloc(buff_size, GFP_KERNEL); } if (mbuff != NULL) { char *pBuf = mbuff; for (i = 0; i < info->ForceChannelLength; i++) { num = force_ix_data[i]; n = 100000; fzero = 0; for (j = 5; j > 0; j--) { n = n / 10; a = num / n; if (a) fzero = 1; cnum = a + '0'; num = num - a*n; if (fzero) *pBuf++ = cnum; } if (!fzero) *pBuf++ = '0'; *pBuf++ = ','; } for (i = 0; i < info->SenseChannelLength; i++) { num = sense_ix_data[i]; n = 100000; fzero = 0; for (j = 5; j > 0; j--) { n = n / 10; a = num / n; if (a) fzero = 1; cnum = a + '0'; num = num - a * n; if (fzero) *pBuf++ = cnum; } if (!fzero) *pBuf++ = '0'; if (i < (info->SenseChannelLength - 1)) *pBuf++ = ','; } sec_cmd_set_cmd_result(sec, mbuff, buff_size); sec->cmd_state = SEC_CMD_STATUS_OK; kfree(mbuff); return; } if (allnode == true) { snprintf(buff, sizeof(buff), "NG"); sec->cmd_state = SEC_CMD_STATUS_FAIL; } else { snprintf(buff, sizeof(buff), "%d,%d,%d,%d", min_tx_ix_sum, max_tx_ix_sum, min_rx_ix_sum, max_rx_ix_sum); sec->cmd_state = SEC_CMD_STATUS_OK; } out: kfree(data); if (sec->cmd_all_factory_state == SEC_CMD_STATUS_RUNNING) { char ret_buff[SEC_CMD_STR_LEN] = { 0 }; snprintf(ret_buff, sizeof(ret_buff), "%d,%d", min_rx_ix_sum, max_rx_ix_sum); sec_cmd_set_cmd_result_all(sec, ret_buff, strnlen(ret_buff, sizeof(ret_buff)), "IX_DATA_X"); snprintf(ret_buff, sizeof(ret_buff), "%d,%d", min_tx_ix_sum, max_tx_ix_sum); sec_cmd_set_cmd_result_all(sec, ret_buff, strnlen(ret_buff, sizeof(ret_buff)), "IX_DATA_Y"); } sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); input_info(true, &info->client->dev, "%s: %s\n", __func__, buff); } static void run_ix_data_read(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct fts_ts_info *info = container_of(sec, struct fts_ts_info, sec); sec_cmd_set_default_result(sec); input_raw_info_d(true, &info->client->dev, "%s\n", __func__); fts_read_ix_data(info, false); } static void run_ix_data_read_all(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct fts_ts_info *info = container_of(sec, struct fts_ts_info, sec); sec_cmd_set_default_result(sec); enter_factory_mode(info, true); fts_read_ix_data(info, true); enter_factory_mode(info, false); } static void fts_read_self_raw_frame(struct fts_ts_info *info, bool allnode) { struct sec_cmd_data *sec = &info->sec; char buff[SEC_CMD_STR_LEN] = { 0 }; struct FTS_SyncFrameHeader *pSyncFrameHeader; u8 regAdd[FTS_EVENT_SIZE] = {0}; u8 *data; s16 self_force_raw_data[100]; s16 self_sense_raw_data[100]; int Offset = 0; u8 count = 0; int i; int ret; int totalbytes; int retry = 10; s16 min_tx_self_raw_data = S16_MAX; s16 max_tx_self_raw_data = S16_MIN; s16 min_rx_self_raw_data = S16_MAX; s16 max_rx_self_raw_data = S16_MIN; data = kzalloc((info->ForceChannelLength + info->SenseChannelLength) * 2 + 1, GFP_KERNEL); if (!data) return; if (info->fts_power_state == FTS_POWER_STATE_POWERDOWN) { input_err(true, &info->client->dev, "%s: [ERROR] Touch is stopped\n", __func__); snprintf(buff, sizeof(buff), "NG"); sec->cmd_state = SEC_CMD_STATUS_FAIL; goto out; } // Request Data Type regAdd[0] = 0xA4; regAdd[1] = 0x06; regAdd[2] = TYPE_RAW_DATA; info->fts_write_reg(info, ®Add[0], 3); do { regAdd[0] = 0xA6; regAdd[1] = 0x00; regAdd[2] = 0x00; ret = info->fts_read_reg(info, ®Add[0], 3, &data[0], FTS_COMP_DATA_HEADER_SIZE); if (ret <= 0) { input_err(true, &info->client->dev, "%s: read failed rc = %d\n", __func__, ret); snprintf(buff, sizeof(buff), "NG"); sec->cmd_state = SEC_CMD_STATUS_FAIL; goto out; } pSyncFrameHeader = (struct FTS_SyncFrameHeader *) &data[0]; if ((pSyncFrameHeader->header == 0xA5) && (pSyncFrameHeader->host_data_mem_id == TYPE_RAW_DATA)) break; fts_delay(100); } while (retry--); if (retry == 0) { input_err(true, &info->client->dev, "%s: didn't match header or id. header = %02X, id = %02X\n", __func__, pSyncFrameHeader->header, pSyncFrameHeader->host_data_mem_id); snprintf(buff, sizeof(buff), "NG"); sec->cmd_state = SEC_CMD_STATUS_FAIL; goto out; } Offset = FTS_COMP_DATA_HEADER_SIZE + pSyncFrameHeader->dbg_frm_len + (pSyncFrameHeader->ms_force_len * pSyncFrameHeader->ms_sense_len * 2); totalbytes = (pSyncFrameHeader->ss_force_len + pSyncFrameHeader->ss_sense_len) * 2; regAdd[0] = 0xA6; regAdd[1] = (u8)(Offset >> 8); regAdd[2] = (u8)(Offset & 0xFF); ret = info->fts_read_reg(info, ®Add[0], 3, &data[0], totalbytes); if (ret <= 0) { input_err(true, &info->client->dev, "%s: read failed rc = %d\n", __func__, ret); snprintf(buff, sizeof(buff), "NG"); sec->cmd_state = SEC_CMD_STATUS_FAIL; goto out; } Offset = 0; for (count = 0; count < (info->ForceChannelLength); count++) { self_force_raw_data[count] = (s16)(data[count * 2 + Offset] + (data[count * 2 + 1 + Offset] << 8)); if (max_tx_self_raw_data < self_force_raw_data[count]) max_tx_self_raw_data = self_force_raw_data[count]; if (min_tx_self_raw_data > self_force_raw_data[count]) min_tx_self_raw_data = self_force_raw_data[count]; } Offset = (info->ForceChannelLength * 2); for (count = 0; count < info->SenseChannelLength; count++) { self_sense_raw_data[count] = (s16)(data[count * 2 + Offset] + (data[count * 2 + 1 + Offset] << 8)); if (max_rx_self_raw_data < self_sense_raw_data[count]) max_rx_self_raw_data = self_sense_raw_data[count]; if (min_rx_self_raw_data > self_sense_raw_data[count]) min_rx_self_raw_data = self_sense_raw_data[count]; } fts_print_channel(info, self_force_raw_data, self_sense_raw_data); input_raw_info_d(true, &info->client->dev, "%s: MIN_TX_SELF_RAW: %d MAX_TX_SELF_RAW : %d\n", __func__, (s16)min_tx_self_raw_data, (s16)max_tx_self_raw_data); input_raw_info_d(true, &info->client->dev, "%s: MIN_RX_SELF_RAW : %d MIN_RX_SELF_RAW : %d\n", __func__, (s16)min_rx_self_raw_data, (s16)max_rx_self_raw_data); if (allnode == true) { char *mbuff; char temp[10] = { 0 }; mbuff = kzalloc((info->ForceChannelLength + info->SenseChannelLength + 2) * 10, GFP_KERNEL); if (!mbuff) goto out; for (i = 0; i < (info->ForceChannelLength); i++) { snprintf(temp, sizeof(temp), "%d,", (s16)self_force_raw_data[i]); strlcat(mbuff, temp, sizeof(mbuff)); } for (i = 0; i < (info->SenseChannelLength); i++) { snprintf(temp, sizeof(temp), "%d,", (s16)self_sense_raw_data[i]); strlcat(mbuff, temp, sizeof(mbuff)); } sec_cmd_set_cmd_result(sec, mbuff, sizeof(mbuff)); sec->cmd_state = SEC_CMD_STATUS_OK; kfree(mbuff); return; } snprintf(buff, sizeof(buff), "%d,%d,%d,%d", (s16)min_tx_self_raw_data, (s16)max_tx_self_raw_data, (s16)min_rx_self_raw_data, (s16)max_rx_self_raw_data); sec->cmd_state = SEC_CMD_STATUS_OK; out: kfree(data); if (sec->cmd_all_factory_state == SEC_CMD_STATUS_RUNNING) { char ret_buff[SEC_CMD_STR_LEN] = { 0 }; snprintf(ret_buff, sizeof(ret_buff), "%d,%d", (s16)min_rx_self_raw_data, (s16)max_rx_self_raw_data); sec_cmd_set_cmd_result_all(sec, ret_buff, strnlen(ret_buff, sizeof(ret_buff)), "SELF_RAW_DATA_X"); snprintf(ret_buff, sizeof(ret_buff), "%d,%d", (s16)min_tx_self_raw_data, (s16)max_tx_self_raw_data); sec_cmd_set_cmd_result_all(sec, ret_buff, strnlen(ret_buff, sizeof(ret_buff)), "SELF_RAW_DATA_Y"); } sec_cmd_set_cmd_result(sec, &buff[0], strnlen(buff, sizeof(buff))); input_info(true, &info->client->dev, "%s: %s\n", __func__, buff); } static void run_self_raw_read(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct fts_ts_info *info = container_of(sec, struct fts_ts_info, sec); sec_cmd_set_default_result(sec); input_raw_info_d(true, &info->client->dev, "%s\n", __func__); fts_read_self_raw_frame(info, false); } static void run_self_raw_read_all(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct fts_ts_info *info = container_of(sec, struct fts_ts_info, sec); sec_cmd_set_default_result(sec); enter_factory_mode(info, true); fts_read_self_raw_frame(info, true); enter_factory_mode(info, false); } static void run_factory_miscalibration(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct fts_ts_info *info = container_of(sec, struct fts_ts_info, sec); char buff[SEC_CMD_STR_LEN]; char data[FTS_EVENT_SIZE]; char echo; int ret; int retry = 200; short min, max; sec_cmd_set_default_result(sec); fts_interrupt_set(info, INT_DISABLE); memset(data, 0x00, sizeof(data)); memset(buff, 0x00, sizeof(buff)); data[0] = 0xC7; data[1] = 0x02; ret = info->fts_write_reg(info, data, 2); if (ret < 0) { input_err(true, &info->client->dev, "%s: write failed: %d\n", __func__, ret); goto error; } /* maximum timeout 2sec ? */ while (retry-- >= 0) { memset(data, 0x00, sizeof(data)); echo = FTS_READ_ONE_EVENT; ret = info->fts_read_reg(info, &echo, 1, data, FTS_EVENT_SIZE); if (ret < 0) { input_err(true, &info->client->dev, "%s: read failed: %d\n", __func__, ret); goto error; } input_info(true, &info->client->dev, "%s: %02X %02X %02X %02X %02X %02X %02X %02X\n", __func__, data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7]); fts_delay(10); if (data[0] == 0x03 || data[0] == 0xF3) { max = data[3] << 8 | data[2]; min = data[5] << 8 | data[4]; break; } if (retry == 0) goto error; } if (sec->cmd_all_factory_state == SEC_CMD_STATUS_RUNNING) { snprintf(buff, sizeof(buff), "%d,%d", min, max); sec_cmd_set_cmd_result_all(sec, buff, strnlen(buff, sizeof(buff)), "MIS_CAL"); } else { if (data[0] == 0x03) { snprintf(buff, sizeof(buff), "OK,%d,%d", min, max); } else { snprintf(buff, sizeof(buff), "NG,%d,%d", min, max); } } sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); sec->cmd_state = SEC_CMD_STATUS_OK; fts_reinit(info, false); fts_interrupt_set(info, INT_ENABLE); return; error: snprintf(buff, sizeof(buff), "NG"); sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); sec->cmd_state = SEC_CMD_STATUS_FAIL; fts_reinit(info, false); fts_interrupt_set(info, INT_ENABLE); } static void run_miscalibration(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct fts_ts_info *info = container_of(sec, struct fts_ts_info, sec); char buff[SEC_CMD_STR_LEN]; char data[FTS_EVENT_SIZE]; char echo; int ret; int retry = 200; short min, max; sec_cmd_set_default_result(sec); fts_interrupt_set(info, INT_DISABLE); memset(data, 0x00, sizeof(data)); memset(buff, 0x00, sizeof(buff)); data[0] = 0xA4; data[1] = 0x0B; data[2] = 0x00; data[3] = 0xC0; ret = info->fts_write_reg(info, data, 4); if (ret < 0) { input_err(true, &info->client->dev, "%s: write failed: %d\n", __func__, ret); goto error; } /* maximum timeout 2sec ? */ while (retry-- >= 0) { memset(data, 0x00, sizeof(data)); echo = FTS_READ_ONE_EVENT; ret = info->fts_read_reg(info, &echo, 1, data, FTS_EVENT_SIZE); if (ret < 0) { input_err(true, &info->client->dev, "%s: read failed: %d\n", __func__, ret); goto error; } input_info(true, &info->client->dev, "%s: %02X %02X %02X %02X %02X %02X %02X %02X\n", __func__, data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7]); fts_delay(10); if (data[0] == 0x03 || data[0] == 0xF3) { max = data[3] << 8 | data[2]; min = data[5] << 8 | data[4]; break; } if (retry == 0) goto error; } if (data[0] == 0x03) { snprintf(buff, sizeof(buff), "OK,%d,%d", min, max); } else { snprintf(buff, sizeof(buff), "NG,%d,%d", min, max); } sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); sec->cmd_state = SEC_CMD_STATUS_OK; fts_reinit(info, false); fts_interrupt_set(info, INT_ENABLE); return; error: snprintf(buff, sizeof(buff), "NG"); sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); sec->cmd_state = SEC_CMD_STATUS_FAIL; fts_reinit(info, false); fts_interrupt_set(info, INT_ENABLE); } int fts_panel_test_result(struct fts_ts_info *info, int type) { u8 data[FTS_EVENT_SIZE]; u8 cmd = FTS_READ_ONE_EVENT; uint8_t regAdd[4] = { 0 }; bool matched = false; int retry = 0; int i = 0; int result = 0; short temp_min = 32767, temp_max = -32768; bool cheked_short_to_gnd = false; bool cheked_short_to_vdd = false; bool cheked_short = false; bool cheked_open = false; char tempv[25] = {0}; char temph[30] = {0}; struct sec_cmd_data *sec = &info->sec; char buff[SEC_CMD_STR_LEN] = {0}; u8 *result_buff = NULL; int size = 4095; result_buff = kzalloc(size, GFP_KERNEL); if (!result_buff) { input_err(true, &info->client->dev, "%s: result_buff kzalloc fail!\n", __func__); goto alloc_fail; } regAdd[0] = 0xA4; regAdd[1] = 0x04; regAdd[2] = 0xFC; regAdd[3] = 0x09; info->fts_write_reg(info, ®Add[0], 4); fts_delay(100); memset(info->ito_test, 0x0, 4); memset(data, 0x0, FTS_EVENT_SIZE); while (info->fts_read_reg(info, &cmd, 1, (u8 *)data, FTS_EVENT_SIZE)) { memset(tempv, 0x00, 25); memset(temph, 0x00, 30); if ((data[0] == FTS_EVENT_STATUS_REPORT) && (data[1] == 0x01)) { for (i = 0; i < 4; i++) { if (data[i + 2] != regAdd[i]) { matched = false; break; } matched = true; } if (matched == true) break; } else if (data[0] == FTS_EVENT_ERROR_REPORT) { info->ito_test[0] = data[0]; info->ito_test[1] = data[1]; info->ito_test[2] = data[2]; info->ito_test[3] = 0x00; switch (data[1]) { case ITO_FORCE_SHRT_GND: case ITO_SENSE_SHRT_GND: input_info(true, &info->client->dev, "%s: TX/RX_SHORT_TO_GND:%cX[%d]\n", __func__, data[1] == ITO_FORCE_SHRT_VDD ? 'T' : 'R', data[2]); if (type != SHORT_TEST) break; if (!cheked_short_to_gnd) { snprintf(temph, 30, "TX/RX_SHORT_TO_GND:"); strlcat(result_buff, temph, size); cheked_short_to_gnd = true; } snprintf(tempv, sizeof(tempv), "%c%d,", data[1] == ITO_FORCE_SHRT_GND ? 'T' : 'R', data[2]); strlcat(result_buff, tempv, size); result = ITO_FAIL_SHORT; break; case ITO_FORCE_SHRT_VDD: case ITO_SENSE_SHRT_VDD: input_info(true, &info->client->dev, "%s: TX/RX_SHORT_TO_VDD:%cX[%d]\n", __func__, data[1] == ITO_FORCE_SHRT_VDD ? 'T' : 'R', data[2]); if (type != SHORT_TEST) break; if (!cheked_short_to_vdd) { snprintf(temph, 30, "TX/RX_SHORT_TO_VDD:"); strlcat(result_buff, temph, size); cheked_short_to_vdd = true; } snprintf(tempv, sizeof(tempv), "%c%d,", data[1] == ITO_FORCE_SHRT_VDD ? 'T' : 'R', data[2]); strlcat(result_buff, tempv, size); result = -ITO_FAIL_SHORT; break; case ITO_FORCE_SHRT_FORCE: case ITO_SENSE_SHRT_SENSE: input_info(true, &info->client->dev, "%s: TX/RX_SHORT:%cX[%d]\n", __func__, data[1] == ITO_FORCE_SHRT_FORCE ? 'T' : 'R', data[2]); if (type != SHORT_TEST) break; if (!cheked_short) { snprintf(temph, 30, "TX/RX_SHORT:"); strlcat(result_buff, temph, size); cheked_short = true; } snprintf(tempv, sizeof(tempv), "%c%d,", data[1] == ITO_FORCE_SHRT_FORCE ? 'T' : 'R', data[2]); strlcat(result_buff, tempv, size); result = -ITO_FAIL_SHORT; break; case ITO_FORCE_OPEN: case ITO_SENSE_OPEN: input_info(true, &info->client->dev, "%s: TX/RX_OPEN:%cX[%d]\n", __func__, data[1] == ITO_FORCE_OPEN ? 'T' : 'R', data[2]); if (type != OPEN_TEST) break; if (!cheked_open) { snprintf(temph, 30, "TX/RX_OPEN:"); strlcat(result_buff, temph, size); cheked_open = true; } snprintf(tempv, sizeof(tempv), "%c%d,", data[1] == ITO_FORCE_OPEN ? 'T' : 'R', data[2]); strlcat(result_buff, tempv, size); result = -ITO_FAIL_OPEN; break; default: input_info(true, &info->client->dev, "%s: unknown event %02x %02x %02x %02x %02x %02x %02x %02x\n", __func__, data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7]); break; } } if (retry++ > 50) { input_err(true, &info->client->dev, "%s: Time over - wait for result of ITO test\n", __func__); goto test_fail; } fts_delay(20); } /* read rawdata */ // fts_read_frame(info, TYPE_RAW_DATA, &temp_min, &temp_max); input_raw_info_d(true, &info->client->dev, "%s\n", __func__); fts_read_nonsync_frame(info, &temp_min, &temp_max); if (type == OPEN_TEST && result == -ITO_FAIL_OPEN) { snprintf(result_buff, sizeof(result_buff), "NG"); sec_cmd_set_cmd_result(sec, result_buff, strnlen(result_buff, sizeof(result_buff))); sec->cmd_state = SEC_CMD_STATUS_FAIL; } else if (type == SHORT_TEST && result == -ITO_FAIL_SHORT) { snprintf(result_buff, sizeof(result_buff), "NG"); sec_cmd_set_cmd_result(sec, result_buff, strnlen(result_buff, sizeof(result_buff))); sec->cmd_state = SEC_CMD_STATUS_FAIL; } else { snprintf(result_buff, sizeof(result_buff), "OK"); sec_cmd_set_cmd_result(sec, result_buff, strnlen(result_buff, sizeof(result_buff))); sec->cmd_state = SEC_CMD_STATUS_OK; } input_info(true, &info->client->dev, "%s: %s\n", __func__, result_buff); kfree(result_buff); return result; test_fail: kfree(result_buff); alloc_fail: snprintf(buff, 30, "NG"); sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); sec->cmd_state = SEC_CMD_STATUS_FAIL; return -ITO_FAIL; } static void run_trx_short_test(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct fts_ts_info *info = container_of(sec, struct fts_ts_info, sec); char buff[SEC_CMD_STR_LEN] = { 0 }; int result = 0; int type = 0; char test[32]; sec_cmd_set_default_result(sec); if (info->fts_power_state == FTS_POWER_STATE_POWERDOWN) { input_err(true, &info->client->dev, "%s: [ERROR] Touch is stopped\n", __func__); snprintf(buff, sizeof(buff), "NG"); sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); sec->cmd_state = SEC_CMD_STATUS_FAIL; return; } if (info->fts_power_state == FTS_POWER_STATE_LOWPOWER) { input_err(true, &info->client->dev, "%s: [ERROR] Touch is lp mode\n", __func__); snprintf(buff, sizeof(buff), "NG"); sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); sec->cmd_state = SEC_CMD_STATUS_FAIL; return; } if (sec->cmd_param[0] == 1 && sec->cmd_param[1] == 0) { input_err(true, &info->client->dev, "%s: %s: seperate cm1 test open / short test result\n", __func__, buff); snprintf(buff, sizeof(buff), "%s", "CONT"); sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); sec->cmd_state = SEC_CMD_STATUS_OK; return; } if (sec->cmd_param[0] == 1 && sec->cmd_param[1] == 1) { type = OPEN_TEST; } else if (sec->cmd_param[0] == 1 && sec->cmd_param[1] == 2) { type = SHORT_TEST; } else if (sec->cmd_param[0] > 1) { u8 result_buff[10]; snprintf(result_buff, sizeof(result_buff), "NA"); sec_cmd_set_cmd_result(sec, result_buff, strnlen(result_buff, sizeof(result_buff))); sec->cmd_state = SEC_CMD_STATUS_NOT_APPLICABLE; input_info(true, &info->client->dev, "%s : not supported test case\n", __func__); return; } input_info(true, &info->client->dev, "%s : CM%d factory_position[%d]\n", __func__, sec->cmd_param[0], info->factory_position); fts_interrupt_set(info, INT_DISABLE); result = fts_panel_test_result(info, type); fts_interrupt_set(info, INT_ENABLE); /* reinit */ info->fts_systemreset(info, 0); fts_reinit(info, false); info->touch_count = 0; if (sec->cmd_param[1]) snprintf(test, sizeof(test), "TEST=%d,%d", sec->cmd_param[0], sec->cmd_param[1]); else snprintf(test, sizeof(test), "TEST=%d", sec->cmd_param[0]); if (result == 0) sec_cmd_send_event_to_user(sec, test, "RESULT=PASS"); else sec_cmd_send_event_to_user(sec, test, "RESULT=FAIL"); input_info(true, &info->client->dev, "%s : test done\n", __func__); return; } static void check_connection(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct fts_ts_info *info = container_of(sec, struct fts_ts_info, sec); char buff[SEC_CMD_STR_LEN] = { 0 }; int ret = 0; sec_cmd_set_default_result(sec); if (info->fts_power_state == FTS_POWER_STATE_POWERDOWN) { input_err(true, &info->client->dev, "%s: [ERROR] Touch is stopped\n", __func__); snprintf(buff, sizeof(buff), "NG"); sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); sec->cmd_state = SEC_CMD_STATUS_FAIL; return; } ret = fts_panel_ito_test(info, OPEN_TEST); if (ret == 0) snprintf(buff, sizeof(buff), "OK"); else snprintf(buff, sizeof(buff), "NG"); sec->cmd_state = SEC_CMD_STATUS_OK; sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); input_info(true, &info->client->dev, "%s: %s\n", __func__, buff); } static void get_cx_data(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct fts_ts_info *info = container_of(sec, struct fts_ts_info, sec); char buff[SEC_CMD_STR_LEN] = { 0 }; short val = 0; int node = 0; sec_cmd_set_default_result(sec); if (info->fts_power_state == FTS_POWER_STATE_POWERDOWN) { input_err(true, &info->client->dev, "%s: [ERROR] Touch is stopped\n", __func__); snprintf(buff, sizeof(buff), "NG"); sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); sec->cmd_state = SEC_CMD_STATUS_FAIL; return; } node = fts_check_index(info); if (node < 0) return; if (info->cx_data) val = info->cx_data[node]; snprintf(buff, sizeof(buff), "%d", val); sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); sec->cmd_state = SEC_CMD_STATUS_OK; input_info(true, &info->client->dev, "%s: %s\n", __func__, buff); } static int read_ms_cx_data(struct fts_ts_info *info, u8 *cx_min, u8 *cx_max) { u8 *rdata; u8 regAdd[FTS_EVENT_SIZE] = { 0 }; u8 dataID; u16 comp_start_addr; int txnum, rxnum, i, j, ret = 0; u8 *pStr = NULL; u8 pTmp[16] = { 0 }; pStr = kzalloc(7 * (info->SenseChannelLength + 1), GFP_KERNEL); if (pStr == NULL) return -ENOMEM; rdata = kzalloc(info->ForceChannelLength * info->SenseChannelLength, GFP_KERNEL); if (!rdata) return -ENOMEM; info->fts_command(info, FTS_CMD_CLEAR_ALL_EVENT, true); // Clear FIFO fts_release_all_finger(info); fts_interrupt_set(info, INT_DISABLE); fts_delay(20); // Request compensation data type dataID = 0x11; // MS - LP regAdd[0] = 0xA4; regAdd[1] = 0x06; regAdd[2] = dataID; ret = fts_fw_wait_for_echo_event(info, ®Add[0], 3, 0); if (ret < 0) { input_info(true, &info->client->dev, "%s: failed to request data\n", __func__); fts_interrupt_set(info, INT_ENABLE); goto out; } // Read Header regAdd[0] = 0xA6; regAdd[1] = 0x00; regAdd[2] = 0x00; ret = info->fts_read_reg(info, ®Add[0], 3, &rdata[0], FTS_COMP_DATA_HEADER_SIZE); if (ret < 0) { input_info(true, &info->client->dev, "%s: failed to read header\n", __func__); fts_interrupt_set(info, INT_ENABLE); goto out; } fts_interrupt_set(info, INT_ENABLE); if ((rdata[0] != 0xA5) && (rdata[1] != dataID)) { input_info(true, &info->client->dev, "%s: failed to read signature data of header.\n", __func__); ret = -EIO; goto out; } txnum = rdata[4]; rxnum = rdata[5]; comp_start_addr = (u16)FTS_COMP_DATA_HEADER_SIZE; regAdd[0] = 0xA6; regAdd[1] = (u8)(comp_start_addr >> 8); regAdd[2] = (u8)(comp_start_addr & 0xFF); ret = info->fts_read_reg(info, ®Add[0], 3, &rdata[0], txnum * rxnum); if (ret < 0) { input_info(true, &info->client->dev, "%s: failed to read data\n", __func__); goto out; } *cx_min = *cx_max = rdata[0]; for (j = 0; j < info->ForceChannelLength; j++) { memset(pStr, 0x0, 7 * (info->SenseChannelLength + 1)); snprintf(pTmp, sizeof(pTmp), "Tx%02d | ", j); strlcat(pStr, pTmp, 7 * (info->SenseChannelLength + 1)); for (i = 0; i < info->SenseChannelLength; i++) { snprintf(pTmp, sizeof(pTmp), "%3d", rdata[j * info->SenseChannelLength + i]); strlcat(pStr, pTmp, 7 * (info->SenseChannelLength + 1)); *cx_min = min(*cx_min, rdata[j * info->SenseChannelLength + i]); *cx_max = max(*cx_max, rdata[j * info->SenseChannelLength + i]); } input_raw_info(true, &info->client->dev, "%s\n", pStr); } input_raw_info(true, &info->client->dev, "cx min:%d, cx max:%d\n", *cx_min, *cx_max); if (info->cx_data) memcpy(&info->cx_data[0], &rdata[0], info->ForceChannelLength * info->SenseChannelLength); out: kfree(rdata); kfree(pStr); return ret; } #define NORMAL_CX2 0 /* single driving */ #define ACTIVE_CX2 1 /* multi driving */ static int read_ms_cx2_data(struct fts_ts_info *info, u8 active, s8 *cx_min, s8 *cx_max) { s8 *rdata = NULL; u8 cdata[FTS_COMP_DATA_HEADER_SIZE]; u8 regAdd[FTS_EVENT_SIZE] = { 0 }; u8 dataID = 0; u16 comp_start_addr; int txnum, rxnum, i, j, ret = 0; u8 *pStr = NULL; u8 pTmp[16] = { 0 }; info->fts_command(info, FTS_CMD_CLEAR_ALL_EVENT, true); // Clear FIFO fts_release_all_finger(info); fts_interrupt_set(info, INT_DISABLE); fts_delay(20); // Request compensation data type if (active == NORMAL_CX2) dataID = 0x11; // MS - LP else if (active == ACTIVE_CX2) dataID = 0x10; // MS - ACTIVE regAdd[0] = 0xA4; regAdd[1] = 0x06; regAdd[2] = dataID; ret = fts_fw_wait_for_echo_event(info, ®Add[0], 3, 0); if (ret < 0) { fts_interrupt_set(info, INT_ENABLE); return ret; } // Read Header regAdd[0] = 0xA6; regAdd[1] = 0x00; regAdd[2] = 0x00; ret = info->fts_read_reg(info, ®Add[0], 3, &cdata[0], FTS_COMP_DATA_HEADER_SIZE); if (ret < 0) { fts_interrupt_set(info, INT_ENABLE); return ret; } fts_interrupt_set(info, INT_ENABLE); if ((cdata[0] != 0xA5) && (cdata[1] != dataID)) { input_info(true, &info->client->dev, "%s: failed to read signature data of header.\n", __func__); ret = -EIO; return ret; } txnum = cdata[4]; rxnum = cdata[5]; rdata = kzalloc(txnum * rxnum, GFP_KERNEL); if (!rdata) return -ENOMEM; comp_start_addr = (u16)FTS_COMP_DATA_HEADER_SIZE; regAdd[0] = 0xA6; regAdd[1] = (u8)(comp_start_addr >> 8); regAdd[2] = (u8)(comp_start_addr & 0xFF); ret = info->fts_read_reg(info, ®Add[0], 3, &rdata[0], txnum * rxnum); if (ret < 0) goto out; pStr = kzalloc(7 * (rxnum + 1), GFP_KERNEL); if (!pStr) { ret = -ENOMEM; goto out; } *cx_min = *cx_max = rdata[0]; for (i = 0; i < txnum; i++) { memset(pStr, 0x0, 7 * (rxnum + 1)); snprintf(pTmp, sizeof(pTmp), "Tx%02d | ", i); strlcat(pStr, pTmp, 7 * (rxnum + 1)); for (j = 0; j < rxnum; j++) { snprintf(pTmp, sizeof(pTmp), "%4d", rdata[i * rxnum + j]); strlcat(pStr, pTmp, 7 * (rxnum + 1)); *cx_min = min(*cx_min, rdata[i * rxnum + j]); *cx_max = max(*cx_max, rdata[i * rxnum + j]); } input_raw_info_d(true, &info->client->dev, "%s\n", pStr); } input_raw_info_d(true, &info->client->dev, "cx min:%d, cx max:%d\n", *cx_min, *cx_max); /* info->cx_data length: Force * Sense */ if (info->cx_data && active == NORMAL_CX2) memcpy(&info->cx_data[0], &rdata[0], info->ForceChannelLength * info->SenseChannelLength); kfree(pStr); out: kfree(rdata); return ret; } static void run_active_cx_data_read(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct fts_ts_info *info = container_of(sec, struct fts_ts_info, sec); char buff[SEC_CMD_STR_LEN] = { 0 }; char buff_minmax[SEC_CMD_STR_LEN] = { 0 }; int rc; s8 cx_min, cx_max; sec_cmd_set_default_result(sec); if (info->fts_power_state == FTS_POWER_STATE_POWERDOWN) { input_err(true, &info->client->dev, "%s: [ERROR] Touch is stopped\n", __func__); snprintf(buff, sizeof(buff), "NG"); sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); if (sec->cmd_all_factory_state == SEC_CMD_STATUS_RUNNING) sec_cmd_set_cmd_result_all(sec, buff, strnlen(buff, sizeof(buff)), "ACTIVE_CX2_DATA"); sec->cmd_state = SEC_CMD_STATUS_FAIL; return; } input_raw_info_d(true, &info->client->dev, "%s: start\n", __func__); rc = read_ms_cx2_data(info, ACTIVE_CX2, &cx_min, &cx_max); if (rc < 0) { snprintf(buff, sizeof(buff), "NG"); snprintf(buff_minmax, sizeof(buff_minmax), "NG"); sec->cmd_state = SEC_CMD_STATUS_FAIL; } else { snprintf(buff_minmax, sizeof(buff_minmax), "%d,%d", cx_min, cx_max); snprintf(buff, sizeof(buff), "OK"); sec->cmd_state = SEC_CMD_STATUS_OK; } if (sec->cmd_all_factory_state == SEC_CMD_STATUS_RUNNING) sec_cmd_set_cmd_result_all(sec, buff_minmax, strnlen(buff_minmax, sizeof(buff_minmax)), "ACTIVE_CX2_DATA"); sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); input_info(true, &info->client->dev, "%s: %s\n", __func__, buff); } static void run_multi_mutual_cx_data_read(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct fts_ts_info *info = container_of(sec, struct fts_ts_info, sec); char buff[SEC_CMD_STR_LEN] = { 0 }; u8 regAdd[FTS_EVENT_SIZE] = { 0 }; u8 *data; u8 dataID; u16 sense_cx_data[100]; u16 comp_start_rx_addr; unsigned int rx_num, tx_num; int rc, i, ret; u16 max_sense_cx = 0; u16 min_sense_cx = 0xFFFF; input_info(true, &info->client->dev, "%s\n", __func__); sec_cmd_set_default_result(sec); if (info->fts_power_state == FTS_POWER_STATE_POWERDOWN) { input_err(true, &info->client->dev, "%s: [ERROR] Touch is stopped\n", __func__); goto out; } info->fts_command(info, FTS_CMD_CLEAR_ALL_EVENT, true); fts_release_all_finger(info); fts_interrupt_set(info, INT_DISABLE); // Request compensation data type dataID = 0x56; regAdd[0] = 0xA4; regAdd[1] = 0x06; regAdd[2] = dataID; // Multi Mutual CX data rc = fts_fw_wait_for_echo_event(info, ®Add[0], 3, 0); fts_interrupt_set(info, INT_ENABLE); if (rc < 0) goto out; data = kzalloc((info->ForceChannelLength + info->SenseChannelLength) * 2 + 1, GFP_KERNEL); if (!data) { input_err(true, &info->client->dev, "%s: data kzalloc fail!\n", __func__); goto out; } // Read Header regAdd[0] = 0xA6; regAdd[1] = 0x00; regAdd[2] = 0x00; info->fts_read_reg(info, ®Add[0], 3, &data[0], FTS_COMP_DATA_HEADER_SIZE); if ((data[0] != 0xA5) && (data[1] != dataID)) { kfree(data); goto out; } tx_num = data[4]; rx_num = data[5]; /* Read Multi Mutual CX - RX data */ comp_start_rx_addr = FTS_COMP_DATA_HEADER_SIZE + (((tx_num * 2) + rx_num) * 2); regAdd[0] = 0xA6; regAdd[1] = (u8)(comp_start_rx_addr >> 8); regAdd[2] = (u8)(comp_start_rx_addr & 0xFF); ret = info->fts_read_reg(info, ®Add[0], 3, &data[0], rx_num * 2); if (ret < 0) { kfree(data); goto out; } for (i = 0; i < rx_num; i++) { sense_cx_data[i] = data[2 * i] | data[2 * i + 1] << 8; if (max_sense_cx < sense_cx_data[i]) max_sense_cx = sense_cx_data[i]; if (min_sense_cx > sense_cx_data[i]) min_sense_cx = sense_cx_data[i]; } kfree(data); snprintf(buff, sizeof(buff), "%d,%d", min_sense_cx, max_sense_cx); if (sec->cmd_all_factory_state == SEC_CMD_STATUS_RUNNING) sec_cmd_set_cmd_result_all(sec, buff, strnlen(buff, sizeof(buff)), "MULTI_MUTUAL_CX"); sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); sec->cmd_state = SEC_CMD_STATUS_OK; input_info(true, &info->client->dev, "%s: %s\n", __func__, buff); return; out: snprintf(buff, sizeof(buff), "NG"); sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); if (sec->cmd_all_factory_state == SEC_CMD_STATUS_RUNNING) sec_cmd_set_cmd_result_all(sec, buff, strnlen(buff, sizeof(buff)), "MULTI_MUTUAL_CX"); sec->cmd_state = SEC_CMD_STATUS_FAIL; input_info(true, &info->client->dev, "%s: %s\n", __func__, buff); } static void run_cx_data_read(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct fts_ts_info *info = container_of(sec, struct fts_ts_info, sec); char buff[SEC_CMD_STR_LEN] = { 0 }; char buff_minmax[SEC_CMD_STR_LEN] = { 0 }; int rc; u8 cx_min, cx_max; sec_cmd_set_default_result(sec); if (info->fts_power_state == FTS_POWER_STATE_POWERDOWN) { input_err(true, &info->client->dev, "%s: [ERROR] Touch is stopped\n", __func__); snprintf(buff, sizeof(buff), "NG"); sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); if (sec->cmd_all_factory_state == SEC_CMD_STATUS_RUNNING) sec_cmd_set_cmd_result_all(sec, buff, strnlen(buff, sizeof(buff)), "CX_DATA"); sec->cmd_state = SEC_CMD_STATUS_FAIL; return; } input_raw_info_d(true, &info->client->dev, "%s: start\n", __func__); rc = read_ms_cx_data(info, &cx_min, &cx_max); if (rc < 0) { snprintf(buff, sizeof(buff), "NG"); snprintf(buff_minmax, sizeof(buff_minmax), "NG"); sec->cmd_state = SEC_CMD_STATUS_FAIL; } else { snprintf(buff_minmax, sizeof(buff_minmax), "%d,%d", cx_min, cx_max); snprintf(buff, sizeof(buff), "OK"); sec->cmd_state = SEC_CMD_STATUS_OK; } if (sec->cmd_all_factory_state == SEC_CMD_STATUS_RUNNING) sec_cmd_set_cmd_result_all(sec, buff_minmax, strnlen(buff_minmax, sizeof(buff_minmax)), "CX_DATA"); sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); input_info(true, &info->client->dev, "%s: %s\n", __func__, buff); } static void get_cx_all_data(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct fts_ts_info *info = container_of(sec, struct fts_ts_info, sec); char buff[SEC_CMD_STR_LEN] = { 0 }; int rc, i, j; u8 cx_min, cx_max; char *all_strbuff; sec_cmd_set_default_result(sec); if (info->fts_power_state == FTS_POWER_STATE_POWERDOWN) { input_err(true, &info->client->dev, "%s: [ERROR] Touch is stopped\n", __func__); snprintf(buff, sizeof(buff), "NG"); sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); sec->cmd_state = SEC_CMD_STATUS_FAIL; return; } input_raw_info_d(true, &info->client->dev, "%s\n", __func__); input_info(true, &info->client->dev, "%s: start\n", __func__); rc = read_ms_cx_data(info, &cx_min, &cx_max); /* do not systemreset in COB type */ if (info->board->chip_on_board) fts_set_scanmode(info, info->scan_mode); else enter_factory_mode(info, false); if (rc < 0) { snprintf(buff, sizeof(buff), "NG"); sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); sec->cmd_state = SEC_CMD_STATUS_FAIL; return; } all_strbuff = kzalloc(info->ForceChannelLength * info->SenseChannelLength * 4 + 1, GFP_KERNEL); if (!all_strbuff) { snprintf(buff, sizeof(buff), "NG"); sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); sec->cmd_state = SEC_CMD_STATUS_FAIL; return; } /* Read compensation data */ if (info->cx_data) { for (j = 0; j < info->ForceChannelLength; j++) { for (i = 0; i < info->SenseChannelLength; i++) { snprintf(buff, sizeof(buff), "%d,", info->cx_data[j * info->SenseChannelLength + i]); strlcat(all_strbuff, buff, info->ForceChannelLength * info->SenseChannelLength * 4 + 1); } } } sec->cmd_state = SEC_CMD_STATUS_OK; sec_cmd_set_cmd_result(sec, all_strbuff, strlen(all_strbuff)); input_info(true, &info->client->dev, "%s: %ld\n", __func__, strlen(all_strbuff)); kfree(all_strbuff); } static void get_cx_gap_data(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct fts_ts_info *info = container_of(sec, struct fts_ts_info, sec); char buff[SEC_CMD_STR_LEN] = { 0 }; int rx_max = 0, tx_max = 0, ii; for (ii = 0; ii < (info->SenseChannelLength * info->ForceChannelLength); ii++) { /* rx(x) gap max */ if ((ii + 1) % (info->SenseChannelLength) != 0) rx_max = max(rx_max, (int)abs(info->cx_data[ii + 1] - info->cx_data[ii])); /* tx(y) gap max */ if (ii < (info->ForceChannelLength - 1) * info->SenseChannelLength) tx_max = max(tx_max, (int)abs(info->cx_data[ii + info->SenseChannelLength] - info->cx_data[ii])); } input_raw_info_d(true, &info->client->dev, "%s: max: rx:%d, tx:%d\n", __func__, rx_max, tx_max); if (sec->cmd_all_factory_state == SEC_CMD_STATUS_RUNNING) { snprintf(buff, sizeof(buff), "0,%d", rx_max); sec_cmd_set_cmd_result_all(sec, buff, SEC_CMD_STR_LEN, "CX_DATA_GAP_X"); snprintf(buff, sizeof(buff), "0,%d", tx_max); sec_cmd_set_cmd_result_all(sec, buff, SEC_CMD_STR_LEN, "CX_DATA_GAP_Y"); } } static void run_cx_gap_data_x_all(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct fts_ts_info *info = container_of(sec, struct fts_ts_info, sec); char *buff = NULL; int ii, jj; char temp[5] = { 0 }; sec_cmd_set_default_result(sec); buff = kzalloc(info->ForceChannelLength * info->SenseChannelLength * 5, GFP_KERNEL); if (!buff) { snprintf(temp, sizeof(temp), "NG"); sec_cmd_set_cmd_result(sec, temp, strnlen(temp, sizeof(temp))); sec->cmd_state = SEC_CMD_STATUS_FAIL; return; } for (ii = 0; ii < info->ForceChannelLength; ii++) { for (jj = 0; jj < info->SenseChannelLength - 1; jj++) { snprintf(temp, sizeof(temp), "%d,", abs(info->cx_data[(ii * info->SenseChannelLength) + jj + 1] - info->cx_data[(ii * info->SenseChannelLength) + jj])); strlcat(buff, temp, info->ForceChannelLength * info->SenseChannelLength * 5); memset(temp, 0x00, 5); } } sec_cmd_set_cmd_result(sec, buff, strnlen(buff, info->ForceChannelLength * info->SenseChannelLength * 5)); sec->cmd_state = SEC_CMD_STATUS_OK; kfree(buff); } static void run_cx_gap_data_y_all(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct fts_ts_info *info = container_of(sec, struct fts_ts_info, sec); char *buff = NULL; int ii, jj; char temp[5] = { 0 }; sec_cmd_set_default_result(sec); buff = kzalloc(info->ForceChannelLength * info->SenseChannelLength * 5, GFP_KERNEL); if (!buff) { snprintf(temp, sizeof(temp), "NG"); sec_cmd_set_cmd_result(sec, temp, strnlen(temp, sizeof(temp))); sec->cmd_state = SEC_CMD_STATUS_FAIL; return; } for (ii = 0; ii < info->ForceChannelLength - 1; ii++) { for (jj = 0; jj < info->SenseChannelLength; jj++) { snprintf(temp, sizeof(temp), "%d,", abs(info->cx_data[((ii + 1) * info->SenseChannelLength) + jj] - info->cx_data[(ii * info->SenseChannelLength)+ jj])); strlcat(buff, temp, info->ForceChannelLength * info->SenseChannelLength * 5); memset(temp, 0x00, 5); } } sec_cmd_set_cmd_result(sec, buff, strnlen(buff, info->ForceChannelLength * info->SenseChannelLength * 5)); sec->cmd_state = SEC_CMD_STATUS_OK; kfree(buff); } static void run_rawdata_gap_data_rx_all(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct fts_ts_info *info = container_of(sec, struct fts_ts_info, sec); char *buff = NULL; int ii; char temp[5] = { 0 }; sec_cmd_set_default_result(sec); buff = kzalloc(info->ForceChannelLength * info->SenseChannelLength * 5, GFP_KERNEL); if (!buff) { snprintf(temp, sizeof(temp), "NG"); sec_cmd_set_cmd_result(sec, temp, strnlen(temp, sizeof(temp))); sec->cmd_state = SEC_CMD_STATUS_FAIL; return; } for (ii = 0; ii < (info->SenseChannelLength * info->ForceChannelLength); ii++) { if ((ii + 1) % (info->SenseChannelLength) != 0) { snprintf(temp, sizeof(temp), "%d,", (int)abs(info->pFrame[ii + 1] - info->pFrame[ii])); strlcat(buff, temp, info->ForceChannelLength * info->SenseChannelLength * 5); memset(temp, 0x00, 5); } } sec_cmd_set_cmd_result(sec, buff, strnlen(buff, info->ForceChannelLength * info->SenseChannelLength * 5)); sec->cmd_state = SEC_CMD_STATUS_OK; kfree(buff); } static void run_rawdata_gap_data_tx_all(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct fts_ts_info *info = container_of(sec, struct fts_ts_info, sec); char *buff = NULL; int ii; char temp[5] = { 0 }; sec_cmd_set_default_result(sec); buff = kzalloc(info->ForceChannelLength * info->SenseChannelLength * 5, GFP_KERNEL); if (!buff) { snprintf(temp, sizeof(temp), "NG"); sec_cmd_set_cmd_result(sec, temp, strnlen(temp, sizeof(temp))); sec->cmd_state = SEC_CMD_STATUS_FAIL; return; } for (ii = 0; ii < (info->SenseChannelLength * info->ForceChannelLength); ii++) { if (ii < (info->ForceChannelLength - 1) * info->SenseChannelLength) { snprintf(temp, sizeof(temp), "%d,", (int)abs(info->pFrame[ii + info->SenseChannelLength] - info->pFrame[ii])); strlcat(buff, temp, info->ForceChannelLength * info->SenseChannelLength * 5); memset(temp, 0x00, 5); } } sec_cmd_set_cmd_result(sec, buff, strnlen(buff, info->ForceChannelLength * info->SenseChannelLength * 5)); sec->cmd_state = SEC_CMD_STATUS_OK; kfree(buff); } static void factory_cmd_result_all(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct fts_ts_info *info = container_of(sec, struct fts_ts_info, sec); sec->item_count = 0; memset(sec->cmd_result_all, 0x00, SEC_CMD_RESULT_STR_LEN); if (info->fts_power_state == FTS_POWER_STATE_POWERDOWN) { input_err(true, &info->client->dev, "%s: [ERROR] Touch is stopped\n", __func__); sec->cmd_all_factory_state = SEC_CMD_STATUS_FAIL; goto out; } sec->cmd_all_factory_state = SEC_CMD_STATUS_RUNNING; get_chip_vendor(sec); get_chip_name(sec); get_fw_ver_bin(sec); get_fw_ver_ic(sec); enter_factory_mode(info, true); // run_lp_single_ended_rawcap_read(sec); /* Mutual raw */ run_rawcap_read(sec); run_self_raw_read(sec); fts_set_scanmode(info, FTS_SCAN_MODE_SCAN_OFF); fts_release_all_finger(info); // have to check items // get_strength_all_data(sec); /* jitter data */ // run_high_frequency_rawcap_read(sec); /* micro_open */ // get_rawcap_gap_data(sec); /* micro_open rawcap gap */ // run_low_frequency_rawcap_read(sec); /* micro_short gap diff */ // run_active_cx_data_read(sec); run_cx_data_read(sec); get_cx_gap_data(sec); run_ix_data_read(sec); get_wet_mode(sec); /* do not systemreset in COB type */ if (info->board->chip_on_board) fts_set_scanmode(info, info->scan_mode); else enter_factory_mode(info, false); run_mutual_jitter(sec); run_self_jitter(sec); run_factory_miscalibration(sec); if (info->board->support_sram_test ) run_sram_test(sec); sec->cmd_all_factory_state = SEC_CMD_STATUS_OK; out: input_info(true, &info->client->dev, "%s: %d%s\n", __func__, sec->item_count, sec->cmd_result_all); } static void factory_cmd_result_all_imagetest(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct fts_ts_info *info = container_of(sec, struct fts_ts_info, sec); sec->item_count = 0; memset(sec->cmd_result_all, 0x00, SEC_CMD_RESULT_STR_LEN); if (info->fts_power_state == FTS_POWER_STATE_POWERDOWN) { input_err(true, &info->client->dev, "%s: [ERROR] Touch is stopped\n", __func__); sec->cmd_all_factory_state = SEC_CMD_STATUS_FAIL; goto out; } sec->cmd_all_factory_state = SEC_CMD_STATUS_RUNNING; run_jitter_delta_test(sec); sec->cmd_all_factory_state = SEC_CMD_STATUS_OK; out: input_info(true, &info->client->dev, "%s: %d%s\n", __func__, sec->item_count, sec->cmd_result_all); } static void set_factory_level(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct fts_ts_info *info = container_of(sec, struct fts_ts_info, sec); char buff[SEC_CMD_STR_LEN] = { 0 }; sec_cmd_set_default_result(sec); if (info->fts_power_state == FTS_POWER_STATE_POWERDOWN) { input_err(true, &info->client->dev, "%s: Touch is stopped!\n", __func__); goto NG; } if (sec->cmd_param[0] < OFFSET_FAC_SUB || sec->cmd_param[0] > OFFSET_FAC_MAIN) { input_err(true, &info->client->dev, "%s: cmd data is abnormal, %d\n", __func__, sec->cmd_param[0]); goto NG; } info->factory_position = sec->cmd_param[0]; input_info(true, &info->client->dev, "%s: %d\n", __func__, info->factory_position); snprintf(buff, sizeof(buff), "OK"); sec->cmd_state = SEC_CMD_STATUS_OK; sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); return; NG: snprintf(buff, sizeof(buff), "NG"); sec->cmd_state = SEC_CMD_STATUS_FAIL; sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); } int fts_get_tsp_test_result(struct fts_ts_info *info) { u8 data; int ret; ret = get_nvm_data(info, FTS_NVM_OFFSET_FAC_RESULT, &data); if (ret < 0) goto err_read; if (data == 0xFF) data = 0; info->test_result.data[0] = data; err_read: return ret; } EXPORT_SYMBOL(fts_get_tsp_test_result); static void get_tsp_test_result(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct fts_ts_info *info = container_of(sec, struct fts_ts_info, sec); char buff[SEC_CMD_STR_LEN] = { 0 }; int ret; sec_cmd_set_default_result(sec); if (info->fts_power_state == FTS_POWER_STATE_POWERDOWN) { input_err(true, &info->client->dev, "%s: [ERROR] Touch is stopped\n", __func__); snprintf(buff, sizeof(buff), "NG"); sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); sec->cmd_state = SEC_CMD_STATUS_FAIL; return; } ret = fts_get_tsp_test_result(info); if (ret < 0) { input_err(true, &info->client->dev, "%s: get failed. ret: %d\n", __func__, ret); snprintf(buff, sizeof(buff), "NG"); sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); sec->cmd_state = SEC_CMD_STATUS_FAIL; } else { snprintf(buff, sizeof(buff), "M:%s, M:%d, A:%s, A:%d", info->test_result.module_result == 0 ? "NONE" : info->test_result.module_result == 1 ? "FAIL" : info->test_result.module_result == 2 ? "PASS" : "A", info->test_result.module_count, info->test_result.assy_result == 0 ? "NONE" : info->test_result.assy_result == 1 ? "FAIL" : info->test_result.assy_result == 2 ? "PASS" : "A", info->test_result.assy_count); sec_cmd_set_cmd_result(sec, buff, strlen(buff)); sec->cmd_state = SEC_CMD_STATUS_OK; } } /* FACTORY TEST RESULT SAVING FUNCTION * bit 3 ~ 0 : OCTA Assy * bit 7 ~ 4 : OCTA module * param[0] : OCTA module(1) / OCTA Assy(2) * param[1] : TEST NONE(0) / TEST FAIL(1) / TEST PASS(2) : 2 bit */ static void set_tsp_test_result(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct fts_ts_info *info = container_of(sec, struct fts_ts_info, sec); char buff[SEC_CMD_STR_LEN] = { 0 }; int ret; sec_cmd_set_default_result(sec); if (info->fts_power_state == FTS_POWER_STATE_POWERDOWN) { input_err(true, &info->client->dev, "%s: [ERROR] Touch is stopped\n", __func__); snprintf(buff, sizeof(buff), "NG"); sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); sec->cmd_state = SEC_CMD_STATUS_FAIL; return; } ret = fts_get_tsp_test_result(info); if (ret < 0) { input_err(true, &info->client->dev, "%s: get failed. ret: %d\n", __func__, ret); snprintf(buff, sizeof(buff), "NG"); sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); sec->cmd_state = SEC_CMD_STATUS_FAIL; return; } sec->cmd_state = SEC_CMD_STATUS_RUNNING; if (sec->cmd_param[0] == TEST_OCTA_ASSAY) { info->test_result.assy_result = sec->cmd_param[1]; if (info->test_result.assy_count < 3) info->test_result.assy_count++; } else if (sec->cmd_param[0] == TEST_OCTA_MODULE) { info->test_result.module_result = sec->cmd_param[1]; if (info->test_result.module_count < 3) info->test_result.module_count++; } input_info(true, &info->client->dev, "%s: [0x%X] M:%s, M:%d, A:%s, A:%d\n", __func__, info->test_result.data[0], info->test_result.module_result == 0 ? "NONE" : info->test_result.module_result == 1 ? "FAIL" : info->test_result.module_result == 2 ? "PASS" : "A", info->test_result.module_count, info->test_result.assy_result == 0 ? "NONE" : info->test_result.assy_result == 1 ? "FAIL" : info->test_result.assy_result == 2 ? "PASS" : "A", info->test_result.assy_count); ret = set_nvm_data(info, FTS_NVM_OFFSET_FAC_RESULT, info->test_result.data); if (ret < 0) { input_err(true, &info->client->dev, "%s: set failed. ret: %d\n", __func__, ret); snprintf(buff, sizeof(buff), "NG"); sec->cmd_state = SEC_CMD_STATUS_FAIL; } else { snprintf(buff, sizeof(buff), "OK"); sec->cmd_state = SEC_CMD_STATUS_OK; } sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); input_info(true, &info->client->dev, "%s: %s\n", __func__, buff); } int fts_get_disassemble_count(struct fts_ts_info *info) { u8 data; int ret; ret = get_nvm_data(info, FTS_NVM_OFFSET_DISASSEMBLE_COUNT, &data); if (ret < 0) goto err_read; if (data == 0xFF) data = 0; info->disassemble_count = data; err_read: return ret; } static void increase_disassemble_count(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct fts_ts_info *info = container_of(sec, struct fts_ts_info, sec); char buff[SEC_CMD_STR_LEN] = { 0 }; int ret; sec_cmd_set_default_result(sec); if (info->fts_power_state == FTS_POWER_STATE_POWERDOWN) { input_err(true, &info->client->dev, "%s: [ERROR] Touch is stopped\n", __func__); snprintf(buff, sizeof(buff), "NG"); sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); sec->cmd_state = SEC_CMD_STATUS_FAIL; return; } ret = fts_get_disassemble_count(info); if (ret < 0) { input_err(true, &info->client->dev, "%s: get failed. ret: %d\n", __func__, ret); snprintf(buff, sizeof(buff), "NG"); sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); sec->cmd_state = SEC_CMD_STATUS_FAIL; return; } sec->cmd_state = SEC_CMD_STATUS_RUNNING; if (info->disassemble_count < 0xFE) info->disassemble_count++; ret = set_nvm_data(info, FTS_NVM_OFFSET_DISASSEMBLE_COUNT, &info->disassemble_count); if (ret < 0) { input_err(true, &info->client->dev, "%s: set failed. ret: %d\n", __func__, ret); snprintf(buff, sizeof(buff), "NG"); sec->cmd_state = SEC_CMD_STATUS_FAIL; } else { snprintf(buff, sizeof(buff), "OK"); sec->cmd_state = SEC_CMD_STATUS_OK; } sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); input_info(true, &info->client->dev, "%s: %s\n", __func__, buff); } static void get_disassemble_count(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct fts_ts_info *info = container_of(sec, struct fts_ts_info, sec); char buff[SEC_CMD_STR_LEN] = { 0 }; int ret; sec_cmd_set_default_result(sec); if (info->fts_power_state == FTS_POWER_STATE_POWERDOWN) { input_err(true, &info->client->dev, "%s: [ERROR] Touch is stopped\n", __func__); snprintf(buff, sizeof(buff), "NG"); sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); sec->cmd_state = SEC_CMD_STATUS_FAIL; return; } ret = fts_get_disassemble_count(info); if (ret < 0) { input_err(true, &info->client->dev, "%s: get failed. ret: %d\n", __func__, ret); snprintf(buff, sizeof(buff), "NG"); sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); sec->cmd_state = SEC_CMD_STATUS_FAIL; } else { snprintf(buff, sizeof(buff), "%d", info->disassemble_count); sec_cmd_set_cmd_result(sec, buff, strlen(buff)); sec->cmd_state = SEC_CMD_STATUS_OK; } } static void get_osc_trim_error(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct fts_ts_info *info = container_of(sec, struct fts_ts_info, sec); char buff[SEC_CMD_STR_LEN] = { 0 }; int ret; sec_cmd_set_default_result(sec); if (info->fts_power_state == FTS_POWER_STATE_POWERDOWN) { input_err(true, &info->client->dev, "%s: [ERROR] Touch is stopped\n", __func__); snprintf(buff, sizeof(buff), "NG"); sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); sec->cmd_state = SEC_CMD_STATUS_FAIL; return; } ret = info->fts_systemreset(info, 0); if (ret == -FTS_ERROR_BROKEN_OSC_TRIM) { snprintf(buff, sizeof(buff), "1"); } else { snprintf(buff, sizeof(buff), "0"); } fts_set_scanmode(info, info->scan_mode); sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); if (sec->cmd_all_factory_state == SEC_CMD_STATUS_RUNNING) sec_cmd_set_cmd_result_all(sec, buff, strnlen(buff, sizeof(buff)), "OSC_TRIM_ERR"); sec->cmd_state = SEC_CMD_STATUS_OK; input_info(true, &info->client->dev, "%s: %s\n", __func__, buff); } static void get_osc_trim_info(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct fts_ts_info *info = container_of(sec, struct fts_ts_info, sec); char buff[SEC_CMD_STR_LEN] = { 0 }; int ret; unsigned char data[4]; unsigned char regAdd[3]; sec_cmd_set_default_result(sec); if (info->fts_power_state == FTS_POWER_STATE_POWERDOWN) { input_err(true, &info->client->dev, "%s: [ERROR] Touch is stopped\n", __func__); snprintf(buff, sizeof(buff), "NG"); sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); sec->cmd_state = SEC_CMD_STATUS_FAIL; return; } ret = info->fts_get_sysinfo_data(info, FTS_SI_OSC_TRIM_INFO, 2, data); if (ret < 0) { input_err(true, &info->client->dev, "%s: system info read failed. ret: %d\n", __func__, ret); snprintf(buff, sizeof(buff), "NG"); sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); sec->cmd_state = SEC_CMD_STATUS_FAIL; return; } regAdd[0] = 0xA6; regAdd[1] = data[1]; regAdd[2] = data[0]; memset(data, 0x00, 4); ret = info->fts_read_reg(info, regAdd, 3, data, 4); if (ret < 0) { input_err(true, &info->client->dev, "%s: osc trim info read failed. ret: %d\n", __func__, ret); snprintf(buff, sizeof(buff), "NG"); sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); sec->cmd_state = SEC_CMD_STATUS_FAIL; return; } snprintf(buff, sizeof(buff), "%02X%02X%02X%02X", data[0], data[1], data[2], data[3]); sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); if (sec->cmd_all_factory_state == SEC_CMD_STATUS_RUNNING) sec_cmd_set_cmd_result_all(sec, buff, strnlen(buff, sizeof(buff)), "OSC_TRIM_INFO"); sec->cmd_state = SEC_CMD_STATUS_OK; input_info(true, &info->client->dev, "%s: %s\n", __func__, buff); } static void run_snr_non_touched(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct fts_ts_info *info = container_of(sec, struct fts_ts_info, sec); char buff[SEC_CMD_STR_LEN] = { 0 }; u8 address[5] = { 0 }; u16 status; int ret = 0; int wait_time = 0; int retry_cnt = 0; input_info(true, &info->client->dev, "%s\n", __func__); sec_cmd_set_default_result(sec); if (info->fts_power_state == FTS_POWER_STATE_POWERDOWN) { input_err(true, &info->client->dev, "%s: [ERROR] Touch is stopped\n", __func__); goto out_init; } if (sec->cmd_param[0] < 1 || sec->cmd_param[0] > 1000) { input_err(true, &info->client->dev, "%s: strange value frame:%d\n", __func__, sec->cmd_param[0]); goto out_init; } fts_fix_active_mode(info, true); /* enter SNR mode */ address[0] = 0x70; address[1] = 0x25; ret = info->fts_write_reg(info, &address[0], 2); if (ret < 0) { input_err(true, &info->client->dev, "%s: i2c_write failed\n", __func__); goto out; } /* start Non-touched Peak Noise */ address[0] = 0xC7; address[1] = 0x09; address[2] = 0x01; address[3] = (u8)(sec->cmd_param[0] & 0xff); address[4] = (u8)(sec->cmd_param[0] >> 8); ret = info->fts_write_reg(info, &address[0], 5); if (ret < 0) { input_err(true, &info->client->dev, "%s: i2c_write failed\n", __func__); goto out; } wait_time = (sec->cmd_param[0] * 1000) / 120 + (sec->cmd_param[0] * 1000) % 120; fts_delay(wait_time); retry_cnt = 50; address[0] = 0x72; while ((info->fts_read_reg(info, &address[0], 1, (u8 *)&status, 2) > 0) && (retry_cnt-- > 0)) { if (status == 1) break; fts_delay(20); } if (status == 0) { input_err(true, &info->client->dev, "%s: failed non-touched status:%d\n", __func__, status); goto out; } snprintf(buff, sizeof(buff), "OK"); sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); sec->cmd_state = SEC_CMD_STATUS_OK; /* EXIT SNR mode */ address[0] = 0x70; address[1] = 0x00; info->fts_write_reg(info, &address[0], 2); fts_fix_active_mode(info, false); input_info(true, &info->client->dev, "%s: %s\n", __func__, buff); return; out: address[0] = 0x70; address[1] = 0x00; info->fts_write_reg(info, &address[0], 2); fts_fix_active_mode(info, false); out_init: snprintf(buff, sizeof(buff), "NG"); sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); sec->cmd_state = SEC_CMD_STATUS_FAIL; input_info(true, &info->client->dev, "%s: %s\n", __func__, buff); } static void run_snr_touched(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct fts_ts_info *info = container_of(sec, struct fts_ts_info, sec); struct stm_ts_snr_result_cmd snr_cmd_result; struct stm_ts_snr_result snr_result; char buff[SEC_CMD_STR_LEN] = { 0 }; char tbuff[SEC_CMD_STR_LEN] = { 0 }; u8 address[5] = { 0 }; int ret = 0; int wait_time = 0; int retry_cnt = 0; int i = 0; input_info(true, &info->client->dev, "%s\n", __func__); sec_cmd_set_default_result(sec); memset(&snr_result, 0, sizeof(struct stm_ts_snr_result)); memset(&snr_cmd_result, 0, sizeof(struct stm_ts_snr_result_cmd)); if (info->fts_power_state == FTS_POWER_STATE_POWERDOWN) { input_err(true, &info->client->dev, "%s: [ERROR] Touch is stopped\n", __func__); goto out_init; } if (sec->cmd_param[0] < 1 || sec->cmd_param[0] > 1000) { input_err(true, &info->client->dev, "%s: strange value frame:%d\n", __func__, sec->cmd_param[0]); goto out_init; } fts_fix_active_mode(info, true); /* enter SNR mode */ address[0] = 0x70; address[1] = 0x25; ret = info->fts_write_reg(info, &address[0], 2); if (ret < 0) { input_err(true, &info->client->dev, "%s: i2c_write failed\n", __func__); goto out; } /* start touched Peak Noise */ address[0] = 0xC7; address[1] = 0x09; address[2] = 0x02; address[3] = (u8)(sec->cmd_param[0] & 0xff); address[4] = (u8)(sec->cmd_param[0] >> 8); ret = info->fts_write_reg(info, &address[0], 5); if (ret < 0) { input_err(true, &info->client->dev, "%s: i2c_write failed\n", __func__); goto out; } wait_time = (sec->cmd_param[0] * 1000) / 120 + (sec->cmd_param[0] * 1000) % 120; fts_delay(wait_time); retry_cnt = 50; address[0] = 0x72; while ((info->fts_read_reg(info, &address[0], 1, (u8 *)&snr_cmd_result, 6) > 0) && (retry_cnt-- > 0)) { if (snr_cmd_result.status == 1) break; fts_delay(20); } if (snr_cmd_result.status == 0) { input_err(true, &info->client->dev, "%s: failed non-touched status:%d\n", __func__, snr_cmd_result.status); goto out; } else { input_info(true, &info->client->dev, "%s: status:%d, point:%d, average:%d\n", __func__, snr_cmd_result.status, snr_cmd_result.point, snr_cmd_result.average); } address[0] = 0x72; ret = info->fts_read_reg(info, &address[0], 1, (u8 *)&snr_result, sizeof(struct stm_ts_snr_result)); if (ret < 0) { input_err(true, &info->client->dev, "%s: i2c_write failed size:%d\n", __func__, sizeof(struct stm_ts_snr_result)); goto out; } for (i = 0; i < 9; i++) { input_info(true, &info->client->dev, "%s: average:%d, snr1:%d, snr2:%d\n", __func__, snr_result.result[i].average, snr_result.result[i].snr1, snr_result.result[i].snr2); snprintf(tbuff, sizeof(tbuff), "%d,%d,%d,", snr_result.result[i].average, snr_result.result[i].snr1, snr_result.result[i].snr2); strlcat(buff, tbuff, sizeof(buff)); } sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); sec->cmd_state = SEC_CMD_STATUS_OK; /* EXIT SNR mode */ address[0] = 0x70; address[1] = 0x00; info->fts_write_reg(info, &address[0], 2); fts_fix_active_mode(info, false); input_info(true, &info->client->dev, "%s: %s\n", __func__, buff); return; out: address[0] = 0x70; address[1] = 0x00; info->fts_write_reg(info, &address[0], 2); fts_fix_active_mode(info, false); out_init: snprintf(buff, sizeof(buff), "NG"); sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); sec->cmd_state = SEC_CMD_STATUS_FAIL; input_info(true, &info->client->dev, "%s: %s\n", __func__, buff); } /* static void run_elvss_test(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct fts_ts_info *info = container_of(sec, struct fts_ts_info, sec); char buff[SEC_CMD_STR_LEN] = { 0 }; int ret; u8 data[FTS_EVENT_SIZE + 1]; int retry = 10; sec_cmd_set_default_result(sec); snprintf(buff, sizeof(buff), "NG"); if (info->fts_power_state == FTS_POWER_STATE_POWERDOWN) { input_err(true, &info->client->dev, "%s: [ERROR] Touch is stopped\n", __func__); sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); sec->cmd_state = SEC_CMD_STATUS_FAIL; return; } info->fts_systemreset(info, 0); fts_interrupt_set(info, INT_DISABLE); memset(data, 0x00, 8); data[0] = 0xA4; data[1] = 0x04; data[2] = 0x00; data[3] = 0x04; ret = info->fts_write_reg(info, data, 4); if (ret < 0) { input_err(true, &info->client->dev, "%s: write failed. ret: %d\n", __func__, ret); sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); sec->cmd_state = SEC_CMD_STATUS_FAIL; fts_reinit(info, false); fts_interrupt_set(info, INT_ENABLE); return; } memset(data, 0x00, FTS_EVENT_SIZE); data[0] = FTS_READ_ONE_EVENT; while (info->fts_read_reg(info, &data[0], 1, &data[1], FTS_EVENT_SIZE) > 0) { input_info(true, &info->client->dev, "%s: %02X: %02X,%02X,%02X,%02X,%02X,%02X,%02X,%02X,%02X,%02X,%02X,%02X,%02X,%02X,%02X\n", __func__, data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7], data[8], data[9], data[10], data[11], data[12], data[13], data[14], data[15]); if (data[1] == FTS_EVENT_ERROR_REPORT) { break; } else if (data[1] == 0x03) { snprintf(buff, sizeof(buff), "OK"); break; } else if (retry < 0) { break; } retry--; fts_delay(50); } fts_reinit(info, false); fts_interrupt_set(info, INT_ENABLE); sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); sec->cmd_state = SEC_CMD_STATUS_OK; input_info(true, &info->client->dev, "%s: %s\n", __func__, buff); } */ int set_nvm_data_by_size(struct fts_ts_info *info, u8 offset, int length, u8 *buf) { u8 regAdd[256] = { 0 }; u8 remaining, index, sendinglength; int ret; info->fts_command(info, FTS_CMD_CLEAR_ALL_EVENT, true); // Clear FIFO fts_release_all_finger(info); remaining = length; index = 0; sendinglength = 0; while (remaining) { regAdd[0] = 0xC7; regAdd[1] = 0x01; regAdd[2] = offset + index; // write data up to 12 bytes available if (remaining < 13) { memcpy(®Add[3], &buf[index], remaining); sendinglength = remaining; } else { memcpy(®Add[3], &buf[index], 12); index += 12; sendinglength = 12; } ret = fts_write_reg(info, ®Add[0], sendinglength + 3); if (ret < 0) { input_err(true, &info->client->dev, "%s: write failed. ret: %d\n", __func__, ret); return ret; } remaining -= sendinglength; } fts_interrupt_set(info, INT_DISABLE); // Save to flash regAdd[0] = 0xA4; regAdd[1] = 0x05; regAdd[2] = 0x04; // panel configuration area ret = fts_fw_wait_for_echo_event(info, ®Add[0], 3, 200); if (ret < 0) input_err(true, &info->client->dev, "%s: failed to get echo. ret: %d\n", __func__, ret); fts_interrupt_set(info, INT_ENABLE); return ret; } int set_nvm_data(struct fts_ts_info *info, u8 type, u8 *buf) { return set_nvm_data_by_size(info, nvm_data[type].offset, nvm_data[type].length, buf); } int get_nvm_data_by_size(struct fts_ts_info *info, u8 offset, int length, u8 *nvdata) { u8 regAdd[3] = {0}; u8 data[128] = { 0 }; int ret; info->fts_command(info, FTS_CMD_CLEAR_ALL_EVENT, true); // Clear FIFO fts_release_all_finger(info); fts_interrupt_set(info, INT_DISABLE); // Request SEC factory debug data from flash regAdd[0] = 0xA4; regAdd[1] = 0x06; regAdd[2] = 0x90; ret = fts_fw_wait_for_echo_event(info, ®Add[0], 3, 0); if (ret < 0) { input_err(true, &info->client->dev, "%s: timeout. ret: %d\n", __func__, ret); fts_interrupt_set(info, INT_ENABLE); return ret; } fts_interrupt_set(info, INT_ENABLE); regAdd[0] = 0xA6; regAdd[1] = 0x00; regAdd[2] = offset; ret = fts_read_reg(info, ®Add[0], 3, data, length + 1); if (ret < 0) { input_err(true, &info->client->dev, "%s: read failed. ret: %d\n", __func__, ret); return ret; } memcpy(nvdata, &data[0], length); input_raw_info_d(true, &info->client->dev, "%s: offset [%d], length [%d]\n", __func__, offset, length); return ret; } int get_nvm_data(struct fts_ts_info *info, int type, u8 *nvdata) { int size = sizeof(nvm_data) / sizeof(struct fts_nvm_data_map); if (type >= size) return -EINVAL; return get_nvm_data_by_size(info, nvm_data[type].offset, nvm_data[type].length, nvdata); } #ifdef TCLM_CONCEPT int fts_tclm_data_read(struct i2c_client *client, int address) { struct fts_ts_info *info = i2c_get_clientdata(client); int ret = 0; int i = 0; u8 nbuff[FTS_NVM_OFFSET_ALL]; u16 ic_version; switch (address) { case SEC_TCLM_NVM_OFFSET_IC_FIRMWARE_VER: ret = info->fts_get_version_info(info); ic_version = (info->module_version_of_ic << 8) | (info->fw_main_version_of_ic & 0xFF); return ic_version; case SEC_TCLM_NVM_ALL_DATA: ret = get_nvm_data_by_size(info, nvm_data[FTS_NVM_OFFSET_FAC_RESULT].offset, FTS_NVM_OFFSET_ALL, nbuff); if (ret < 0) return ret; info->tdata->nvdata.cal_count = nbuff[nvm_data[FTS_NVM_OFFSET_CAL_COUNT].offset]; info->tdata->nvdata.tune_fix_ver = (nbuff[nvm_data[FTS_NVM_OFFSET_TUNE_VERSION].offset] << 8) | nbuff[nvm_data[FTS_NVM_OFFSET_TUNE_VERSION].offset + 1]; info->tdata->nvdata.cal_position = nbuff[nvm_data[FTS_NVM_OFFSET_CAL_POSITION].offset]; info->tdata->nvdata.cal_pos_hist_cnt = nbuff[nvm_data[FTS_NVM_OFFSET_HISTORY_QUEUE_COUNT].offset]; info->tdata->nvdata.cal_pos_hist_lastp = nbuff[nvm_data[FTS_NVM_OFFSET_HISTORY_QUEUE_LASTP].offset]; for (i = nvm_data[FTS_NVM_OFFSET_HISTORY_QUEUE_ZERO].offset; i < nvm_data[FTS_NVM_OFFSET_HISTORY_QUEUE_ZERO].offset + nvm_data[FTS_NVM_OFFSET_HISTORY_QUEUE_ZERO].length; i++) info->tdata->nvdata.cal_pos_hist_queue[i - nvm_data[FTS_NVM_OFFSET_HISTORY_QUEUE_ZERO].offset] = nbuff[i]; info->tdata->nvdata.cal_fail_falg = nbuff[nvm_data[FTS_NVM_OFFSET_CAL_FAIL_FLAG].offset]; info->tdata->nvdata.cal_fail_cnt= nbuff[nvm_data[FTS_NVM_OFFSET_CAL_FAIL_COUNT].offset]; info->fac_nv = nbuff[nvm_data[FTS_NVM_OFFSET_FAC_RESULT].offset]; info->disassemble_count = nbuff[nvm_data[FTS_NVM_OFFSET_DISASSEMBLE_COUNT].offset]; return ret; case SEC_TCLM_NVM_TEST: input_info(true, &info->client->dev, "%s: dt: tclm_level [%d] afe_base [%04X]\n", __func__, info->tdata->tclm_level, info->tdata->afe_base); ret = get_nvm_data_by_size(info, FTS_NVM_OFFSET_ALL + SEC_TCLM_NVM_OFFSET, SEC_TCLM_NVM_OFFSET_LENGTH, info->tdata->tclm); if (info->tdata->tclm[0] != 0xFF) { info->tdata->tclm_level = info->tdata->tclm[0]; info->tdata->afe_base = (info->tdata->tclm[1] << 8) | info->tdata->tclm[2]; input_info(true, &info->client->dev, "%s: nv: tclm_level [%d] afe_base [%04X]\n", __func__, info->tdata->tclm_level, info->tdata->afe_base); } return ret; default: return ret; } } int fts_tclm_data_write(struct i2c_client *client, int address) { struct fts_ts_info *info = i2c_get_clientdata(client); int ret = 1; int i = 0; u8 nbuff[FTS_NVM_OFFSET_ALL]; switch (address) { case SEC_TCLM_NVM_ALL_DATA: memset(nbuff, 0x00, FTS_NVM_OFFSET_ALL); nbuff[nvm_data[FTS_NVM_OFFSET_FAC_RESULT].offset] = info->fac_nv; nbuff[nvm_data[FTS_NVM_OFFSET_DISASSEMBLE_COUNT].offset] = info->disassemble_count; nbuff[nvm_data[FTS_NVM_OFFSET_CAL_COUNT].offset] = info->tdata->nvdata.cal_count; nbuff[nvm_data[FTS_NVM_OFFSET_TUNE_VERSION].offset] = (u8)(info->tdata->nvdata.tune_fix_ver >> 8); nbuff[nvm_data[FTS_NVM_OFFSET_TUNE_VERSION].offset + 1] = (u8)(0xff & info->tdata->nvdata.tune_fix_ver); nbuff[nvm_data[FTS_NVM_OFFSET_CAL_POSITION].offset] = info->tdata->nvdata.cal_position; nbuff[nvm_data[FTS_NVM_OFFSET_HISTORY_QUEUE_COUNT].offset] = info->tdata->nvdata.cal_pos_hist_cnt; nbuff[nvm_data[FTS_NVM_OFFSET_HISTORY_QUEUE_LASTP].offset] = info->tdata->nvdata.cal_pos_hist_lastp; for (i = nvm_data[FTS_NVM_OFFSET_HISTORY_QUEUE_ZERO].offset; i < nvm_data[FTS_NVM_OFFSET_HISTORY_QUEUE_ZERO].offset + nvm_data[FTS_NVM_OFFSET_HISTORY_QUEUE_ZERO].length; i++) nbuff[i] = info->tdata->nvdata.cal_pos_hist_queue[i - nvm_data[FTS_NVM_OFFSET_HISTORY_QUEUE_ZERO].offset]; nbuff[nvm_data[FTS_NVM_OFFSET_CAL_FAIL_FLAG].offset] = info->tdata->nvdata.cal_fail_falg; nbuff[nvm_data[FTS_NVM_OFFSET_CAL_FAIL_COUNT].offset] = info->tdata->nvdata.cal_fail_cnt; ret = set_nvm_data_by_size(info, nvm_data[FTS_NVM_OFFSET_FAC_RESULT].offset, FTS_NVM_OFFSET_ALL, nbuff); return ret; case SEC_TCLM_NVM_TEST: ret = set_nvm_data_by_size(info, FTS_NVM_OFFSET_ALL + SEC_TCLM_NVM_OFFSET, SEC_TCLM_NVM_OFFSET_LENGTH, info->tdata->tclm); return ret; default: return ret; } } static void tclm_test_cmd(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct fts_ts_info *info = container_of(sec, struct fts_ts_info, sec); struct sec_tclm_data *data = info->tdata; char buff[SEC_CMD_STR_LEN] = { 0 }; int ret = 0; sec_cmd_set_default_result(sec); if (!info->tdata->support_tclm_test) goto not_support; ret = tclm_test_command(data, sec->cmd_param[0], sec->cmd_param[1], sec->cmd_param[2], buff); if (ret < 0) sec->cmd_state = SEC_CMD_STATUS_FAIL; else sec->cmd_state = SEC_CMD_STATUS_OK; sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); return; not_support: snprintf(buff, sizeof(buff), "%s", "NA"); sec->cmd_state = SEC_CMD_STATUS_NOT_APPLICABLE; sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); } static void get_calibration(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct fts_ts_info *info = container_of(sec, struct fts_ts_info, sec); char buff[SEC_CMD_STR_LEN] = { 0 }; sec_cmd_set_default_result(sec); if (!info->tdata->support_tclm_test) goto not_support; snprintf(buff, sizeof(buff), "%d", info->is_cal_done); info->is_cal_done = false; sec->cmd_state = SEC_CMD_STATUS_OK; sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); return; not_support: snprintf(buff, sizeof(buff), "%s", "NA"); sec->cmd_state = SEC_CMD_STATUS_NOT_APPLICABLE; sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); } #endif #ifdef CONFIG_GLOVE_TOUCH static void glove_mode(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct fts_ts_info *info = container_of(sec, struct fts_ts_info, sec); char buff[SEC_CMD_STR_LEN] = { 0 }; u8 regAdd[3] = {0}; sec_cmd_set_default_result(sec); if (sec->cmd_param[0] < 0 || sec->cmd_param[0] > 1) { snprintf(buff, sizeof(buff), "NG"); sec->cmd_state = SEC_CMD_STATUS_FAIL; } else { info->glove_enabled = sec->cmd_param[0]; if (info->fts_power_state != FTS_POWER_STATE_POWERDOWN && info->reinit_done) { if (info->glove_enabled) info->touch_functions = info->touch_functions | FTS_TOUCHTYPE_BIT_GLOVE | FTS_TOUCHTYPE_DEFAULT_ENABLE; else info->touch_functions = (info->touch_functions & (~FTS_TOUCHTYPE_BIT_GLOVE)) | FTS_TOUCHTYPE_DEFAULT_ENABLE; } regAdd[0] = FTS_CMD_SET_GET_TOUCHTYPE; regAdd[1] = (u8)(info->touch_functions & 0xFF); regAdd[2] = (u8)(info->touch_functions >> 8); fts_write_reg(info, ®Add[0], 3); snprintf(buff, sizeof(buff), "OK"); sec->cmd_state = SEC_CMD_STATUS_OK; } sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); sec->cmd_state = SEC_CMD_STATUS_WAITING; sec_cmd_set_cmd_exit(sec); input_info(true, &info->client->dev, "%s: %s\n", __func__, buff); } #endif static void clear_cover_mode(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct fts_ts_info *info = container_of(sec, struct fts_ts_info, sec); char buff[SEC_CMD_STR_LEN] = { 0 }; sec_cmd_set_default_result(sec); if (sec->cmd_param[0] < 0 || sec->cmd_param[0] > 3) { snprintf(buff, sizeof(buff), "NG"); sec->cmd_state = SEC_CMD_STATUS_FAIL; } else { if (sec->cmd_param[0] > 1) { info->flip_enable = true; info->cover_type = sec->cmd_param[1]; } else { info->flip_enable = false; } if (info->fts_power_state != FTS_POWER_STATE_POWERDOWN && info->reinit_done) { if (info->flip_enable) fts_set_cover_type(info, true); else fts_set_cover_type(info, false); } snprintf(buff, sizeof(buff), "OK"); sec->cmd_state = SEC_CMD_STATUS_OK; } sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); sec->cmd_state = SEC_CMD_STATUS_WAITING; sec_cmd_set_cmd_exit(sec); input_info(true, &info->client->dev, "%s: %s\n", __func__, buff); }; static void report_rate(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct fts_ts_info *info = container_of(sec, struct fts_ts_info, sec); char buff[SEC_CMD_STR_LEN] = { 0 }; u8 scan_rate; sec_cmd_set_default_result(sec); if (info->fts_power_state == FTS_POWER_STATE_POWERDOWN) { input_err(true, &info->client->dev, "%s: [ERROR] Touch is stopped\n", __func__); snprintf(buff, sizeof(buff), "NG"); sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); sec->cmd_state = SEC_CMD_STATUS_FAIL; goto out; } if (sec->cmd_param[0] < 0 || sec->cmd_param[0] > 255) { snprintf(buff, sizeof(buff), "NG"); sec->cmd_state = SEC_CMD_STATUS_FAIL; } else { scan_rate = sec->cmd_param[0]; fts_change_scan_rate(info, scan_rate); snprintf(buff, sizeof(buff), "OK"); sec->cmd_state = SEC_CMD_STATUS_OK; } sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); sec->cmd_state = SEC_CMD_STATUS_WAITING; out: sec_cmd_set_cmd_exit(sec); input_info(true, &info->client->dev, "%s: %s\n", __func__, buff); } #if !defined(CONFIG_SAMSUNG_PRODUCT_SHIP) static void interrupt_control(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct fts_ts_info *info = container_of(sec, struct fts_ts_info, sec); char buff[SEC_CMD_STR_LEN] = { 0 }; sec_cmd_set_default_result(sec); if (info->fts_power_state == FTS_POWER_STATE_POWERDOWN) { input_err(true, &info->client->dev, "%s: [ERROR] Touch is stopped\n", __func__); snprintf(buff, sizeof(buff), "NG"); sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); sec->cmd_state = SEC_CMD_STATUS_FAIL; goto out; } if (sec->cmd_param[0] < 0 || sec->cmd_param[0] > 1) { snprintf(buff, sizeof(buff), "NG"); sec->cmd_state = SEC_CMD_STATUS_FAIL; } else { int enables = sec->cmd_param[0]; if (enables) fts_irq_enable(info, true); else fts_irq_enable(info, false); snprintf(buff, sizeof(buff), "OK"); sec->cmd_state = SEC_CMD_STATUS_OK; } sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); sec->cmd_state = SEC_CMD_STATUS_WAITING; out: sec_cmd_set_cmd_exit(sec); input_info(true, &info->client->dev, "%s: %s\n", __func__, buff); } #endif static void set_wirelesscharger_mode(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct fts_ts_info *info = container_of(sec, struct fts_ts_info, sec); char buff[SEC_CMD_STR_LEN] = { 0 }; sec_cmd_set_default_result(sec); if (info->fts_power_state == FTS_POWER_STATE_POWERDOWN) { info->charger_mode = sec->cmd_param[0]; input_err(true, &info->client->dev, "%s: [ERROR] Touch is stopped\n", __func__); snprintf(buff, sizeof(buff), "NG"); sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); sec->cmd_state = SEC_CMD_STATUS_FAIL; goto out; } if (sec->cmd_param[0] < 0 || sec->cmd_param[0] > 3) { snprintf(buff, sizeof(buff), "NG"); sec->cmd_state = SEC_CMD_STATUS_FAIL; } else { info->charger_mode = sec->cmd_param[0]; fts_wirelesscharger_mode(info); snprintf(buff, sizeof(buff), "OK"); sec->cmd_state = SEC_CMD_STATUS_OK; } sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); sec->cmd_state = SEC_CMD_STATUS_WAITING; out: sec_cmd_set_cmd_exit(sec); input_info(true, &info->client->dev, "%s: %s\n", __func__, buff); }; /********************************************************************* * flag 1 : set edge handler * 2 : set (portrait, normal) edge zone data * 4 : set (portrait, normal) dead zone data * 8 : set landscape mode data * 16 : mode clear * data * 0x00, FFF (y start), FFF (y end), FF(direction) * 0x01, FFFF (edge zone) * 0x02, FF (up x), FF (down x), FFFF (y) * 0x03, FF (mode), FFF (edge), FFF (dead zone) * case * edge handler set : 0x00.... * booting time : 0x00... + 0x01... * normal mode : 0x02... (+0x01...) * landscape mode : 0x03... * landscape -> normal (if same with old data) : 0x03, 0 * landscape -> normal (etc) : 0x02.... + 0x03, 0 *********************************************************************/ void fts_set_grip_data_to_ic(struct fts_ts_info *info, u8 flag) { u8 data[4] = { 0 }; u8 regAdd[11] = {FTS_CMD_SET_FUNCTION_ONOFF, }; input_info(true, &info->client->dev, "%s: flag: %02X (clr,lan,nor,edg,han)\n", __func__, flag); memset(®Add[1], 0x00, 10); if (flag & G_SET_EDGE_HANDLER) { if (info->grip_edgehandler_direction == 0) { data[0] = 0x0; data[1] = 0x0; data[2] = 0x0; data[3] = 0x0; } else { data[0] = (info->grip_edgehandler_start_y >> 4) & 0xFF; data[1] = (info->grip_edgehandler_start_y << 4 & 0xF0) | ((info->grip_edgehandler_end_y >> 8) & 0xF); data[2] = info->grip_edgehandler_end_y & 0xFF; data[3] = info->grip_edgehandler_direction & 0x3; } regAdd[1] = FTS_FUNCTION_EDGE_HANDLER; regAdd[2] = data[0]; regAdd[3] = data[1]; regAdd[4] = data[2]; regAdd[5] = data[3]; fts_write_reg(info, regAdd, 6); } if (flag & G_SET_EDGE_ZONE) { /* ex) C1 07 00 3E 00 3E * - 0x003E(60) px : Grip Right zone * - 0x003E(60) px : Grip Left zone */ regAdd[1] = FTS_FUNCTION_EDGE_AREA; regAdd[2] = (info->grip_edge_range >> 8) & 0xFF; regAdd[3] = info->grip_edge_range & 0xFF; regAdd[4] = (info->grip_edge_range >> 8) & 0xFF; regAdd[5] = info->grip_edge_range & 0xFF; fts_write_reg(info, regAdd, 6); } if (flag & G_SET_NORMAL_MODE) { /* ex) C1 08 1E 1E 00 00 * - 0x1E (30) px : upper X range * - 0x1E (30) px : lower X range * - 0x0000 (0) px : division Y */ regAdd[1] = FTS_FUNCTION_DEAD_ZONE; regAdd[2] = info->grip_deadzone_up_x & 0xFF; regAdd[3] = info->grip_deadzone_dn_x & 0xFF; regAdd[4] = (info->grip_deadzone_y >> 8) & 0xFF; regAdd[5] = info->grip_deadzone_y & 0xFF; fts_write_reg(info, regAdd, 6); } if (flag & G_SET_LANDSCAPE_MODE) { /* ex) C1 09 01 00 3C 00 3C 00 1E * - 0x01 : horizontal mode * - 0x03C (60) px : Grip zone range (Right) * - 0x03C (60) px : Grip zone range (Left) * - 0x01E (30) px : Reject zone range (Left/Right) */ regAdd[1] = FTS_FUNCTION_LANDSCAPE_MODE; regAdd[2] = info->grip_landscape_mode; regAdd[3] = (info->grip_landscape_edge >> 8) & 0xFF; regAdd[4] = info->grip_landscape_edge & 0xFF; regAdd[5] = (info->grip_landscape_edge >> 8) & 0xFF; regAdd[6] = info->grip_landscape_edge & 0xFF; regAdd[7] = (info->grip_landscape_deadzone >> 8) & 0xFF; regAdd[8] = info->grip_landscape_deadzone & 0xFF; fts_write_reg(info, regAdd, 9); /*ex) C1 0A 01 00 3C 00 3C 00 1E 00 1E * - 0x01(1) : Enable function * - 0x003C (60) px : Grip Top zone range * - 0x001E (60) px : Grip Bottom zone range * - 0x001E (30) px : Reject Top zone range * - 0x001E (30) px : Reject Bottom zone range */ regAdd[1] = FTS_FUNCTION_LANDSCAPE_TOP_BOTTOM; regAdd[2] = info->grip_landscape_mode; regAdd[3] = (info->grip_landscape_top_gripzone >> 8)& 0xFF; regAdd[4] = info->grip_landscape_top_gripzone & 0xFF; regAdd[5] = (info->grip_landscape_bottom_gripzone >> 8)& 0xFF; regAdd[6] = info->grip_landscape_bottom_gripzone & 0xFF; regAdd[7] = (info->grip_landscape_top_deadzone >> 8)& 0xFF; regAdd[8] = info->grip_landscape_top_deadzone & 0xFF; regAdd[9] = (info->grip_landscape_bottom_deadzone >> 8)& 0xFF; regAdd[10] = info->grip_landscape_bottom_deadzone & 0xFF; fts_write_reg(info, regAdd, 11); } if (flag & G_CLR_LANDSCAPE_MODE) { memset(®Add[1], 0x00, 10); /* ex) C1 09 00 00 00 00 00 00 00 * - 0x00 : Apply previous vertical mode value for grip zone and reject zone range */ regAdd[1] = FTS_FUNCTION_LANDSCAPE_MODE; regAdd[2] = info->grip_landscape_mode; fts_write_reg(info, regAdd, 9); /*ex) C1 0A 00 00 00 00 00 00 00 00 00 * - Disable function */ regAdd[1] = FTS_FUNCTION_LANDSCAPE_TOP_BOTTOM; fts_write_reg(info, regAdd, 11); } } /* * index * 0 : set edge handler * 1 : portrait (normal) mode * 2 : landscape mode * data * 0, X (direction), X (y start), X (y end) * direction : 0 (off), 1 (left), 2 (right) * ex) echo set_grip_data,0,2,600,900 > cmd * * * 1, X (edge zone), X (dead zone up x), X (dead zone down x), X (dead zone y) * ex) echo set_grip_data,1,200,10,50,1500 > cmd * * 2, 1 (landscape mode), X (edge zone), X (dead zone), X (dead zone top y), X (dead zone bottom y) * ex) echo set_grip_data,2,1,200,100,120,0 > cmd * * 2, 0 (portrait mode) * ex) echo set_grip_data,2,0 > cmd */ static void set_grip_data(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct fts_ts_info *info = container_of(sec, struct fts_ts_info, sec); char buff[SEC_CMD_STR_LEN] = { 0 }; u8 mode = G_NONE; sec_cmd_set_default_result(sec); memset(buff, 0, sizeof(buff)); mutex_lock(&info->device_mutex); if (sec->cmd_param[0] == 0) { // edge handler if (sec->cmd_param[1] == 0) { // clear info->grip_edgehandler_direction = 0; } else if (sec->cmd_param[1] < 3) { info->grip_edgehandler_direction = sec->cmd_param[1]; info->grip_edgehandler_start_y = sec->cmd_param[2]; info->grip_edgehandler_end_y = sec->cmd_param[3]; } else { input_err(true, &info->client->dev, "%s: cmd1 is abnormal, %d (%d)\n", __func__, sec->cmd_param[1], __LINE__); goto err_grip_data; } mode = mode | G_SET_EDGE_HANDLER; fts_set_grip_data_to_ic(info, mode); } else if (sec->cmd_param[0] == 1) { // normal mode if (info->grip_edge_range != sec->cmd_param[1]) mode = mode | G_SET_EDGE_ZONE; info->grip_edge_range = sec->cmd_param[1]; info->grip_deadzone_up_x = sec->cmd_param[2]; info->grip_deadzone_dn_x = sec->cmd_param[3]; info->grip_deadzone_y = sec->cmd_param[4]; mode = mode | G_SET_NORMAL_MODE; if (info->grip_landscape_mode == 1) { info->grip_landscape_mode = 0; mode = mode | G_CLR_LANDSCAPE_MODE; } fts_set_grip_data_to_ic(info, mode); } else if (sec->cmd_param[0] == 2) { // landscape mode if (sec->cmd_param[1] == 0) { // normal mode info->grip_landscape_mode = 0; mode = mode | G_CLR_LANDSCAPE_MODE; } else if (sec->cmd_param[1] == 1) { info->grip_landscape_mode = 1; info->grip_landscape_edge = sec->cmd_param[2]; info->grip_landscape_deadzone = sec->cmd_param[3]; info->grip_landscape_top_deadzone = sec->cmd_param[4]; info->grip_landscape_bottom_deadzone = sec->cmd_param[5]; info->grip_landscape_top_gripzone = sec->cmd_param[6]; info->grip_landscape_bottom_gripzone = sec->cmd_param[7]; mode = mode | G_SET_LANDSCAPE_MODE; } else { input_err(true, &info->client->dev, "%s: cmd1 is abnormal, %d (%d)\n", __func__, sec->cmd_param[1], __LINE__); goto err_grip_data; } fts_set_grip_data_to_ic(info, mode); } else { input_err(true, &info->client->dev, "%s: cmd0 is abnormal, %d", __func__, sec->cmd_param[0]); goto err_grip_data; } mutex_unlock(&info->device_mutex); snprintf(buff, sizeof(buff), "OK"); sec->cmd_state = SEC_CMD_STATUS_OK; sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); sec_cmd_set_cmd_exit(sec); return; err_grip_data: mutex_unlock(&info->device_mutex); snprintf(buff, sizeof(buff), "NG"); sec->cmd_state = SEC_CMD_STATUS_FAIL; sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); sec_cmd_set_cmd_exit(sec); } static void dead_zone_enable(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct fts_ts_info *info = container_of(sec, struct fts_ts_info, sec); char buff[SEC_CMD_STR_LEN] = { 0 }; u8 regAdd[3] = {FTS_CMD_SET_FUNCTION_ONOFF, FTS_FUNCTION_ENABLE_DEAD_ZONE, 0x00}; int ret; sec_cmd_set_default_result(sec); if (sec->cmd_param[0] < 0 || sec->cmd_param[0] > 1) { snprintf(buff, sizeof(buff), "NG"); sec->cmd_state = SEC_CMD_STATUS_FAIL; } else { if (sec->cmd_param[0] == 0) regAdd[2] = 0x01; /* dead zone disable */ else regAdd[2] = 0x00; /* dead zone enable */ ret = info->fts_write_reg(info, regAdd, 3); if (ret < 0) input_err(true, &info->client->dev, "%s: failed. ret: %d\n", __func__, ret); else input_info(true, &info->client->dev, "%s: reg:%d, ret: %d\n", __func__, sec->cmd_param[0], ret); snprintf(buff, sizeof(buff), "OK"); sec->cmd_state = SEC_CMD_STATUS_OK; } sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); sec_cmd_set_cmd_exit(sec); input_info(true, &info->client->dev, "%s: %s\n", __func__, buff); } static void drawing_test_enable(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct fts_ts_info *info = container_of(sec, struct fts_ts_info, sec); char buff[SEC_CMD_STR_LEN] = { 0 }; sec_cmd_set_default_result(sec); snprintf(buff, sizeof(buff), "NA"); sec->cmd_state = SEC_CMD_STATUS_NOT_APPLICABLE; sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); sec_cmd_set_cmd_exit(sec); input_info(true, &info->client->dev, "%s: %s\n", __func__, buff); } static void spay_enable(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct fts_ts_info *info = container_of(sec, struct fts_ts_info, sec); char buff[SEC_CMD_STR_LEN] = { 0 }; sec_cmd_set_default_result(sec); if (sec->cmd_param[0]) info->lowpower_flag |= FTS_MODE_SPAY; else info->lowpower_flag &= ~FTS_MODE_SPAY; snprintf(buff, sizeof(buff), "OK"); sec->cmd_state = SEC_CMD_STATUS_OK; sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); sec_cmd_set_cmd_exit(sec); input_info(true, &info->client->dev, "%s: %s\n", __func__, buff); } static void aot_enable(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct fts_ts_info *info = container_of(sec, struct fts_ts_info, sec); char buff[SEC_CMD_STR_LEN] = { 0 }; sec_cmd_set_default_result(sec); if (sec->cmd_param[0]) info->lowpower_flag |= FTS_MODE_DOUBLETAP_WAKEUP; else info->lowpower_flag &= ~FTS_MODE_DOUBLETAP_WAKEUP; snprintf(buff, sizeof(buff), "OK"); sec->cmd_state = SEC_CMD_STATUS_OK; sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); sec_cmd_set_cmd_exit(sec); input_info(true, &info->client->dev, "%s: %d\n", __func__, sec->cmd_param[0]); } static void aod_enable(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct fts_ts_info *info = container_of(sec, struct fts_ts_info, sec); char buff[SEC_CMD_STR_LEN] = { 0 }; sec_cmd_set_default_result(sec); if (sec->cmd_param[0]) info->lowpower_flag |= FTS_MODE_AOD; else info->lowpower_flag &= ~FTS_MODE_AOD; snprintf(buff, sizeof(buff), "OK"); sec->cmd_state = SEC_CMD_STATUS_OK; sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); sec_cmd_set_cmd_exit(sec); input_info(true, &info->client->dev, "%s: %d\n", __func__, sec->cmd_param[0]); } static void singletap_enable(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct fts_ts_info *info = container_of(sec, struct fts_ts_info, sec); char buff[SEC_CMD_STR_LEN] = { 0 }; sec_cmd_set_default_result(sec); if (sec->cmd_param[0]) info->lowpower_flag |= FTS_MODE_SINGLETAP; else info->lowpower_flag &= ~FTS_MODE_SINGLETAP; snprintf(buff, sizeof(buff), "OK"); sec->cmd_state = SEC_CMD_STATUS_OK; sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); sec_cmd_set_cmd_exit(sec); input_info(true, &info->client->dev, "%s: %d\n", __func__, sec->cmd_param[0]); } static void set_aod_rect(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct fts_ts_info *info = container_of(sec, struct fts_ts_info, sec); char buff[SEC_CMD_STR_LEN] = { 0 }; u8 data[8] = {0, }; int i, ret = -1; sec_cmd_set_default_result(sec); #if !defined(CONFIG_SAMSUNG_PRODUCT_SHIP) input_info(true, &info->client->dev, "%s: w:%d, h:%d, x:%d, y:%d\n", __func__, sec->cmd_param[0], sec->cmd_param[1], sec->cmd_param[2], sec->cmd_param[3]); #endif for (i = 0; i < 4; i++) { data[i * 2] = sec->cmd_param[i] & 0xFF; data[i * 2 + 1] = (sec->cmd_param[i] >> 8) & 0xFF; info->rect_data[i] = sec->cmd_param[i]; } #ifdef FTS_SUPPORT_SPONGELIB if (!info->use_sponge) goto NG; ret = info->fts_write_to_sponge(info, FTS_CMD_SPONGE_OFFSET_AOD_RECT, data, sizeof(data)); #endif if (ret < 0) { input_err(true, &info->client->dev, "%s: failed. ret: %d\n", __func__, ret); goto NG; } if (info->fts_power_state == FTS_POWER_STATE_LOWPOWER) { if (sec->cmd_param[0] == 0 && sec->cmd_param[1] == 0 && sec->cmd_param[2] == 0 && sec->cmd_param[3] == 0) { input_info(true, &info->client->dev, "%s: sync -> async base scan\n", __func__); ret = fts_set_hsync_scanmode(info, FTS_CMD_LPM_ASYNC_SCAN); } else { input_info(true, &info->client->dev, "%s: sync base scan\n", __func__); ret = fts_set_hsync_scanmode(info, FTS_CMD_LPM_SYNC_SCAN); } if (ret <= 0) { input_err(true, &info->client->dev, "%s: Failed to send command!", __func__); goto NG; } } snprintf(buff, sizeof(buff), "OK"); sec->cmd_state = SEC_CMD_STATUS_OK; sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); sec_cmd_set_cmd_exit(sec); return; NG: snprintf(buff, sizeof(buff), "NG"); sec->cmd_state = SEC_CMD_STATUS_FAIL; sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); sec_cmd_set_cmd_exit(sec); } static void get_aod_rect(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct fts_ts_info *info = container_of(sec, struct fts_ts_info, sec); char buff[SEC_CMD_STR_LEN] = { 0 }; u8 data[8] = {0, }; u16 rect_data[4] = {0, }; int i, ret = -1; sec_cmd_set_default_result(sec); #ifdef FTS_SUPPORT_SPONGELIB if (!info->use_sponge) goto NG; ret = info->fts_read_from_sponge(info, FTS_CMD_SPONGE_OFFSET_AOD_RECT, data, sizeof(data)); #endif if (ret < 0) { input_err(true, &info->client->dev, "%s: failed. ret: %d\n", __func__, ret); goto NG; } for (i = 0; i < 4; i++) rect_data[i] = (data[i * 2 + 1] & 0xFF) << 8 | (data[i * 2] & 0xFF); #if !defined(CONFIG_SAMSUNG_PRODUCT_SHIP) input_info(true, &info->client->dev, "%s: w:%d, h:%d, x:%d, y:%d\n", __func__, rect_data[0], rect_data[1], rect_data[2], rect_data[3]); #endif snprintf(buff, sizeof(buff), "OK"); sec->cmd_state = SEC_CMD_STATUS_OK; sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); sec_cmd_set_cmd_exit(sec); return; NG: snprintf(buff, sizeof(buff), "NG"); sec->cmd_state = SEC_CMD_STATUS_FAIL; sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); sec_cmd_set_cmd_exit(sec); } static void fod_enable(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct fts_ts_info *info = container_of(sec, struct fts_ts_info, sec); int ret = 0; char buff[SEC_CMD_STR_LEN] = { 0 }; sec_cmd_set_default_result(sec); if (sec->cmd_param[0]) info->lowpower_flag |= FTS_MODE_PRESS; else info->lowpower_flag &= ~FTS_MODE_PRESS; info->press_prop = !!sec->cmd_param[1]; input_info(true, &info->client->dev, "%s: %s, fast:%d, 0x%02X\n", __func__, sec->cmd_param[0] ? "on" : "off", info->press_prop, info->lowpower_flag); ret = info->fts_write_to_sponge(info, FTS_CMD_SPONGE_OFFSET_MODE, &info->lowpower_flag, sizeof(info->lowpower_flag)); if (ret < 0) { input_err(true, &info->client->dev, "%s: failed. ret: %d\n", __func__, ret); snprintf(buff, sizeof(buff), "%s", "NG"); sec->cmd_state = SEC_CMD_STATUS_FAIL; goto out; } fts_set_press_property(info); fts_set_fod_finger_merge(info); snprintf(buff, sizeof(buff), "OK"); sec->cmd_state = SEC_CMD_STATUS_OK; out: sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); sec_cmd_set_cmd_exit(sec); } int fts_set_fod_rect(struct fts_ts_info *info) { int i, ret; u8 data[8]; u32 sum = 0; for (i = 0; i < 4; i++) { data[i * 2] = info->fod_rect_data[i] & 0xFF; data[i * 2 + 1] = (info->fod_rect_data[i] >> 8) & 0xFF; sum += info->fod_rect_data[i]; } if (!sum) /* no data */ return 0; input_info(true, &info->client->dev, "%s: l:%d, t:%d, r:%d, b:%d\n", __func__, info->fod_rect_data[0], info->fod_rect_data[1], info->fod_rect_data[2], info->fod_rect_data[3]); ret = info->fts_write_to_sponge(info, FTS_CMD_SPONGE_FOD_RECT, data, sizeof(data)); if (ret < 0) input_err(true, &info->client->dev, "%s: failed. ret: %d\n", __func__, ret); return ret; } static void set_fod_rect(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct fts_ts_info *info = container_of(sec, struct fts_ts_info, sec); char buff[SEC_CMD_STR_LEN] = { 0 }; int i, ret; sec_cmd_set_default_result(sec); if (sec->cmd_param[0] > info->board->max_x || sec->cmd_param[1] > info->board->max_y || sec->cmd_param[2] > info->board->max_x || sec->cmd_param[3] > info->board->max_y) { input_err(true, &info->client->dev, "%s: Abnormal fod_rect data\n", __func__); goto NG; } input_info(true, &info->client->dev, "%s: l:%d, t:%d, r:%d, b:%d\n", __func__, sec->cmd_param[0], sec->cmd_param[1], sec->cmd_param[2], sec->cmd_param[3]); for (i = 0; i < 4; i++) info->fod_rect_data[i] = sec->cmd_param[i]; ret = fts_set_fod_rect(info); if (ret < 0) { input_err(true, &info->client->dev, "%s: failed. ret: %d\n", __func__, ret); goto NG; } snprintf(buff, sizeof(buff), "OK"); sec->cmd_state = SEC_CMD_STATUS_OK; sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); sec_cmd_set_cmd_exit(sec); return; NG: snprintf(buff, sizeof(buff), "NG"); sec->cmd_state = SEC_CMD_STATUS_FAIL; sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); sec_cmd_set_cmd_exit(sec); } /* * Enable or disable external_noise_mode * * If mode has EXT_NOISE_MODE_MAX, * then write enable cmd for all enabled mode. (set as ts->external_noise_mode bit value) * This routine need after IC power reset. TSP IC need to be re-wrote all enabled modes. * * Else if mode has specific value like EXT_NOISE_MODE_MONITOR, * then write enable/disable cmd about for that mode's latest setting value. * * If you want to add new mode, * please define new enum value like EXT_NOISE_MODE_MONITOR, * then set cmd for that mode like below. (it is in this function) * noise_mode_cmd[EXT_NOISE_MODE_MONITOR] = SEC_TS_CMD_SET_MONITOR_NOISE_MODE; */ int fts_set_external_noise_mode(struct fts_ts_info *info, u8 mode) { int i, ret, fail_count = 0; u8 mode_bit_to_set, check_bit, mode_enable; u8 noise_mode_cmd[EXT_NOISE_MODE_MAX] = { 0 }; u8 regAdd[3] = {FTS_CMD_SET_FUNCTION_ONOFF, 0x00, 0x00}; if (info->fts_power_state == FTS_POWER_STATE_POWERDOWN) { input_err(true, &info->client->dev, "%s: Touch is stopped!\n", __func__); return -ENODEV; } if (mode == EXT_NOISE_MODE_MAX) { /* write all enabled mode */ mode_bit_to_set = info->external_noise_mode; } else { /* make enable or disable the specific mode */ mode_bit_to_set = 1 << mode; } input_info(true, &info->client->dev, "%s: %sable %d\n", __func__, info->external_noise_mode & mode_bit_to_set ? "en" : "dis", mode_bit_to_set); /* set cmd for each mode */ noise_mode_cmd[EXT_NOISE_MODE_MONITOR] = FTS_FUNCTION_SET_MONITOR_NOISE_MODE; /* write mode */ for (i = EXT_NOISE_MODE_NONE + 1; i < EXT_NOISE_MODE_MAX; i++) { check_bit = 1 << i; if (mode_bit_to_set & check_bit) { mode_enable = !!(info->external_noise_mode & check_bit); regAdd[1] = noise_mode_cmd[i]; regAdd[2] = mode_enable; ret = info->fts_write_reg(info, regAdd, 3); if (ret < 0) { input_err(true, &info->client->dev, "%s: failed to set %02X %02X %02X\n", __func__, regAdd[0], regAdd[1], regAdd[2]); fail_count++; } } } if (fail_count != 0) return -EIO; else return 0; } /* * Enable or disable specific external_noise_mode (sec_cmd) * * This cmd has 2 params. * param 0 : the mode that you want to change. * param 1 : enable or disable the mode. * * For example, * enable EXT_NOISE_MODE_MONITOR mode, * write external_noise_mode,1,1 * disable EXT_NOISE_MODE_MONITOR mode, * write external_noise_mode,1,0 */ static void external_noise_mode(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct fts_ts_info *info = container_of(sec, struct fts_ts_info, sec); char buff[SEC_CMD_STR_LEN] = { 0 }; int ret; sec_cmd_set_default_result(sec); if (sec->cmd_param[0] <= EXT_NOISE_MODE_NONE || sec->cmd_param[0] >= EXT_NOISE_MODE_MAX || sec->cmd_param[1] < 0 || sec->cmd_param[1] > 1) { input_err(true, &info->client->dev, "%s: not support param\n", __func__); goto NG; } if (sec->cmd_param[1] == 1) info->external_noise_mode |= 1 << sec->cmd_param[0]; else info->external_noise_mode &= ~(1 << sec->cmd_param[0]); ret = fts_set_external_noise_mode(info, sec->cmd_param[0]); if (ret < 0) goto NG; snprintf(buff, sizeof(buff), "OK"); sec->cmd_state = SEC_CMD_STATUS_OK; sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); sec_cmd_set_cmd_exit(sec); return; NG: snprintf(buff, sizeof(buff), "NG"); sec->cmd_state = SEC_CMD_STATUS_FAIL; sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); sec_cmd_set_cmd_exit(sec); } static void brush_enable(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct fts_ts_info *info = container_of(sec, struct fts_ts_info, sec); char buff[SEC_CMD_STR_LEN] = { 0 }; u8 regAdd[3] = {FTS_CMD_SET_FUNCTION_ONOFF, FTS_FUNCTION_ENABLE_BRUSH_MODE, 0x00}; int ret; sec_cmd_set_default_result(sec); if (sec->cmd_param[0] < 0 || sec->cmd_param[0] > 1) { snprintf(buff, sizeof(buff), "NG"); sec->cmd_state = SEC_CMD_STATUS_FAIL; goto out; } info->brush_mode = sec->cmd_param[0]; if (info->fts_power_state == FTS_POWER_STATE_POWERDOWN) { input_err(true, &info->client->dev, "%s: [ERROR] Touch is stopped\n", __func__); snprintf(buff, sizeof(buff), "NG"); sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); sec->cmd_state = SEC_CMD_STATUS_FAIL; goto out; } input_info(true, &info->client->dev, "%s: set brush mode %s\n", __func__, info->brush_mode ? "enable" : "disable"); if (info->brush_mode == 0) regAdd[2] = 0x00; /* 0: Disable Artcanvas min phi mode */ else regAdd[2] = 0x01; /* 1: Enable Artcanvas min phi mode */ ret = info->fts_write_reg(info, ®Add[0], 3); if (ret < 0) { input_err(true, &info->client->dev, "%s: failed to set brush mode\n", __func__); snprintf(buff, sizeof(buff), "NG"); sec->cmd_state = SEC_CMD_STATUS_FAIL; goto out; } snprintf(buff, sizeof(buff), "OK"); sec->cmd_state = SEC_CMD_STATUS_OK; out: sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); sec_cmd_set_cmd_exit(sec); input_info(true, &info->client->dev, "%s: %s\n", __func__, buff); } static void set_touchable_area(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct fts_ts_info *info = container_of(sec, struct fts_ts_info, sec); char buff[SEC_CMD_STR_LEN] = { 0 }; u8 regAdd[3] = {FTS_CMD_SET_FUNCTION_ONOFF, FTS_FUNCTION_SET_TOUCHABLE_AREA, 0x00}; int ret; sec_cmd_set_default_result(sec); if (sec->cmd_param[0] < 0 || sec->cmd_param[0] > 1) { snprintf(buff, sizeof(buff), "NG"); sec->cmd_state = SEC_CMD_STATUS_FAIL; goto out; } info->touchable_area = sec->cmd_param[0]; if (info->fts_power_state == FTS_POWER_STATE_POWERDOWN) { input_err(true, &info->client->dev, "%s: [ERROR] Touch is stopped\n", __func__); snprintf(buff, sizeof(buff), "NG"); sec->cmd_state = SEC_CMD_STATUS_FAIL; goto out; } input_info(true, &info->client->dev, "%s: set 16:9 mode %s\n", __func__, info->touchable_area ? "enable" : "disable"); if (info->touchable_area == 0) regAdd[2] = 0x00; /* 0: Disable 16:9 mode */ else regAdd[2] = 0x01; /* 1: Enable 16:9 mode */ ret = info->fts_write_reg(info, ®Add[0], 3); if (ret < 0) { input_err(true, &info->client->dev, "%s: failed to set 16:9 mode\n", __func__); snprintf(buff, sizeof(buff), "NG"); sec->cmd_state = SEC_CMD_STATUS_FAIL; goto out; } snprintf(buff, sizeof(buff), "OK"); sec->cmd_state = SEC_CMD_STATUS_OK; out: sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); sec_cmd_set_cmd_exit(sec); input_info(true, &info->client->dev, "%s: %s\n", __func__, buff); } static void debug(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct fts_ts_info *info = container_of(sec, struct fts_ts_info, sec); char buff[SEC_CMD_STR_LEN] = { 0 }; sec_cmd_set_default_result(sec); info->debug_string = sec->cmd_param[0]; input_info(true, &info->client->dev, "%s: command is %d\n", __func__, info->debug_string); sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); sec->cmd_state = SEC_CMD_STATUS_WAITING; sec_cmd_set_cmd_exit(sec); input_info(true, &info->client->dev, "%s: %s\n", __func__, buff); } static void run_force_calibration(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct fts_ts_info *info = container_of(sec, struct fts_ts_info, sec); char buff[SEC_CMD_STR_LEN] = { 0 }; bool touch_on = false; sec_cmd_set_default_result(sec); if (info->fts_power_state == FTS_POWER_STATE_POWERDOWN) { input_err(true, &info->client->dev, "%s: [ERROR] Touch is stopped\n", __func__); snprintf(buff, sizeof(buff), "NG"); sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); sec->cmd_state = SEC_CMD_STATUS_FAIL; #ifdef TCLM_CONCEPT info->tdata->external_factory = false; #endif return; } if (info->rawdata_read_lock == 1) { input_err(true, &info->client->dev, "%s: ramdump mode is running, %d\n", __func__, info->rawdata_read_lock); goto autotune_fail; } if (info->touch_count > 0) { touch_on = true; input_err(true, &info->client->dev, "%s: finger on touch(%d)\n", __func__, info->touch_count); } info->fts_systemreset(info, 0); fts_release_all_finger(info); if (touch_on) { input_err(true, &info->client->dev, "%s: finger! do not run autotune\n", __func__); } else { input_info(true, &info->client->dev, "%s: run autotune\n", __func__); input_err(true, &info->client->dev, "%s: RUN OFFSET CALIBRATION\n", __func__); if (fts_execute_autotune(info, true) < 0) { fts_set_scanmode(info, info->scan_mode); goto autotune_fail; } #ifdef TCLM_CONCEPT /* devide tclm case */ sec_tclm_case(info->tdata, sec->cmd_param[0]); input_info(true, &info->client->dev, "%s: param, %d, %c, %d\n", __func__, sec->cmd_param[0], sec->cmd_param[0], info->tdata->root_of_calibration); if (sec_execute_tclm_package(info->tdata, 1) < 0) input_err(true, &info->client->dev, "%s: sec_execute_tclm_package\n", __func__); sec_tclm_root_of_cal(info->tdata, CALPOSITION_NONE); #endif } fts_set_scanmode(info, info->scan_mode); if (touch_on) { snprintf(buff, sizeof(buff), "NG"); sec->cmd_state = SEC_CMD_STATUS_FAIL; } else { snprintf(buff, sizeof(buff), "OK"); sec->cmd_state = SEC_CMD_STATUS_OK; } sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); #ifdef TCLM_CONCEPT info->tdata->external_factory = false; #endif input_info(true, &info->client->dev, "%s: %s\n", __func__, buff); return; autotune_fail: #ifdef TCLM_CONCEPT info->tdata->external_factory = false; #endif fts_interrupt_set(info, INT_ENABLE); snprintf(buff, sizeof(buff), "NG"); sec->cmd_state = SEC_CMD_STATUS_FAIL; sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); input_info(true, &info->client->dev, "%s: %s\n", __func__, buff); } static void fix_active_mode(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct fts_ts_info *info = container_of(sec, struct fts_ts_info, sec); char buff[SEC_CMD_STR_LEN] = { 0 }; sec_cmd_set_default_result(sec); if (sec->cmd_param[0] < 0 || sec->cmd_param[0] > 1) { snprintf(buff, sizeof(buff), "NG"); sec->cmd_state = SEC_CMD_STATUS_FAIL; } else { if (info->fts_power_state == FTS_POWER_STATE_ACTIVE) fts_fix_active_mode(info, !!sec->cmd_param[0]); info->fix_active_mode = !!sec->cmd_param[0]; } snprintf(buff, sizeof(buff), "OK"); sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); sec->cmd_state = SEC_CMD_STATUS_WAITING; sec_cmd_set_cmd_exit(sec); input_info(true, &info->client->dev, "%s: %s\n", __func__, buff); } static void touch_aging_mode(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct fts_ts_info *info = container_of(sec, struct fts_ts_info, sec); char buff[SEC_CMD_STR_LEN] = { 0 }; char regAdd[3]; sec_cmd_set_default_result(sec); if (sec->cmd_param[0] < 0 || sec->cmd_param[0] > 1) { snprintf(buff, sizeof(buff), "NG"); sec->cmd_state = SEC_CMD_STATUS_FAIL; } else { info->touch_aging_mode = sec->cmd_param[0]; if (info->touch_aging_mode) { regAdd[0] = 0xA0; regAdd[1] = 0x03; regAdd[2] = 0x20; info->fts_write_reg(info, ®Add[0], 3); } else { fts_reinit(info, false); } } snprintf(buff, sizeof(buff), "OK"); sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); sec->cmd_state = SEC_CMD_STATUS_WAITING; sec_cmd_set_cmd_exit(sec); input_info(true, &info->client->dev, "%s: %s\n", __func__, buff); } static void run_sram_test(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct fts_ts_info *info = container_of(sec, struct fts_ts_info, sec); char buff[SEC_CMD_STR_LEN]; u8 regAdd; u8 data[FTS_EVENT_SIZE]; int rc, retry = 0; sec_cmd_set_default_result(sec); info->fts_systemreset(info, 0); fts_interrupt_set(info, INT_DISABLE); mutex_lock(&info->wait_for); regAdd = FTS_CMD_RUN_SRAM_TEST; rc = info->fts_write_reg(info, ®Add, 1); if (rc < 0) { input_err(true, &info->client->dev, "%s: failed to write cmd\n", __func__); goto error; } fts_delay(300); memset(data, 0x0, FTS_EVENT_SIZE); rc = -EIO; regAdd = FTS_READ_ONE_EVENT; while (info->fts_read_reg(info, ®Add, 1, data, FTS_EVENT_SIZE) > 0) { if (data[0] != 0x00) input_info(true, &info->client->dev, "%s: event %02X, %02X, %02X, %02X, %02X, %02X, %02X, %02X\n", __func__, data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7]); if (data[0] == FTS_EVENT_PASS_REPORT && data[1] == FTS_EVENT_SRAM_TEST_RESULT) { rc = 0; /* PASS */ break; } else if (data[0] == FTS_EVENT_ERROR_REPORT && data[1] == FTS_EVENT_SRAM_TEST_RESULT) { rc = 1; /* FAIL */ break; } if (retry++ > FTS_RETRY_COUNT * 25) { input_err(true, &info->client->dev, "%s: Time Over (%02X,%02X,%02X,%02X,%02X,%02X,%02X,%02X)\n", __func__, data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7]); break; } fts_delay(20); } error: mutex_unlock(&info->wait_for); if (rc < 0) { snprintf(buff, sizeof(buff), "NG"); sec->cmd_state = SEC_CMD_STATUS_FAIL; } else { snprintf(buff, sizeof(buff), "%d", rc); sec->cmd_state = SEC_CMD_STATUS_OK; } if (sec->cmd_all_factory_state == SEC_CMD_STATUS_RUNNING) sec_cmd_set_cmd_result_all(sec, buff, strnlen(buff, sizeof(buff)), "SRAM"); sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); fts_reinit(info, false); fts_interrupt_set(info, INT_ENABLE); } static void set_rear_selfie_mode(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct fts_ts_info *info = container_of(sec, struct fts_ts_info, sec); char buff[SEC_CMD_STR_LEN] = { 0 }; sec_cmd_set_default_result(sec); if (sec->cmd_param[0] < 0 || sec->cmd_param[0] > 1) { snprintf(buff, sizeof(buff), "NG"); sec->cmd_state = SEC_CMD_STATUS_FAIL; } else { info->rear_selfie_mode = sec->cmd_param[0]; snprintf(buff, sizeof(buff), "OK"); } sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); sec->cmd_state = SEC_CMD_STATUS_WAITING; sec_cmd_set_cmd_exit(sec); input_info(true, &info->client->dev, "%s: %s\n", __func__, buff); } static void ear_detect_enable(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct fts_ts_info *info = container_of(sec, struct fts_ts_info, sec); char buff[SEC_CMD_STR_LEN] = { 0 }; u8 data[2]; int ret; sec_cmd_set_default_result(sec); if (!info->board->support_ear_detect || sec->cmd_param[0] < 0 || sec->cmd_param[0] > 3) { snprintf(buff, sizeof(buff), "NG"); sec->cmd_state = SEC_CMD_STATUS_FAIL; } else { info->ed_enable = sec->cmd_param[0]; snprintf(buff, sizeof(buff), "OK"); data[0] = FTS_CMD_SET_EAR_DETECT; data[1] = info->ed_enable; ret = fts_write_reg(info, data, 2); input_info(true, &info->client->dev, "%s: %s, ret = %d\n", __func__, info->ed_enable ? "enable" : "disable", ret); } if (info->board->hw_i2c_reset) { cancel_delayed_work_sync(&info->fw_reset_work); if (info->ed_enable == 3) { info->fw_reset_cmd = 0x01; } else { info->fw_reset_cmd = 0x00; } schedule_work(&info->fw_reset_work.work); } sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); sec->cmd_state = SEC_CMD_STATUS_WAITING; sec_cmd_set_cmd_exit(sec); input_info(true, &info->client->dev, "%s: %s\n", __func__, buff); } static void pocket_mode_enable(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct fts_ts_info *info = container_of(sec, struct fts_ts_info, sec); char buff[SEC_CMD_STR_LEN] = { 0 }; u8 data[2]; int ret; sec_cmd_set_default_result(sec); if (!info->board->support_ear_detect || sec->cmd_param[0] < 0 || sec->cmd_param[0] > 1) { snprintf(buff, sizeof(buff), "NG"); sec->cmd_state = SEC_CMD_STATUS_FAIL; } else { info->pocket_mode = sec->cmd_param[0]; snprintf(buff, sizeof(buff), "OK"); data[0] = FTS_CMD_SET_POCKET_MODE; data[1] = info->pocket_mode; ret = fts_write_reg(info, data, 2); input_info(true, &info->client->dev, "%s: %s, ret = %d\n", __func__, info->pocket_mode ? "enable" : "disable", ret); } sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); sec->cmd_state = SEC_CMD_STATUS_WAITING; sec_cmd_set_cmd_exit(sec); input_info(true, &info->client->dev, "%s: %s\n", __func__, buff); } static void set_sip_mode(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct fts_ts_info *info = container_of(sec, struct fts_ts_info, sec); char buff[SEC_CMD_STR_LEN] = { 0 }; int ret; sec_cmd_set_default_result(sec); if (sec->cmd_param[0] < 0 || sec->cmd_param[0] > 1) { snprintf(buff, sizeof(buff), "NG"); sec->cmd_state = SEC_CMD_STATUS_FAIL; } else { ret = fts_set_sip_mode(info, (u8)sec->cmd_param[0]); if (ret < 0) { snprintf(buff, sizeof(buff), "NG"); sec->cmd_state = SEC_CMD_STATUS_FAIL; } else { snprintf(buff, sizeof(buff), "OK"); sec->cmd_state = SEC_CMD_STATUS_OK; } } sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); sec->cmd_state = SEC_CMD_STATUS_WAITING; sec_cmd_set_cmd_exit(sec); input_info(true, &info->client->dev, "%s: %s\n", __func__, buff); } static void set_note_mode(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct fts_ts_info *info = container_of(sec, struct fts_ts_info, sec); char buff[SEC_CMD_STR_LEN] = { 0 }; u8 regAdd[3]; int ret; sec_cmd_set_default_result(sec); if (sec->cmd_param[0] < 0 || sec->cmd_param[0] > 1) { input_err(true, &info->client->dev, "%s: wrong param %d\n", __func__, sec->cmd_param[0]); snprintf(buff, sizeof(buff), "NG"); sec->cmd_state = SEC_CMD_STATUS_FAIL; goto out; } regAdd[0] = FTS_CMD_SET_FUNCTION_ONOFF; regAdd[1] = FTS_FUNCTION_SET_NOTE_MODE; regAdd[2] = sec->cmd_param[0] & 0xFF; input_info(true, &info->client->dev, "%s: %s\n", __func__, sec->cmd_param[0] ? "enable" : "disable"); ret = fts_write_reg(info, regAdd, 3); if (ret < 0) { snprintf(buff, sizeof(buff), "NG"); sec->cmd_state = SEC_CMD_STATUS_FAIL; } else { snprintf(buff, sizeof(buff), "OK"); sec->cmd_state = SEC_CMD_STATUS_OK; } out: sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); sec->cmd_state = SEC_CMD_STATUS_WAITING; sec_cmd_set_cmd_exit(sec); } static void set_game_mode(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct fts_ts_info *info = container_of(sec, struct fts_ts_info, sec); char buff[SEC_CMD_STR_LEN] = { 0 }; int ret; u8 reg[3] = { 0 }; sec_cmd_set_default_result(sec); if (sec->cmd_param[0] < 0 || sec->cmd_param[0] > 1) { snprintf(buff, sizeof(buff), "NG"); sec->cmd_state = SEC_CMD_STATUS_FAIL; } else { reg[0] = FTS_CMD_SET_FUNCTION_ONOFF; reg[1] = FTS_FUNCTION_SET_GAME_MODE; reg[2] = sec->cmd_param[0]; ret = fts_write_reg(info, reg, 3); if (ret < 0) { snprintf(buff, sizeof(buff), "NG"); sec->cmd_state = SEC_CMD_STATUS_FAIL; } else { snprintf(buff, sizeof(buff), "OK"); sec->cmd_state = SEC_CMD_STATUS_OK; } } sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); sec->cmd_state = SEC_CMD_STATUS_WAITING; sec_cmd_set_cmd_exit(sec); input_info(true, &info->client->dev, "%s: %s\n", __func__, buff); } #endif