#include "stm_dev.h" #include "stm_reg.h" 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 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 }; static ssize_t scrub_pos_show(struct device *dev, struct device_attribute *attr, char *buf) { struct sec_cmd_data *sec = dev_get_drvdata(dev); struct stm_ts_data *ts = container_of(sec, struct stm_ts_data, sec); char buff[256] = { 0 }; #if IS_ENABLED(CONFIG_SAMSUNG_PRODUCT_SHIP) input_info(true, &ts->client->dev, "%s: id: %d\n", __func__, ts->plat_data->gesture_id); #else input_info(true, &ts->client->dev, "%s: id: %d, X:%d, Y:%d\n", __func__, ts->plat_data->gesture_id, ts->plat_data->gesture_x, ts->plat_data->gesture_y); #endif snprintf(buff, sizeof(buff), "%d %d %d", ts->plat_data->gesture_id, ts->plat_data->gesture_x, ts->plat_data->gesture_y); ts->plat_data->gesture_x = 0; ts->plat_data->gesture_y = 0; return snprintf(buf, PAGE_SIZE, "%s", buff); } /* read param */ static ssize_t hw_param_show(struct device *dev, struct device_attribute *attr, char *buf) { struct sec_cmd_data *sec = dev_get_drvdata(dev); struct stm_ts_data *ts = container_of(sec, struct stm_ts_data, sec); char buff[516]; char tbuff[128]; char temp[128]; memset(buff, 0x00, sizeof(buff)); sec_input_get_common_hw_param(ts->plat_data, buff); /* module_id */ memset(tbuff, 0x00, sizeof(tbuff)); snprintf(tbuff, sizeof(tbuff), "\"TMOD\":\"ST%02X%04X%02X%c%01X\",", ts->panel_revision, ts->fw_main_version_of_ic, ts->test_result.data[0], #ifdef TCLM_CONCEPT ts->tdata->tclm_string[ts->tdata->nvdata.cal_position].s_name, ts->tdata->nvdata.cal_count & 0xF); #else '0', 0); #endif strlcat(buff, tbuff, sizeof(buff)); /* vendor_id */ memset(tbuff, 0x00, sizeof(tbuff)); if (ts->plat_data->firmware_name) { memset(temp, 0x00, sizeof(temp)); snprintf(temp, 9, "%s", ts->plat_data->firmware_name + 8); snprintf(tbuff, sizeof(tbuff), "\"TVEN\":\"STM_%s\"", temp); } else { snprintf(tbuff, sizeof(tbuff), "\"TVEN\":\"STM\""); } strlcat(buff, tbuff, sizeof(buff)); input_info(true, &ts->client->dev, "%s: %s\n", __func__, buff); return snprintf(buf, SEC_CMD_BUF_SIZE, "%s", buff); } /* clear param */ static ssize_t hw_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 stm_ts_data *ts = container_of(sec, struct stm_ts_data, sec); sec_input_clear_common_hw_param(ts->plat_data); 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 stm_ts_data *ts = container_of(sec, struct stm_ts_data, sec); input_info(true, &ts->client->dev, "\"TAMB_MAX\":\"%d\",\"TAMB_MAX_TX\":\"%d\",\"TAMB_MAX_RX\":\"%d\"" "\"TAMB_MIN\":\"%d\",\"TAMB_MIN_TX\":\"%d\",\"TAMB_MIN_RX\":\"%d\"", ts->rawcap_max, ts->rawcap_max_tx, ts->rawcap_max_rx, ts->rawcap_min, ts->rawcap_min_tx, ts->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\"", ts->rawcap_max, ts->rawcap_max_tx, ts->rawcap_max_rx, ts->rawcap_min, ts->rawcap_min_tx, ts->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 stm_ts_data *ts = container_of(sec, struct stm_ts_data, 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 (ts->plat_data->power_state == SEC_INPUT_STATE_POWER_OFF) { input_err(true, &ts->client->dev, "%s: [ERROR] Touch is stopped\n", __func__); return -EPERM; } cancel_delayed_work(&ts->work_print_info); wbuf[0] = STM_TS_CMD_SENSITIVITY_MODE; switch (value) { case 0: wbuf[1] = 0xFF; /* disable */ break; case 1: wbuf[1] = 0x24; /* enable */ wbuf[2] = 0x01; ts->sensitivity_mode = 1; break; case 2: wbuf[1] = 0x24; /* flex mode enable */ wbuf[2] = 0x02; ts->sensitivity_mode = 2; break; default: break; } ret = ts->stm_ts_write(ts, &wbuf[0], 1, &wbuf[1], 2); if (ret < 0) { input_err(true, &ts->client->dev, "%s: write failed. ret: %d\n", __func__, ret); schedule_delayed_work(&ts->work_print_info, msecs_to_jiffies(TOUCH_PRINT_INFO_DWORK_TIME)); return ret; } sec_delay(30); if (value == 0) schedule_delayed_work(&ts->work_print_info, msecs_to_jiffies(TOUCH_PRINT_INFO_DWORK_TIME)); input_info(true, &ts->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 stm_ts_data *ts = container_of(sec, struct stm_ts_data, sec); u8 *rbuf; u8 reg_read = STM_TS_READ_SENSITIVITY_VALUE; int ret, i; s16 value[12]; u8 count = 9; char *buffer; ssize_t len; if (ts->plat_data->power_state == SEC_INPUT_STATE_POWER_OFF) { input_err(true, &ts->client->dev, "%s: [ERROR] Touch is stopped\n", __func__); return -EPERM; } if (ts->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 = ts->stm_ts_read(ts, ®_read, 1, rbuf, count * 2); if (ret < 0) { kfree(rbuf); kfree(buffer); input_err(true, &ts->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, &ts->client->dev, "%s: %s\n", __func__, buffer); len = snprintf(buf, SEC_CMD_BUF_SIZE, "%s", buffer); kfree(rbuf); kfree(buffer); return len; } /* * returns the bit combination of specific feature that is supported. */ static ssize_t support_feature_show(struct device *dev, struct device_attribute *attr, char *buf) { struct sec_cmd_data *sec = dev_get_drvdata(dev); struct stm_ts_data *ts = container_of(sec, struct stm_ts_data, sec); u32 feature = 0; if (ts->plat_data->enable_settings_aot) feature |= INPUT_FEATURE_ENABLE_SETTINGS_AOT; if (ts->plat_data->sync_reportrate_120) feature |= INPUT_FEATURE_ENABLE_SYNC_RR120; if (ts->plat_data->support_vrr) feature |= INPUT_FEATURE_ENABLE_VRR; if (ts->plat_data->support_open_short_test) feature |= INPUT_FEATURE_SUPPORT_OPEN_SHORT_TEST; if (ts->plat_data->support_mis_calibration_test) feature |= INPUT_FEATURE_SUPPORT_MIS_CALIBRATION_TEST; if (ts->plat_data->support_wireless_tx) feature |= INPUT_FEATURE_SUPPORT_WIRELESS_TX; if (ts->plat_data->support_input_monitor) feature |= INPUT_FEATURE_SUPPORT_INPUT_MONITOR; if (ts->plat_data->enable_sysinput_enabled) feature |= INPUT_FEATURE_ENABLE_SYSINPUT_ENABLED; if (ts->plat_data->support_rawdata_motion_aivf) feature |= INPUT_FEATURE_SUPPORT_MOTION_AIVF; if (ts->plat_data->support_rawdata_motion_palm) feature |= INPUT_FEATURE_SUPPORT_MOTION_PALM; input_info(true, &ts->client->dev, "%s: %d%s%s%s%s%s%s%s%s%s%s%s\n", __func__, feature, feature & INPUT_FEATURE_ENABLE_SETTINGS_AOT ? " aot" : "", feature & INPUT_FEATURE_ENABLE_PRESSURE ? " pressure" : "", feature & INPUT_FEATURE_ENABLE_SYNC_RR120 ? " RR120hz" : "", feature & INPUT_FEATURE_ENABLE_VRR ? " vrr" : "", feature & INPUT_FEATURE_SUPPORT_OPEN_SHORT_TEST ? " openshort" : "", feature & INPUT_FEATURE_SUPPORT_MIS_CALIBRATION_TEST ? " miscal" : "", feature & INPUT_FEATURE_SUPPORT_WIRELESS_TX ? " wirelesstx" : "", feature & INPUT_FEATURE_SUPPORT_INPUT_MONITOR ? " inputmonitor" : "", feature & INPUT_FEATURE_ENABLE_SYSINPUT_ENABLED ? " SE" : "", feature & INPUT_FEATURE_SUPPORT_MOTION_AIVF ? " AIVF" : "", feature & INPUT_FEATURE_SUPPORT_MOTION_PALM ? " PALM" : ""); return snprintf(buf, SEC_CMD_BUF_SIZE, "%d", feature); } ssize_t get_lp_dump_show(struct device *dev, struct device_attribute *attr, char *buf) { struct sec_cmd_data *sec = dev_get_drvdata(dev); struct stm_ts_data *ts = container_of(sec, struct stm_ts_data, 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 data[3] = {0}; if (ts->plat_data->power_state == SEC_INPUT_STATE_POWER_OFF) { input_err(true, &ts->client->dev, "%s: Touch is stopped!\n", __func__); if (buf) return snprintf(buf, SEC_CMD_BUF_SIZE, "TSP turned off"); else return 0; } if (ts->reset_is_on_going) { input_err(true, &ts->client->dev, "%s: Reset is ongoing!\n", __func__); if (buf) return snprintf(buf, SEC_CMD_BUF_SIZE, "Reset is ongoing"); else return 0; } /* preparing dump buffer */ sec_spg_dat = vmalloc(SEC_TS_MAX_SPONGE_DUMP_BUFFER); if (!sec_spg_dat) { input_err(true, &ts->client->dev, "%s : Failed!!\n", __func__); if (buf) return snprintf(buf, SEC_CMD_BUF_SIZE, "vmalloc failed"); else return 0; } memset(sec_spg_dat, 0, SEC_TS_MAX_SPONGE_DUMP_BUFFER); disable_irq(ts->irq); string_data[0] = SEC_TS_CMD_SPONGE_LP_DUMP_CUR_IDX; ret = ts->stm_ts_read_sponge(ts, string_data, 2); if (ret < 0) { input_err(true, &ts->client->dev, "%s: Failed to read rect\n", __func__); if (buf) snprintf(buf, SEC_CMD_BUF_SIZE, "NG, Failed to read rect"); goto out; } if (ts->sponge_inf_dump) dump_gain = 2; else dump_gain = 1; current_index = (string_data[1] & 0xFF) << 8 | (string_data[0] & 0xFF); dump_start = SEC_TS_CMD_SPONGE_LP_DUMP_EVENT; dump_end = dump_start + (ts->sponge_dump_format * ((ts->sponge_dump_event * dump_gain) - 1)); if (current_index > dump_end || current_index < dump_start) { input_err(true, &ts->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); goto out; } /* legacy get_lp_dump */ input_info(true, &ts->client->dev, "%s: DEBUG format=%d, num=%d, start=%d, end=%d, current_index=%d\n", __func__, ts->sponge_dump_format, ts->sponge_dump_event, dump_start, dump_end, current_index); for (i = (ts->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 < (ts->sponge_dump_format * i)) string_addr = (ts->sponge_dump_format * ts->sponge_dump_event * dump_gain) + current_index - (ts->sponge_dump_format * i); else string_addr = current_index - (ts->sponge_dump_format * i); if (string_addr < dump_start) string_addr += (ts->sponge_dump_format * ts->sponge_dump_event * dump_gain); string_data[0] = string_addr & 0xFF; string_data[1] = (string_addr & 0xFF00) >> 8; if (ts->sponge_dump_format > 10) { input_err(true, &ts->client->dev, "%s: wrong sponge sponge_dump_format size:%d\n", __func__, ts->sponge_dump_format); if (buf) snprintf(buf, SEC_CMD_BUF_SIZE, "NG,wrong sponge_dump_format"); goto out; } ret = ts->stm_ts_read_sponge(ts, string_data, ts->sponge_dump_format); if (ret < 0) { input_err(true, &ts->client->dev, "%s: Failed to read sponge\n", __func__); if (buf) snprintf(buf, SEC_CMD_BUF_SIZE, "NG, Failed to read sponge, addr=%d", string_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 (ts->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); } if (buf) strlcat(buf, buff, PAGE_SIZE); } } if (ts->sponge_inf_dump) { if (current_index >= ts->sponge_dump_border) { dump_cnt = ((current_index - (ts->sponge_dump_border)) / ts->sponge_dump_format) + 1; dump_area = 1; sec_spg_dat[0] = (u8)ts->sponge_dump_border & 0xff; sec_spg_dat[1] = (u8)(ts->sponge_dump_border >> 8); } else { dump_cnt = ((current_index - SEC_TS_CMD_SPONGE_LP_DUMP_EVENT) / ts->sponge_dump_format) + 1; dump_area = 0; sec_spg_dat[0] = SEC_TS_CMD_SPONGE_LP_DUMP_EVENT; sec_spg_dat[1] = 0; } if (dump_cnt * ts->sponge_dump_format > SEC_TS_MAX_SPONGE_DUMP_BUFFER) { input_err(true, &ts->client->dev, "%s: wrong sponge sponge_dump_format size:%d dump_cnt:%d\n", __func__, ts->sponge_dump_format, dump_cnt); if (buf) snprintf(buf, SEC_CMD_BUF_SIZE, "NG,wrong sponge_dump_format"); goto out; } ret = ts->stm_ts_read_sponge(ts, sec_spg_dat, dump_cnt * ts->sponge_dump_format); if (ret < 0) { input_err(true, &ts->client->dev, "%s: Failed to read sponge\n", __func__); goto out; } for (i = 0 ; i <= dump_cnt ; i++) { int e_offset = i * ts->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 + (ts->sponge_dump_event * dump_area), edata[0], edata[1], edata[2], edata[3], edata[4]); #if IS_ENABLED(CONFIG_SEC_DEBUG_TSP_LOG) sec_tsp_sponge_log(ibuff); #endif } } ts->sponge_dump_delayed_flag = false; data[0] = STM_TS_CMD_SPONGE_OFFSET_MODE_01; data[2] = ts->plat_data->sponge_mode |= SEC_TS_MODE_SPONGE_INF_DUMP_CLEAR; ret = ts->stm_ts_write_sponge(ts, data, 3); if (ret < 0) { input_err(true, &ts->client->dev, "%s: Failed to clear sponge dump\n", __func__); } ts->plat_data->sponge_mode &= ~SEC_TS_MODE_SPONGE_INF_DUMP_CLEAR; } out: vfree(sec_spg_dat); enable_irq(ts->client->irq); if (buf) return strlen(buf); else return 0; } 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 stm_ts_data *ts = container_of(sec, struct stm_ts_data, sec); input_info(true, &ts->client->dev, "%s: %d\n", __func__, ts->plat_data->prox_power_off); return snprintf(buf, SEC_CMD_BUF_SIZE, "%d", ts->plat_data->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 stm_ts_data *ts = container_of(sec, struct stm_ts_data, sec); int ret, data; ret = kstrtoint(buf, 10, &data); if (ret < 0) return ret; input_info(true, &ts->client->dev, "%s: %d\n", __func__, data); ts->plat_data->prox_power_off = data; return count; } static ssize_t ear_detect_enable_show(struct device *dev, struct device_attribute *attr, char *buf) { struct sec_cmd_data *sec = dev_get_drvdata(dev); struct stm_ts_data *ts = container_of(sec, struct stm_ts_data, sec); input_info(true, &ts->client->dev, "%s: %d\n", __func__, ts->plat_data->ed_enable); return snprintf(buf, SEC_CMD_BUF_SIZE, "%d", ts->plat_data->ed_enable); } static ssize_t ear_detect_enable_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct sec_cmd_data *sec = dev_get_drvdata(dev); struct stm_ts_data *ts = container_of(sec, struct stm_ts_data, sec); int ret, value; u8 address = STM_TS_CMD_SET_EAR_DETECT; ret = kstrtoint(buf, 10, &value); if (ret < 0) return ret; if (ts->plat_data->support_ear_detect) { ts->plat_data->ed_enable = value; ret = ts->stm_ts_write(ts, &address, 1, &ts->plat_data->ed_enable, 1); input_info(true, &ts->client->dev, "%s: set ear detect %s, ret = %d\n", __func__, ts->plat_data->ed_enable ? "enable" : "disable", ret); } return count; } static ssize_t virtual_prox_show(struct device *dev, struct device_attribute *attr, char *buf) { struct sec_cmd_data *sec = dev_get_drvdata(dev); struct stm_ts_data *ts = container_of(sec, struct stm_ts_data, sec); input_info(true, &ts->client->dev, "%s: %d\n", __func__, ts->hover_event); return snprintf(buf, SEC_CMD_BUF_SIZE, "%d", ts->hover_event != 3 ? 0 : 3); } static ssize_t virtual_prox_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct sec_cmd_data *sec = dev_get_drvdata(dev); struct stm_ts_data *ts = container_of(sec, struct stm_ts_data, sec); int ret; u8 address; u8 data; ret = kstrtou8(buf, 8, &data); if (ret < 0) return ret; address = STM_TS_CMD_SET_EAR_DETECT; ret = ts->stm_ts_write(ts, &address, 1, &data, 1); input_info(true, &ts->client->dev, "%s: set %d: ret:%d\n", __func__, data, ret); return count; } static ssize_t fod_pos_show(struct device *dev, struct device_attribute *attr, char *buf) { struct sec_cmd_data *sec = dev_get_drvdata(dev); struct stm_ts_data *ts = container_of(sec, struct stm_ts_data, sec); char buff[3] = { 0 }; int i, ret; if (!ts->plat_data->support_fod) { input_err(true, &ts->client->dev, "%s: fod is not supported\n", __func__); return snprintf(buf, SEC_CMD_BUF_SIZE, "NA"); } if (!ts->plat_data->fod_data.vi_size) { input_err(true, &ts->client->dev, "%s: not read fod_info yet\n", __func__); return snprintf(buf, SEC_CMD_BUF_SIZE, "NG"); } if (!ts->plat_data->support_fod_lp_mode) { ret = stm_ts_fod_vi_event(ts); if (ret < 0) { input_err(true, &ts->client->dev, "%s: Failed to read\n", __func__); return snprintf(buf, SEC_CMD_BUF_SIZE, "NG"); } } for (i = 0; i < ts->plat_data->fod_data.vi_size; i++) { snprintf(buff, 3, "%02X", ts->plat_data->fod_data.vi_data[i]); strlcat(buf, buff, SEC_CMD_BUF_SIZE); } return strlen(buf); } static ssize_t fod_info_show(struct device *dev, struct device_attribute *attr, char *buf) { struct sec_cmd_data *sec = dev_get_drvdata(dev); struct stm_ts_data *ts = container_of(sec, struct stm_ts_data, sec); return sec_input_get_fod_info(&ts->client->dev, buf); } static ssize_t aod_active_area_show(struct device *dev, struct device_attribute *attr, char *buf) { struct sec_cmd_data *sec = dev_get_drvdata(dev); struct stm_ts_data *ts = container_of(sec, struct stm_ts_data, sec); input_info(true, &ts->client->dev, "%s: top:%d, edge:%d, bottom:%d\n", __func__, ts->plat_data->aod_data.active_area[0], ts->plat_data->aod_data.active_area[1], ts->plat_data->aod_data.active_area[2]); return snprintf(buf, SEC_CMD_BUF_SIZE, "%d,%d,%d", ts->plat_data->aod_data.active_area[0], ts->plat_data->aod_data.active_area[1], ts->plat_data->aod_data.active_area[2]); } 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 stm_ts_data *ts = container_of(sec, struct stm_ts_data, sec); int ret, value; if (!(ts->plat_data->support_flex_mode && (ts->plat_data->support_dual_foldable == MAIN_TOUCH))) return count; ret = kstrtoint(buf, 10, &value); if (ret < 0) return ret; input_info(true, &ts->client->dev, "%s: power_state[%d] %sfolding\n", __func__, ts->plat_data->power_state, ts->flip_status_current ? "" : "un"); if (ts->plat_data->power_state == SEC_INPUT_STATE_POWER_OFF && ts->flip_status_current == STM_TS_STATUS_UNFOLDING) { cancel_delayed_work(&ts->switching_work); schedule_work(&ts->switching_work.work); } return count; } static ssize_t enabled_show(struct device *dev, struct device_attribute *attr, char *buf) { struct sec_cmd_data *sec = dev_get_drvdata(dev); struct stm_ts_data *ts = container_of(sec, struct stm_ts_data, sec); if (!ts->plat_data->enable_sysinput_enabled) return -EINVAL; input_info(true, &ts->client->dev, "%s: power_status %d\n", __func__, ts->plat_data->power_state); return snprintf(buf, SEC_CMD_BUF_SIZE, "%d", ts->plat_data->power_state); } static ssize_t enabled_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct sec_cmd_data *sec = dev_get_drvdata(dev); struct stm_ts_data *ts = container_of(sec, struct stm_ts_data, sec); struct input_dev *input_dev = ts->plat_data->input_dev; int buff[2]; int ret; if (!ts->plat_data->enable_sysinput_enabled) return -EINVAL; ret = sscanf(buf, "%d,%d", &buff[0], &buff[1]); if (ret != 2) { input_err(true, &ts->client->dev, "%s: failed read params [%d]\n", __func__, ret); return -EINVAL; } if (buff[0] == DISPLAY_STATE_ON && buff[1] == DISPLAY_EVENT_LATE) { if (ts->vvc_mode) stm_ts_set_vvc_mode(ts, false); if (ts->plat_data->enabled) { ts->plat_data->display_state = DISPLAY_STATE_ON; input_err(true, &ts->client->dev, "%s: device already enabled\n", __func__); goto out; } input_info(true, &ts->client->dev, "%s: [%s] enable\n", __func__, current->comm); ret = sec_input_enable_device(input_dev); ts->plat_data->display_state = DISPLAY_STATE_ON; } else if (buff[0] == DISPLAY_STATE_OFF && buff[1] == DISPLAY_EVENT_EARLY) { if (buff[0] == DISPLAY_STATE_OFF && ts->vvc_mode) stm_ts_set_vvc_mode(ts, true); if (!ts->plat_data->enabled) { input_err(true, &ts->client->dev, "%s: device already disabled1\n", __func__); goto out; } input_info(true, &ts->client->dev, "%s: [%s] disable\n", __func__, current->comm); ret = sec_input_disable_device(input_dev); } else if (buff[0] == DISPLAY_STATE_FORCE_ON) { if (ts->vvc_mode) stm_ts_set_vvc_mode(ts, true); if (ts->plat_data->enabled) { input_err(true, &ts->client->dev, "%s: device already enabled\n", __func__); goto out; } input_info(true, &ts->client->dev, "%s: [%s] DISPLAY_STATE_FORCE_ON\n", __func__, current->comm); ret = sec_input_enable_device(input_dev); ts->plat_data->display_state = DISPLAY_STATE_FORCE_ON; } else if (buff[0] == DISPLAY_STATE_FORCE_OFF) { if (ts->vvc_mode) stm_ts_set_vvc_mode(ts, true); if (!ts->plat_data->enabled) { input_err(true, &ts->client->dev, "%s: device already disabled\n", __func__); goto out; } input_info(true, &ts->client->dev, "%s: [%s] DISPLAY_STATE_FORCE_OFF\n", __func__, current->comm); ret = sec_input_disable_device(input_dev); ts->plat_data->display_state = DISPLAY_STATE_FORCE_OFF; } if (ret) return ret; out: return count; } static DEVICE_ATTR_RO(scrub_pos); static DEVICE_ATTR_RW(hw_param); static DEVICE_ATTR_RO(read_ambient_info); static DEVICE_ATTR_RW(sensitivity_mode); static DEVICE_ATTR_RO(support_feature); static DEVICE_ATTR_RO(get_lp_dump); static DEVICE_ATTR_RW(prox_power_off); static DEVICE_ATTR_RW(ear_detect_enable); static DEVICE_ATTR_RW(virtual_prox); static DEVICE_ATTR_RO(fod_pos); static DEVICE_ATTR_RO(fod_info); static DEVICE_ATTR_RO(aod_active_area); static DEVICE_ATTR_WO(dualscreen_policy); static DEVICE_ATTR_RW(enabled); static struct attribute *cmd_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, &dev_attr_get_lp_dump.attr, &dev_attr_prox_power_off.attr, &dev_attr_ear_detect_enable.attr, &dev_attr_virtual_prox.attr, &dev_attr_fod_pos.attr, &dev_attr_fod_info.attr, &dev_attr_aod_active_area.attr, &dev_attr_dualscreen_policy.attr, &dev_attr_enabled.attr, NULL, }; static struct attribute_group cmd_attr_group = { .attrs = cmd_attributes, }; static void enter_factory_mode(struct stm_ts_data *ts, bool fac_mode) { if (ts->plat_data->power_state == SEC_INPUT_STATE_POWER_OFF) return; ts->stm_ts_systemreset(ts, 50); stm_ts_release_all_finger(ts); if (fac_mode) { stm_ts_execute_autotune(ts, false); sec_delay(50); } stm_ts_set_scanmode(ts, ts->scan_mode); sec_delay(50); } static int stm_ts_check_index(struct stm_ts_data *ts) { struct sec_cmd_data *sec = &ts->sec; char buff[SEC_CMD_STR_LEN] = { 0 }; int node; if (sec->cmd_param[0] < 0 || sec->cmd_param[0] >= ts->rx_count || sec->cmd_param[1] < 0 || sec->cmd_param[1] >= ts->tx_count) { 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, &ts->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] * ts->rx_count + sec->cmd_param[0]; input_info(true, &ts->client->dev, "%s: node = %d\n", __func__, node); return node; } static void stm_ts_print_channel(struct stm_ts_data *ts, 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 = ts->tx_count; int rx_count = ts->rx_count; 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, &ts->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, &ts->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, &ts->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, &ts->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, &ts->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, &ts->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, &ts->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, &ts->client->dev, "%s\n", pStr); vfree(pStr); } void stm_ts_print_frame(struct stm_ts_data *ts, short *min, short *max) { int i = 0; int j = 0; u8 *pStr = NULL; u8 pTmp[16] = { 0 }; int lsize = 6 * (ts->rx_count + 1); pStr = kzalloc(lsize, GFP_KERNEL); if (pStr == NULL) return; snprintf(pTmp, 5, " "); strlcat(pStr, pTmp, lsize); for (i = 0; i < ts->rx_count; i++) { snprintf(pTmp, 7, "Rx%02d ", i); strlcat(pStr, pTmp, lsize); } input_raw_info_d(true, &ts->client->dev, "%s\n", pStr); memset(pStr, 0x0, 6 * (ts->rx_count + 1)); snprintf(pTmp, 3, " +"); strlcat(pStr, pTmp, lsize); for (i = 0; i < ts->rx_count; i++) { snprintf(pTmp, 7, "------"); strlcat(pStr, pTmp, lsize); } input_raw_info_d(true, &ts->client->dev, "%s\n", pStr); for (i = 0; i < ts->tx_count; i++) { memset(pStr, 0x0, 6 * (ts->rx_count + 1)); snprintf(pTmp, 8, "Tx%02d | ", i); strlcat(pStr, pTmp, lsize); for (j = 0; j < ts->rx_count; j++) { snprintf(pTmp, 7, "%5d ", ts->pFrame[(i * ts->rx_count) + j]); strlcat(pStr, pTmp, lsize); if (ts->pFrame[(i * ts->rx_count) + j] < *min) *min = ts->pFrame[(i * ts->rx_count) + j]; if (ts->pFrame[(i * ts->rx_count) + j] > *max) *max = ts->pFrame[(i * ts->rx_count) + j]; } input_raw_info_d(true, &ts->client->dev, "%s\n", pStr); } input_raw_info_d(true, &ts->client->dev, "%s, min:%d, max:%d\n", __func__, *min, *max); kfree(pStr); } int stm_ts_read_frame(struct stm_ts_data *ts, u8 type, short *min, short *max) { struct stm_ts_syncframeheader *psyncframeheader; u8 reg[8] = { 0 }; unsigned int totalbytes = 0; u8 *pRead; int rc = 0; int ret = 0; int i = 0, j = 0; int retry = 10; pRead = kzalloc(ts->tx_count * ts->rx_count * 3 + 1, GFP_KERNEL); if (!pRead) return -ENOMEM; /* Request Data Type */ reg[0] = 0xA4; reg[1] = 0x06; reg[2] = (u8)type; ts->stm_ts_write(ts, ®[0], 3, NULL, 0); sec_delay(50); do { reg[0] = STM_TS_CMD_FRM_BUFF_R; reg[1] = 0x00; reg[2] = 0x00; ret = ts->stm_ts_read(ts, ®[0], 3, &pRead[0], STM_TS_COMP_DATA_HEADER_SIZE); if (ret < 0) { input_err(true, &ts->client->dev, "%s: read failed rc = %d\n", __func__, ret); rc = -3; goto ERROREXIT; } psyncframeheader = (struct stm_ts_syncframeheader *) &pRead[0]; if ((psyncframeheader->header == 0xA5) && (psyncframeheader->host_data_mem_id == type)) break; sec_delay(100); } while (retry--); if (retry == 0) { input_err(true, &ts->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 = (ts->tx_count * ts->rx_count * 2); reg[0] = STM_TS_CMD_FRM_BUFF_R; reg[1] = 0x00; reg[2] = STM_TS_COMP_DATA_HEADER_SIZE + psyncframeheader->dbg_frm_len; ret = ts->stm_ts_read(ts, ®[0], 3, &pRead[0], totalbytes); if (ret < 0) { input_err(true, &ts->client->dev, "%s: read failed rc = %d\n", __func__, ret); rc = -5; goto ERROREXIT; } for (i = 0; i < totalbytes / 2; i++) ts->pFrame[i] = (short)(pRead[i * 2] + (pRead[i * 2 + 1] << 8)); switch (type) { case TYPE_RAW_DATA: input_raw_info_d(true, &ts->client->dev, "%s", "[Raw Data]\n"); break; case TYPE_STRENGTH_DATA: input_raw_info_d(true, &ts->client->dev, "%s: [Strength Data]\n", __func__); break; case TYPE_BASELINE_DATA: input_raw_info_d(true, &ts->client->dev, "%s: [Baseline Data]\n", __func__); break; } stm_ts_print_frame(ts, min, max); if (!ts->info_work_done) { if (type == TYPE_RAW_DATA) { for (j = 0; j < ts->tx_count; j++) { for (i = 0; i < ts->rx_count; i++) { if (ts->rawcap_max < ts->pFrame[j * ts->rx_count + i]) { ts->rawcap_max = ts->pFrame[j * ts->rx_count + i]; ts->rawcap_max_tx = j; ts->rawcap_max_rx = i; } if (ts->rawcap_min > ts->pFrame[j * ts->rx_count + i]) { ts->rawcap_min = ts->pFrame[j * ts->rx_count + i]; ts->rawcap_min_tx = j; ts->rawcap_min_rx = i; } } } } } ERROREXIT: kfree(pRead); return rc; } int stm_ts_read_nonsync_frame(struct stm_ts_data *ts, short *min, short *max) { struct stm_ts_syncframeheader *psyncframeheader; u8 reg[8] = { 0 }; unsigned int totalbytes = 0; u8 *pRead; int rc = 0; int ret = 0; int i = 0; int retry = 10; input_info(true, &ts->client->dev, "%s\n", __func__); pRead = kzalloc(ts->tx_count * ts->rx_count * 3 + 1, GFP_KERNEL); if (!pRead) return -ENOMEM; /* Request System Information */ reg[0] = 0xA4; reg[1] = 0x06; reg[2] = 0x01; ts->stm_ts_write(ts, ®[0], 3, NULL, 0); sec_delay(50); do { reg[0] = STM_TS_CMD_FRM_BUFF_R; reg[1] = 0x00; reg[2] = 0x00; ret = ts->stm_ts_read(ts, ®[0], 3, &pRead[0], STM_TS_COMP_DATA_HEADER_SIZE); if (ret < 0) { input_err(true, &ts->client->dev, "%s: read failed rc = %d\n", __func__, ret); rc = -3; goto ERROREXIT; } psyncframeheader = (struct stm_ts_syncframeheader *) &pRead[0]; if ((psyncframeheader->header == 0xA5) && (psyncframeheader->host_data_mem_id == 0x01)) break; sec_delay(100); } while (retry--); if (retry == 0) { input_err(true, &ts->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; } reg[0] = STM_TS_CMD_FRM_BUFF_R; reg[1] = 0x00; reg[2] = 0x88; // ms screen rawdata ret = ts->stm_ts_read(ts, ®[0], 3, &pRead[0], 2); if (ret < 0) { input_err(true, &ts->client->dev, "%s: read failed rc = %d\n", __func__, ret); rc = -5; goto ERROREXIT; } totalbytes = (ts->tx_count * ts->rx_count * 2); reg[0] = STM_TS_CMD_FRM_BUFF_R; reg[1] = (u8)pRead[1]; reg[2] = (u8)pRead[0]; ret = ts->stm_ts_read(ts, ®[0], 3, &pRead[0], totalbytes); if (ret < 0) { input_err(true, &ts->client->dev, "%s: read failed rc = %d\n", __func__, ret); rc = -6; goto ERROREXIT; } for (i = 0; i < totalbytes / 2; i++) ts->pFrame[i] = (short)(pRead[i * 2] + (pRead[i * 2 + 1] << 8)); stm_ts_print_frame(ts, min, max); ERROREXIT: kfree(pRead); return rc; } #define JITTER_TEST_RETRY 10 int stm_ts_get_jitter_result(struct stm_ts_data *ts, u8 *reg, u8 count, s16 *result, u8 type) { int rc = 0; u8 address; u8 data[STM_TS_EVENT_BUFF_SIZE]; int retry = 0; int retry_time = JITTER_TEST_RETRY; if (type == STM_TS_EVENT_JITTER_DELTA_TEST) retry_time = JITTER_TEST_RETRY * 5; stm_ts_release_all_finger(ts); mutex_lock(&ts->fn_mutex); disable_irq(ts->irq); rc = stm_ts_fix_active_mode(ts, STM_TS_ACTIVE_TRUE); if (rc < 0) { input_err(true, &ts->client->dev, "%s: failed to set active mode\n", __func__); goto ERROR; } rc = ts->stm_ts_write(ts, reg, count, NULL, 0); if (rc < 0) { input_err(true, &ts->client->dev, "%s: failed to write command\n", __func__); goto ERROR; } sec_delay(5); memset(data, 0x0, STM_TS_EVENT_BUFF_SIZE); address = STM_TS_READ_ONE_EVENT; rc = -1; while (ts->stm_ts_read(ts, &address, 1, data, STM_TS_EVENT_BUFF_SIZE) >= 0) { if (data[0] != 0x00) input_info(true, &ts->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] == STM_TS_EVENT_JITTER_RESULT) && (data[1] == 0x03)) { if ((type == STM_TS_EVENT_JITTER_MUTUAL_TEST) || (type == STM_TS_EVENT_JITTER_SELF_TEST)) { if (data[2] == STM_TS_EVENT_JITTER_MUTUAL_MAX) { result[1] = (s16)((data[8] << 8) + data[9]); input_info(true, &ts->client->dev, "%s: Mutual max jitter Strength : %d, RX:%d, TX:%d\n", __func__, result[1], data[5], data[6]); } else if (data[2] == STM_TS_EVENT_JITTER_MUTUAL_MIN) { result[0] = (s16)((data[3] << 8) + data[4]); input_info(true, &ts->client->dev, "%s: Mutual min jitter Strength : %d, RX:%d, TX:%d\n", __func__, result[0], data[5], data[6]); rc = 0; break; } else if (data[2] == STM_TS_EVENT_JITTER_SELF_TX_P2P) { result[0] = (s16)((data[3] << 8) + data[4]); input_info(true, &ts->client->dev, "%s: Self TX P2P jitter Strength : %d, TX:%d\n", __func__, result[0], data[6]); } else if (data[2] == STM_TS_EVENT_JITTER_SELF_RX_P2P) { result[1] = (s16)((data[3] << 8) + data[4]); input_info(true, &ts->client->dev, "%s: Self RX P2P jitter Strength : %d, RX:%d\n", __func__, result[1], data[5]); rc = 0; break; } } else if (type == STM_TS_EVENT_JITTER_DELTA_TEST) { if (data[2] == STM_TS_EVENT_JITTER_MUTUAL_MIN) { result[0] = data[3] << 8 | data[4]; result[1] = data[8] << 8 | data[9]; input_info(true, &ts->client->dev, "%s: MIN: min:%d, max:%d\n", __func__, result[0], result[1]); } else if (data[2] == STM_TS_EVENT_JITTER_MUTUAL_MAX) { result[2] = data[3] << 8 | data[4]; result[3] = data[8] << 8 | data[9]; input_info(true, &ts->client->dev, "%s: MAX: min:%d, max:%d\n", __func__, result[2], result[3]); } else if (data[2] == STM_TS_EVENT_JITTER_MUTUAL_AVG) { result[4] = data[3] << 8 | data[4]; result[5] = data[8] << 8 | data[9]; input_info(true, &ts->client->dev, "%s: AVG: min:%d, max:%d\n", __func__, result[4], result[5]); rc = 0; break; } } else { rc = -1; break; } } else if (data[0] == STM_TS_EVENT_ERROR_REPORT) { input_info(true, &ts->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++ > STM_TS_RETRY_COUNT * retry_time) { rc = -1; input_err(true, &ts->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; } sec_delay(20); } ERROR: enable_irq(ts->irq); mutex_unlock(&ts->fn_mutex); ts->stm_ts_systemreset(ts, 0); stm_ts_set_scanmode(ts, ts->scan_mode); return rc; } void stm_ts_checking_miscal(struct stm_ts_data *ts) { u8 reg[3] = { 0 }; short min = 0x7FFF; short max = 0x8000; ts->stm_ts_systemreset(ts, 0); stm_ts_command(ts, STM_TS_CMD_CLEAR_ALL_EVENT, true); stm_ts_release_all_finger(ts); /* get the raw data after C7 02 : mis cal test */ reg[0] = 0xC7; reg[1] = 0x02; ts->stm_ts_write(ts, ®[0], 2, NULL, 0); sec_delay(300); input_raw_info_d(true, &ts->client->dev, "%s: [miscal diff data]\n", __func__); stm_ts_read_nonsync_frame(ts, &min, &max); stm_ts_set_scanmode(ts, ts->scan_mode); input_raw_info_d(true, &ts->client->dev, "%s: mis cal min/max :%d/%d\n", __func__, min, max); } int stm_ts_panel_ito_test(struct stm_ts_data *ts, int testmode) { u8 cmd = STM_TS_READ_ONE_EVENT; u8 reg[4] = { 0 }; u8 data[STM_TS_EVENT_BUFF_SIZE]; int i; bool matched = false; int retry = 0; int result = 0; result = ts->stm_ts_systemreset(ts, 0); if (result < 0) { input_info(true, &ts->client->dev, "%s: stm_ts_systemreset fail (%d)\n", __func__, result); return result; } disable_irq(ts->irq); stm_ts_command(ts, STM_TS_CMD_CLEAR_ALL_EVENT, true); stm_ts_release_all_finger(ts); reg[0] = 0xA4; reg[1] = 0x04; switch (testmode) { case OPEN_TEST: reg[2] = 0x00; reg[3] = 0x30; break; case OPEN_SHORT_CRACK_TEST: case SAVE_MISCAL_REF_RAW: default: reg[2] = 0xFF; reg[3] = 0x01; break; } ts->stm_ts_write(ts, ®[0], 4, NULL, 0); // ITO test command sec_delay(100); memset(ts->plat_data->hw_param.ito_test, 0x0, 4); memset(data, 0x0, STM_TS_EVENT_BUFF_SIZE); while (ts->stm_ts_read(ts, &cmd, 1, (u8 *)data, STM_TS_EVENT_BUFF_SIZE) >= 0) { if ((data[0] == STM_TS_EVENT_STATUS_REPORT) && (data[1] == 0x01)) { // Check command ECHO - finished for (i = 0; i < 4; i++) { if (data[i + 2] != reg[i]) { matched = false; break; } matched = true; } if (matched == true) break; } else if (data[0] == STM_TS_EVENT_ERROR_REPORT) { ts->plat_data->hw_param.ito_test[0] = data[0]; ts->plat_data->hw_param.ito_test[1] = data[1]; ts->plat_data->hw_param.ito_test[2] = data[2]; ts->plat_data->hw_param.ito_test[3] = 0x00; result = -ITO_FAIL; switch (data[1]) { case ITO_FORCE_SHRT_GND: input_info(true, &ts->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, &ts->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, &ts->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, &ts->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, &ts->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, &ts->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, &ts->client->dev, "%s: Force channel [%d] open\n", __func__, data[2]); result = -ITO_FAIL_OPEN; break; case ITO_SENSE_OPEN: input_info(true, &ts->client->dev, "%s: Sense channel [%d] open\n", __func__, data[2]); result = -ITO_FAIL_OPEN; break; case ITO_KEY_OPEN: input_info(true, &ts->client->dev, "%s: Key channel [%d] open\n", __func__, data[2]); result = -ITO_FAIL_OPEN; break; default: input_info(true, &ts->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, &ts->client->dev, "%s: Time over - wait for result of ITO test\n", __func__); break; } sec_delay(20); } ts->stm_ts_systemreset(ts, 0); ts->plat_data->touch_functions = (ts->plat_data->touch_functions & (~STM_TS_TOUCHTYPE_BIT_COVER)); if (ts->glove_enabled) ts->plat_data->touch_functions = ts->plat_data->touch_functions | STM_TS_TOUCHTYPE_BIT_GLOVE; else ts->plat_data->touch_functions = ts->plat_data->touch_functions & (~STM_TS_TOUCHTYPE_BIT_GLOVE); stm_ts_set_touch_function(ts); sec_delay(10); ts->plat_data->touch_count = 0; stm_ts_set_scanmode(ts, ts->scan_mode); enable_irq(ts->irq); input_raw_info_d(true, &ts->client->dev, "%s: mode:%d [%s] %02X %02X %02X %02X\n", __func__, testmode, result < 0 ? "FAIL" : "PASS", ts->plat_data->hw_param.ito_test[0], ts->plat_data->hw_param.ito_test[1], ts->plat_data->hw_param.ito_test[2], ts->plat_data->hw_param.ito_test[3]); return result; } int stm_ts_panel_test_result(struct stm_ts_data *ts, int type) { u8 data[STM_TS_EVENT_BUFF_SIZE]; u8 cmd = STM_TS_READ_ONE_EVENT; uint8_t reg[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 = &ts->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, &ts->client->dev, "%s: result_buff kzalloc fail!\n", __func__); goto alloc_fail; } disable_irq(ts->irq); reg[0] = 0xA4; reg[1] = 0x04; reg[2] = 0xFC; reg[3] = 0x09; ts->stm_ts_write(ts, ®[0], 4, NULL, 0); sec_delay(100); memset(ts->plat_data->hw_param.ito_test, 0x0, 4); memset(data, 0x0, STM_TS_EVENT_BUFF_SIZE); while (ts->stm_ts_read(ts, &cmd, 1, (u8 *)data, STM_TS_EVENT_BUFF_SIZE) >= 0) { memset(tempv, 0x00, 25); memset(temph, 0x00, 30); if ((data[0] == STM_TS_EVENT_STATUS_REPORT) && (data[1] == 0x01)) { for (i = 0; i < 4; i++) { if (data[i + 2] != reg[i]) { matched = false; break; } matched = true; } if (matched == true) break; } else if (data[0] == STM_TS_EVENT_ERROR_REPORT) { ts->plat_data->hw_param.ito_test[0] = data[0]; ts->plat_data->hw_param.ito_test[1] = data[1]; ts->plat_data->hw_param.ito_test[2] = data[2]; ts->plat_data->hw_param.ito_test[3] = 0x00; switch (data[1]) { case ITO_FORCE_SHRT_GND: case ITO_SENSE_SHRT_GND: input_info(true, &ts->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, &ts->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, &ts->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, &ts->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, &ts->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, &ts->client->dev, "%s: Time over - wait for result of ITO test\n", __func__); goto test_fail; } sec_delay(20); } /* read rawdata */ input_raw_info_d(true, &ts->client->dev, "%s\n", __func__); stm_ts_read_nonsync_frame(ts, &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, &ts->client->dev, "%s: %s\n", __func__, result_buff); enable_irq(ts->irq); kfree(result_buff); return result; test_fail: enable_irq(ts->irq); 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 int stm_ts_panel_test_micro_result(struct stm_ts_data *ts, int type) { struct sec_cmd_data *sec = &ts->sec; char buff[SEC_CMD_STR_LEN]; char data[STM_TS_EVENT_BUFF_SIZE]; char echo; int ret; int retry = 30; char save_cmd[14]; sec_cmd_set_default_result(sec); memset(data, 0x00, sizeof(data)); memset(save_cmd, 0x00, sizeof(save_cmd)); save_cmd[0] = 0x76; if (type == MICRO_OPEN_TEST) { data[0] = 0xA4; data[1] = 0x04; data[2] = 0xFF; data[3] = 0x01; save_cmd[1] = 0x00; /* OPEN */ } else if (type == MICRO_SHORT_TEST) { data[0] = 0xA4; data[1] = 0x04; data[2] = 0x00; data[3] = 0xC0; save_cmd[1] = 0x01; /* SHORT */ } disable_irq(ts->irq); ret = ts->stm_ts_write(ts, &data[0], 4, NULL, 0); if (ret < 0) { input_err(true, &ts->client->dev, "%s: write failed: %d\n", __func__, ret); goto error; } sec_delay(5); /* maximum timeout 500 msec ? */ while (retry-- >= 0) { memset(data, 0x00, sizeof(data)); echo = STM_TS_READ_ONE_EVENT; ret = ts->stm_ts_read(ts, &echo, 1, data, STM_TS_EVENT_BUFF_SIZE); if (ret < 0) { input_err(true, &ts->client->dev, "%s: read failed: %d\n", __func__, ret); goto error; } input_info(true, &ts->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]); msleep(20); if (data[0] == 0x03) { save_cmd[2] = 0x00; /* PASS */ snprintf(buff, sizeof(buff), "OK"); ret = 0; break; } else if (data[0] == 0xF3) { save_cmd[2] = 0x01; /* FAIL */ snprintf(buff, sizeof(buff), "NG"); ret = 1; if (data[1] == 0x6B) { /* 6B : TX */ save_cmd[3] = data[2]; save_cmd[4] = data[3]; save_cmd[5] = 0x00; save_cmd[6] = 0x00; } else if (data[1] == 0x6C) { /* 6C : RX */ save_cmd[7] = data[2]; save_cmd[8] = data[3]; save_cmd[9] = data[4]; save_cmd[10] = data[5]; save_cmd[11] = data[6]; save_cmd[12] = 0x00; save_cmd[13] = 0x00; } if (data[7] == 1) break; } if (retry == 0) goto error; } if (stm_ts_wait_for_echo_event(ts, &save_cmd[0], 14, 0) < 0) { input_err(true, &ts->client->dev, "%s: save result failed: %d\n", __func__, ret); goto error; } enable_irq(ts->irq); sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); sec->cmd_state = SEC_CMD_STATUS_OK; return ret; error: enable_irq(ts->irq); 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; } static int stm_ts_cmd_preparation(struct sec_cmd_data *sec, bool check_lpm) { struct stm_ts_data *ts = container_of(sec, struct stm_ts_data, sec); char buff[64] = { 0 }; sec_cmd_set_default_result(sec); if ((ts->plat_data->power_state == SEC_INPUT_STATE_POWER_OFF) || (check_lpm && (ts->plat_data->power_state == SEC_INPUT_STATE_LPM))) { input_err(true, &ts->client->dev, "%s: [ERROR] TSP is %s\n", __func__, (ts->plat_data->power_state == SEC_INPUT_STATE_POWER_OFF) ? "powered off" : "lp mode"); snprintf(buff, sizeof(buff), "NG"); sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); sec->cmd_state = SEC_CMD_STATUS_FAIL; return -ENODEV; } return 0; } static void fw_update(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct stm_ts_data *ts = container_of(sec, struct stm_ts_data, sec); char buff[64] = { 0 }; int retval = 0; retval = stm_ts_cmd_preparation(sec, false); if (retval < 0) return; #if IS_ENABLED(CONFIG_INPUT_SEC_SECURE_TOUCH) #if IS_ENABLED(CONFIG_GH_RM_DRV) if (atomic_read(&ts->trusted_touch_enabled)) { input_info(true, &ts->client->dev, "%s trusted touch is enabled. skip\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; } #endif #endif mutex_lock(&ts->modechange); retval = stm_ts_fw_update_on_hidden_menu(ts, 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, &ts->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, &ts->client->dev, "%s: success [%d]\n", __func__, retval); } mutex_unlock(&ts->modechange); } static void get_fw_ver_bin(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct stm_ts_data *ts = container_of(sec, struct stm_ts_data, sec); char buff[16] = { 0 }; sec_cmd_set_default_result(sec); snprintf(buff, sizeof(buff), "ST%02X%02X%02X%02X", ts->ic_name_of_bin, ts->project_id_of_bin, ts->module_version_of_bin, ts->fw_main_version_of_bin & 0xFF); input_cmd_result(SEC_CMD_STATUS_OK, INPUT_CMD_RESULT_NOT_EXIT); 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"); } static void get_fw_ver_ic(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct stm_ts_data *ts = container_of(sec, struct stm_ts_data, sec); char buff[16] = { 0 }; char model_ver[7] = { 0 }; sec_cmd_set_default_result(sec); if (ts->plat_data->power_state == SEC_INPUT_STATE_POWER_OFF) { input_err(true, &ts->client->dev, "%s: [ERROR] Touch is stopped\n", __func__); snprintf(buff, sizeof(buff), "NG"); input_cmd_result(SEC_CMD_STATUS_FAIL, INPUT_CMD_RESULT_NOT_EXIT); 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"); } return; } stm_ts_get_version_info(ts); snprintf(buff, sizeof(buff), "ST%02X%02X%02X%02X", ts->ic_name_of_ic, ts->project_id_of_ic, ts->module_version_of_ic, ts->fw_main_version_of_ic & 0xFF); snprintf(model_ver, sizeof(model_ver), "ST%02X%02X", ts->ic_name_of_ic, ts->project_id_of_ic); input_cmd_result(SEC_CMD_STATUS_OK, INPUT_CMD_RESULT_NOT_EXIT); 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"); } } static void get_config_ver(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct stm_ts_data *ts = container_of(sec, struct stm_ts_data, sec); char buff[20] = { 0 }; sec_cmd_set_default_result(sec); snprintf(buff, sizeof(buff), "ST_%04X", ts->config_version_of_ic); input_cmd_result(SEC_CMD_STATUS_OK, INPUT_CMD_RESULT_NOT_EXIT); } static void get_threshold(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct stm_ts_data *ts = container_of(sec, struct stm_ts_data, sec); u8 reg[2]; u8 buff[16] = { 0 }; u8 data[5] = { 0 }; u16 finger_threshold = 0; int rc; rc = stm_ts_cmd_preparation(sec, false); if (rc < 0) return; sec->cmd_state = SEC_CMD_STATUS_RUNNING; reg[0] = STM_TS_CMD_SET_GET_TOUCH_MODE_FOR_THRESHOLD; reg[1] = 0x00; ts->stm_ts_write(ts, ®[0], 2, NULL, 0); sec_delay(50); reg[0] = STM_TS_CMD_SET_GET_TOUCH_THRESHOLD; rc = ts->stm_ts_read(ts, ®[0], 1, data, 2); if (rc <= 0) { input_err(true, &ts->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, &ts->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 stm_ts_data *ts = container_of(sec, struct stm_ts_data, sec); char buff[3] = { 0 }; int ret = 0; ret = stm_ts_stop_device(ts); 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, &ts->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 stm_ts_data *ts = container_of(sec, struct stm_ts_data, sec); char buff[3] = { 0 }; int ret = 0; ret = stm_ts_start_device(ts); 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, &ts->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 stm_ts_data *ts = container_of(sec, struct stm_ts_data, 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, &ts->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 stm_ts_data *ts = container_of(sec, struct stm_ts_data, sec); char buff[16] = { 0 }; if (ts->plat_data->firmware_name) memcpy(buff, ts->plat_data->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, &ts->client->dev, "%s: %s\n", __func__, buff); } static void run_jitter_test(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct stm_ts_data *ts = container_of(sec, struct stm_ts_data, sec); char buff[SEC_CMD_STR_LEN] = { 0 }; u8 reg[4] = { 0 }; int ret; s16 result[2] = { 0 }; ret = stm_ts_cmd_preparation(sec, true); if (ret < 0) return; ts->stm_ts_systemreset(ts, 0); // Mutual jitter. reg[0] = 0xC7; reg[1] = 0x08; reg[2] = 0x64; //100 frame reg[3] = 0x00; ret = stm_ts_get_jitter_result(ts, reg, 4, result, STM_TS_EVENT_JITTER_MUTUAL_TEST); if (ret < 0) { input_info(true, &ts->client->dev, "%s: failed to read Mutual jitter\n", __func__); snprintf(buff, sizeof(buff), "NG"); sec->cmd_state = SEC_CMD_STATUS_FAIL; input_info(true, &ts->client->dev, "%s: Fail %s\n", __func__, buff); } else { snprintf(buff, sizeof(buff), "%d", result[1]); sec->cmd_state = SEC_CMD_STATUS_OK; input_info(true, &ts->client->dev, "%s: Mutual max jitter %s\n", __func__, buff); } 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))); return; } static void run_mutual_jitter(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct stm_ts_data *ts = container_of(sec, struct stm_ts_data, sec); char buff[SEC_CMD_STR_LEN] = { 0 }; u8 reg[4] = { 0 }; int ret; s16 result[2] = { 0 }; ret = stm_ts_cmd_preparation(sec, true); if (ret < 0) return; ts->stm_ts_systemreset(ts, 0); // Mutual jitter. reg[0] = 0xC7; reg[1] = 0x08; reg[2] = 0x64; //100 frame reg[3] = 0x00; ret = stm_ts_get_jitter_result(ts, reg, 4, result, STM_TS_EVENT_JITTER_MUTUAL_TEST); if (ret < 0) { input_info(true, &ts->client->dev, "%s: failed to read Mutual jitter\n", __func__); snprintf(buff, sizeof(buff), "NG"); sec->cmd_state = SEC_CMD_STATUS_FAIL; input_raw_info_d(true, &ts->client->dev, "%s: Fail %s\n", __func__, buff); } else { snprintf(buff, sizeof(buff), "%d,%d", result[0], result[1]); sec->cmd_state = SEC_CMD_STATUS_OK; input_raw_info_d(true, &ts->client->dev, "%s: %s\n", __func__, buff); } 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))); return; } static void run_self_jitter(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct stm_ts_data *ts = container_of(sec, struct stm_ts_data, sec); char buff[SEC_CMD_STR_LEN] = { 0 }; u8 reg[4] = { 0 }; int ret; s16 result[2] = { 0 }; ret = stm_ts_cmd_preparation(sec, true); if (ret < 0) return; ts->stm_ts_systemreset(ts, 300); /* Self jitter */ reg[0] = 0xC7; reg[1] = 0x0A; reg[2] = 0x64; /* 100 frame */ reg[3] = 0x00; ret = stm_ts_get_jitter_result(ts, reg, 4, result, STM_TS_EVENT_JITTER_SELF_TEST); if (ret < 0) { input_info(true, &ts->client->dev, "%s: failed to read Self jitter\n", __func__); snprintf(buff, sizeof(buff), "NG"); sec->cmd_state = SEC_CMD_STATUS_FAIL; input_raw_info_d(true, &ts->client->dev, "%s: Fail %s\n", __func__, buff); } else { snprintf(buff, sizeof(buff), "%d,%d", result[0], result[1]); sec->cmd_state = SEC_CMD_STATUS_OK; input_raw_info_d(true, &ts->client->dev, "%s: %s\n", __func__, buff); } 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))); return; } static void run_jitter_delta_test(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct stm_ts_data *ts = container_of(sec, struct stm_ts_data, sec); char buff[SEC_CMD_STR_LEN] = { 0 }; u8 reg[4] = { 0 }; int ret = -1; s16 result[6] = { 0 }; ret = stm_ts_cmd_preparation(sec, true); if (ret < 0) return; ts->stm_ts_systemreset(ts, 0); /* jitter delta + 1000 frame*/ reg[0] = 0xC7; reg[1] = 0x08; reg[2] = 0xE8; reg[3] = 0x03; ret = stm_ts_get_jitter_result(ts, reg, 4, result, STM_TS_EVENT_JITTER_DELTA_TEST); if (ret < 0) { input_info(true, &ts->client->dev, "%s: failed to read jitter delta\n", __func__); snprintf(buff, sizeof(buff), "NG"); sec->cmd_state = SEC_CMD_STATUS_FAIL; input_info(true, &ts->client->dev, "%s: Fail %s\n", __func__, buff); } else { snprintf(buff, sizeof(buff), "%d,%d,%d,%d,%d,%d", result[0], result[1], result[2], result[3], result[4], result[5]); sec->cmd_state = SEC_CMD_STATUS_OK; input_info(true, &ts->client->dev, "%s: %s\n", __func__, buff); } if (sec->cmd_all_factory_state == SEC_CMD_STATUS_RUNNING) { char buffer[SEC_CMD_STR_LEN] = { 0 }; snprintf(buffer, sizeof(buffer), "%d,%d", result[0], result[1]); 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", result[2], result[3]); 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", result[4], result[5]); 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))); } static void run_lcdoff_mutual_jitter(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct stm_ts_data *ts = container_of(sec, struct stm_ts_data, sec); char buff[SEC_CMD_STR_LEN] = { 0 }; u8 reg[4] = { 0 }; int ret; s16 mutual_min = 0, mutual_max = 0; u8 data[STM_TS_EVENT_BUFF_SIZE] = { 0 }; u8 result = 0; int retry = 0; ret = stm_ts_cmd_preparation(sec, true); if (ret < 0) return; ts->stm_ts_systemreset(ts, 0); stm_ts_release_all_finger(ts); ret = stm_ts_fix_active_mode(ts, STM_TS_ACTIVE_TRUE); if (ret < 0) { input_err(true, &ts->client->dev, "%s: failed to set active mode\n", __func__); goto ERROR; } disable_irq(ts->irq); mutex_lock(&ts->fn_mutex); // lcd off Mutual jitter. reg[0] = 0xC7; reg[1] = 0x0D; reg[2] = 0x64; //100 frame reg[3] = 0x00; ret = ts->stm_ts_write(ts, ®[0], 4, NULL, 0); if (ret < 0) { input_err(true, &ts->client->dev, "%s: failed to write command\n", __func__); mutex_unlock(&ts->fn_mutex); enable_irq(ts->irq); goto ERROR; } sec_delay(5); memset(data, 0x0, STM_TS_EVENT_BUFF_SIZE); reg[0] = STM_TS_READ_ONE_EVENT; while (ts->stm_ts_read(ts, ®[0], 1, data, STM_TS_EVENT_BUFF_SIZE) >= 0) { if ((data[0] == STM_TS_EVENT_ERROR_REPORT) || (data[0] == STM_TS_EVENT_PASS_REPORT)) { mutual_max = data[3] << 8 | data[2]; mutual_min = data[5] << 8 | data[4]; if (data[0] == STM_TS_EVENT_PASS_REPORT) { sec->cmd_state = SEC_CMD_STATUS_OK; result = 0; } else { sec->cmd_state = SEC_CMD_STATUS_FAIL; result = 1; } break; } /* waiting 10 seconds */ if (retry++ > STM_TS_RETRY_COUNT * 50) { input_err(true, &ts->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; } sec_delay(20); } mutex_unlock(&ts->fn_mutex); enable_irq(ts->irq); ts->stm_ts_systemreset(ts, 0); stm_ts_set_scanmode(ts, ts->scan_mode); snprintf(buff, sizeof(buff), "%d,%d,%d", result, 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)), "LCDOFF_MUTUAL_JITTER"); sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); sec->cmd_state = SEC_CMD_STATUS_OK; input_raw_info_d(ts->plat_data->support_dual_foldable, &ts->client->dev, "%s: %s\n", __func__, buff); return; ERROR: ts->stm_ts_systemreset(ts, 0); stm_ts_set_scanmode(ts, ts->scan_mode); 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)), "LCDOFF_MUTUAL_JITTER"); sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); sec->cmd_state = SEC_CMD_STATUS_FAIL; input_raw_info_d(ts->plat_data->support_dual_foldable, &ts->client->dev, "%s: Fail %s\n", __func__, buff); } static void get_wet_mode(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct stm_ts_data *ts = container_of(sec, struct stm_ts_data, sec); char buff[SEC_CMD_STR_LEN] = { 0 }; u8 reg[3] = { 0 }; u8 data[2] = { 0 }; int ret; sec_cmd_set_default_result(sec); if (ts->plat_data->power_state == SEC_INPUT_STATE_POWER_OFF) { input_err(true, &ts->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; } reg[0] = 0xC7; reg[1] = 0x03; ret = ts->stm_ts_read(ts, ®[0], 2, &data[0], 1); if (ret < 0) { input_err(true, &ts->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, &ts->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 stm_ts_data *ts = container_of(sec, struct stm_ts_data, sec); char buff[16] = { 0 }; sec_cmd_set_default_result(sec); snprintf(buff, sizeof(buff), "%d", ts->tx_count); sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); sec->cmd_state = SEC_CMD_STATUS_OK; input_info(true, &ts->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 stm_ts_data *ts = container_of(sec, struct stm_ts_data, sec); char buff[16] = { 0 }; sec_cmd_set_default_result(sec); snprintf(buff, sizeof(buff), "%d", ts->rx_count); sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); sec->cmd_state = SEC_CMD_STATUS_OK; input_info(true, &ts->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 stm_ts_data *ts = container_of(sec, struct stm_ts_data, sec); char buff[16] = { 0 }; int rc; u32 checksum_data; rc = stm_ts_cmd_preparation(sec, false); if (rc < 0) return; ts->stm_ts_systemreset(ts, 0); rc = stm_ts_get_sysinfo_data(ts, STM_TS_SI_CONFIG_CHECKSUM, 4, (u8 *)&checksum_data); if (rc < 0) { input_err(true, &ts->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; } stm_ts_reinit(ts); 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, &ts->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 stm_ts_data *ts = container_of(sec, struct stm_ts_data, sec); char buff[16] = { 0 }; int rc; sec_cmd_set_default_result(sec); if (ts->fw_corruption) { snprintf(buff, sizeof(buff), "NG"); sec->cmd_state = SEC_CMD_STATUS_FAIL; } else { rc = stm_ts_fw_corruption_check(ts); if (rc == -STM_TS_ERROR_FW_CORRUPTION || rc == -STM_TS_ERROR_BROKEN_FW) { 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; stm_ts_reinit(ts); } } ts->fw_corruption = false; sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); input_info(true, &ts->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 stm_ts_data *ts = container_of(sec, struct stm_ts_data, sec); char buff[SEC_CMD_STR_LEN] = { 0 }; short min = 0x7FFF; short max = 0x8000; int ret; ret = stm_ts_cmd_preparation(sec, false); if (ret < 0) return; stm_ts_read_frame(ts, 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, &ts->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 stm_ts_data *ts = container_of(sec, struct stm_ts_data, sec); char buff[SEC_CMD_STR_LEN] = { 0 }; short val = 0; int node = 0; int ret; ret = stm_ts_cmd_preparation(sec, false); if (ret < 0) return; node = stm_ts_check_index(ts); if (node < 0) return; val = ts->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, &ts->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 stm_ts_data *ts = container_of(sec, struct stm_ts_data, sec); char buff[SEC_CMD_STR_LEN] = { 0 }; short min = 0x7FFF; short max = 0x8000; sec_cmd_set_default_result(sec); if (ts->plat_data->power_state == SEC_INPUT_STATE_POWER_OFF) { input_err(true, &ts->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; } stm_ts_read_frame(ts, 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, &ts->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 stm_ts_data *ts = container_of(sec, struct stm_ts_data, sec); char buff[SEC_CMD_STR_LEN] = { 0 }; short min = 0x7FFF; short max = 0x8000; char *all_strbuff; int i, j, ret; ret = stm_ts_cmd_preparation(sec, false); if (ret < 0) return; all_strbuff = kzalloc(ts->tx_count * ts->rx_count * 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, &ts->client->dev, "%s\n", __func__); enter_factory_mode(ts, true); stm_ts_read_frame(ts, TYPE_RAW_DATA, &min, &max); for (j = 0; j < ts->tx_count; j++) { for (i = 0; i < ts->rx_count; i++) { snprintf(buff, sizeof(buff), "%d,", ts->pFrame[j * ts->rx_count + i]); strlcat(all_strbuff, buff, ts->tx_count * ts->rx_count * 7); } } enter_factory_mode(ts, false); sec->cmd_state = SEC_CMD_STATUS_OK; sec_cmd_set_cmd_result(sec, all_strbuff, strlen(all_strbuff)); input_info(true, &ts->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 stm_ts_data *ts = container_of(sec, struct stm_ts_data, sec); char buff[SEC_CMD_STR_LEN] = { 0 }; short min = 0x7FFF; short max = 0x8000; sec_cmd_set_default_result(sec); if (ts->plat_data->power_state == SEC_INPUT_STATE_POWER_OFF) { input_err(true, &ts->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, &ts->client->dev, "%s\n", __func__); stm_ts_read_nonsync_frame(ts, &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, &ts->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 stm_ts_data *ts = container_of(sec, struct stm_ts_data, sec); char buff[SEC_CMD_STR_LEN] = { 0 }; short min = 0x7FFF; short max = 0x8000; char *all_strbuff; int i, j, ret; ret = stm_ts_cmd_preparation(sec, false); if (ret < 0) return; all_strbuff = kzalloc(ts->tx_count * ts->rx_count * 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, &ts->client->dev, "%s\n", __func__); stm_ts_read_nonsync_frame(ts, &min, &max); for (j = 0; j < ts->tx_count; j++) { for (i = 0; i < ts->rx_count; i++) { snprintf(buff, sizeof(buff), "%d,", ts->pFrame[j * ts->rx_count + i]); strlcat(all_strbuff, buff, ts->tx_count * ts->rx_count * 7); } } enter_factory_mode(ts, false); sec->cmd_state = SEC_CMD_STATUS_OK; sec_cmd_set_cmd_result(sec, all_strbuff, strlen(all_strbuff)); input_info(true, &ts->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 stm_ts_data *ts = container_of(sec, struct stm_ts_data, sec); char buff[SEC_CMD_STR_LEN] = { 0 }; short val = 0; int node = 0; int ret; ret = stm_ts_cmd_preparation(sec, false); if (ret < 0) return; node = stm_ts_check_index(ts); if (node < 0) return; val = ts->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, &ts->client->dev, "%s: %s\n", __func__, buff); } static void run_lp_single_ended_rawcap_read(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct stm_ts_data *ts = container_of(sec, struct stm_ts_data, sec); char buff[SEC_CMD_STR_LEN] = { 0 }; u8 regr[4] = { 0xA4, 0x0A, 0x01, 0x00 }; int ret; short min = 0x7FFF; short max = 0x8000; ret = stm_ts_cmd_preparation(sec, false); if (ret < 0) return; ts->stm_ts_systemreset(ts, 0); /* Request to Prepare single ended raw data from flash */ ret = stm_ts_wait_for_echo_event(ts, regr, 4, 0); if (ret < 0) { input_err(true, &ts->client->dev, "%s: timeout, ret: %d\n", __func__, ret); goto out; } input_raw_info_d(true, &ts->client->dev, "%s\n", __func__); stm_ts_read_nonsync_frame(ts, &min, &max); stm_ts_set_scanmode(ts, ts->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, &ts->client->dev, "%s: %s\n", __func__, buff); return; out: stm_ts_set_scanmode(ts, ts->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, &ts->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 stm_ts_data *ts = container_of(sec, struct stm_ts_data, sec); char buff[SEC_CMD_STR_LEN] = { 0 }; u8 regr[4] = { 0xA4, 0x0A, 0x01, 0x00 }; int ret; ret = stm_ts_cmd_preparation(sec, false); if (ret < 0) return; input_raw_info_d(true, &ts->client->dev, "%s\n", __func__); enter_factory_mode(ts, true); stm_ts_set_scanmode(ts, STM_TS_SCAN_MODE_SCAN_OFF); sec_delay(30); /* Request to Prepare single ended raw data from flash */ ret = stm_ts_wait_for_echo_event(ts, regr, 4, 0); if (ret < 0) { input_err(true, &ts->client->dev, "%s: timeout, ret: %d\n", __func__, ret); goto out; } run_nonsync_rawcap_read_all(sec); stm_ts_set_scanmode(ts, ts->scan_mode); return; out: stm_ts_set_scanmode(ts, ts->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(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct stm_ts_data *ts = container_of(sec, struct stm_ts_data, sec); char buff[SEC_CMD_STR_LEN] = { 0 }; u8 reg[4] = { 0xA4, 0x04, 0x00, 0xC0 }; int ret; ret = stm_ts_cmd_preparation(sec, false); if (ret < 0) return; stm_ts_set_scanmode(ts, STM_TS_SCAN_MODE_SCAN_OFF); sec_delay(30); /* Request to Prepare Hight Frequency(ITO) raw data from flash */ ret = stm_ts_wait_for_echo_event(ts, reg, 4, 30); if (ret < 0) { input_err(true, &ts->client->dev, "%s: timeout, ret: %d\n", __func__, ret); goto out; } input_raw_info_d(true, &ts->client->dev, "%s\n", __func__); run_nonsync_rawcap_read(sec); stm_ts_set_scanmode(ts, ts->scan_mode); return; out: stm_ts_set_scanmode(ts, ts->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 stm_ts_data *ts = container_of(sec, struct stm_ts_data, sec); char buff[SEC_CMD_STR_LEN] = { 0 }; u8 reg[4] = { 0xA4, 0x04, 0x00, 0xC0 }; int ret; ret = stm_ts_cmd_preparation(sec, false); if (ret < 0) return; input_raw_info_d(true, &ts->client->dev, "%s\n", __func__); enter_factory_mode(ts, true); stm_ts_set_scanmode(ts, STM_TS_SCAN_MODE_SCAN_OFF); sec_delay(30); /* Request to Prepare Hight Frequency(ITO) raw data from flash */ ret = stm_ts_wait_for_echo_event(ts, reg, 4, 30); if (ret < 0) { input_err(true, &ts->client->dev, "%s: timeout, ret: %d\n", __func__, ret); goto out; } run_nonsync_rawcap_read_all(sec); return; out: stm_ts_set_scanmode(ts, ts->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 stm_ts_data *ts = container_of(sec, struct stm_ts_data, sec); char buff[SEC_CMD_STR_LEN] = { 0 }; u8 reg[4] = { 0xA4, 0x04, 0xFF, 0x01 }; int ret; int i, j; ret = stm_ts_cmd_preparation(sec, false); if (ret < 0) return; stm_ts_set_scanmode(ts, STM_TS_SCAN_MODE_SCAN_OFF); sec_delay(30); /* Request to Prepare Hight Frequency(ITO) raw data from flash */ ret = stm_ts_wait_for_echo_event(ts, reg, 4, 100); if (ret < 0) { input_err(true, &ts->client->dev, "%s: timeout, ret: %d\n", __func__, ret); goto out; } input_raw_info_d(true, &ts->client->dev, "%s\n", __func__); run_nonsync_rawcap_read(sec); stm_ts_set_scanmode(ts, ts->scan_mode); pr_info("sec_input: %s - correlation\n", __func__); for (i = 0; i < ts->tx_count; i++) { pr_info("sec_input: [%2d] ", i); for (j = 0; j < ts->rx_count; j++) pr_cont("%d, ", ts->pFrame[(i * ts->rx_count) + j]); pr_cont("\n"); } return; out: stm_ts_set_scanmode(ts, ts->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 stm_ts_data *ts = container_of(sec, struct stm_ts_data, sec); char buff[SEC_CMD_STR_LEN] = { 0 }; u8 reg[4] = { 0xA4, 0x04, 0xFF, 0x01 }; int ret; int i, j; ret = stm_ts_cmd_preparation(sec, false); if (ret < 0) return; input_raw_info_d(true, &ts->client->dev, "%s\n", __func__); enter_factory_mode(ts, true); stm_ts_set_scanmode(ts, STM_TS_SCAN_MODE_SCAN_OFF); sec_delay(30); /* Request to Prepare Hight Frequency(ITO) raw data from flash */ ret = stm_ts_wait_for_echo_event(ts, reg, 4, 100); if (ret < 0) { input_err(true, &ts->client->dev, "%s: timeout, ret: %d\n", __func__, ret); goto out; } run_nonsync_rawcap_read_all(sec); stm_ts_set_scanmode(ts, ts->scan_mode); pr_info("sec_input: %s - correlation\n", __func__); for (i = 0; i < ts->tx_count; i++) { pr_info("sec_input: [%2d] ", i); for (j = 0; j < ts->rx_count; j++) pr_cont("%d, ", ts->pFrame[(i * ts->rx_count) + j]); pr_cont("\n"); } return; out: stm_ts_set_scanmode(ts, ts->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 stm_ts_data *ts = container_of(sec, struct stm_ts_data, sec); char buff[SEC_CMD_STR_LEN] = { 0 }; short min = 0x7FFF; short max = 0x8000; int ret; ret = stm_ts_cmd_preparation(sec, false); if (ret < 0) return; stm_ts_read_frame(ts, 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, &ts->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 stm_ts_data *ts = container_of(sec, struct stm_ts_data, sec); char buff[SEC_CMD_STR_LEN] = { 0 }; int ret; u8 reg[2]; u8 thd_data[4]; u8 sum_data[4]; ret = stm_ts_cmd_preparation(sec, false); if (ret < 0) return; memset(thd_data, 0x00, 4); memset(sum_data, 0x00, 4); /* Threshold */ reg[0] = 0xC7; reg[1] = 0x0C; ret = ts->stm_ts_read(ts, ®[0], 2, &thd_data[0], 4); if (ret < 0) { input_err(true, &ts->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 = ts->stm_ts_read(ts, ®[0], 2, &sum_data[0], 4); if (ret < 0) { input_err(true, &ts->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 SUM_Y:%d THD_X:%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, &ts->client->dev, "%s: %s\n", __func__, buff); } static void run_cs_raw_read_all(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct stm_ts_data *ts = container_of(sec, struct stm_ts_data, sec); char buff[SEC_CMD_STR_LEN] = { 0 }; short min = 0x7FFF; short max = 0x8000; char *all_strbuff; short *rdata; int i, j, k, ret; ret = stm_ts_cmd_preparation(sec, false); if (ret < 0) return; all_strbuff = kzalloc(ts->tx_count * ts->rx_count * 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; } rdata = (short *)kzalloc(ts->tx_count * ts->rx_count * 2, GFP_KERNEL); if (!rdata) { input_err(true, &ts->client->dev, "%s: rdata 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; kfree(all_strbuff); return; } input_raw_info_d(ts->plat_data->support_dual_foldable, &ts->client->dev, "%s\n", __func__); enter_factory_mode(ts, true); stm_ts_read_frame(ts, TYPE_RAW_DATA, &min, &max); for (i = 0; i < ts->tx_count; i++) { for (j = 0; j < ts->rx_count; j++) { rdata[(ts->rx_count - j - 1) * ts->tx_count + i] = ts->pFrame[i * ts->rx_count + j]; } } k = 0; for (j = 0; j < ts->rx_count; j++) { for (i = 0; i < ts->tx_count; i++) { snprintf(buff, sizeof(buff), "%d,", rdata[k++]); strlcat(all_strbuff, buff, ts->tx_count * ts->rx_count * 7); } } k = 0; for (j = 0; j < ts->rx_count; j++) { pr_cont("[sec_input]: "); for (i = 0; i < ts->tx_count; i++) { pr_cont(" %d", rdata[k++]); } pr_cont("\n"); } enter_factory_mode(ts, false); stm_ts_reinit(ts); sec->cmd_state = SEC_CMD_STATUS_OK; sec_cmd_set_cmd_result(sec, all_strbuff, strlen(all_strbuff)); input_info(true, &ts->client->dev, "%s: %ld\n", __func__, strlen(all_strbuff)); kfree(all_strbuff); kfree(rdata); } static void run_cs_delta_read_all(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct stm_ts_data *ts = container_of(sec, struct stm_ts_data, sec); char buff[SEC_CMD_STR_LEN] = { 0 }; short min = 0x7FFF; short max = 0x8000; char *all_strbuff; short *rdata; int i, j, k, ret; ret = stm_ts_cmd_preparation(sec, false); if (ret < 0) return; all_strbuff = kzalloc(ts->tx_count * ts->rx_count * 7 + 1, GFP_KERNEL); if (!all_strbuff) { input_err(true, &ts->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; } rdata = (short *)kzalloc(ts->tx_count * ts->rx_count * 2, GFP_KERNEL); if (!rdata) { input_err(true, &ts->client->dev, "%s: rdata 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; kfree(all_strbuff); return; } stm_ts_read_frame(ts, TYPE_STRENGTH_DATA, &min, &max); for (i = 0; i < ts->tx_count; i++) { for (j = 0; j < ts->rx_count; j++) { rdata[(ts->rx_count - j - 1) * ts->tx_count + i] = ts->pFrame[i * ts->rx_count + j]; } } k = 0; for (j = 0; j < ts->rx_count; j++) { for (i = 0; i < ts->tx_count; i++) { snprintf(buff, sizeof(buff), "%d,", rdata[k++]); strlcat(all_strbuff, buff, ts->tx_count * ts->rx_count * 7); } } k = 0; for (j = 0; j < ts->rx_count; j++) { pr_cont("[sec_input]: "); for (i = 0; i < ts->tx_count; i++) { pr_cont(" %d", rdata[k++]); } pr_cont("\n"); } sec->cmd_state = SEC_CMD_STATUS_OK; sec_cmd_set_cmd_result(sec, all_strbuff, strlen(all_strbuff)); input_info(true, &ts->client->dev, "%s: %ld\n", __func__, strlen(all_strbuff)); kfree(all_strbuff); kfree(rdata); } static void get_strength_all_data(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct stm_ts_data *ts = container_of(sec, struct stm_ts_data, sec); char buff[SEC_CMD_STR_LEN] = { 0 }; short min = 0x7FFF; short max = 0x8000; char *all_strbuff; int i, j, ret; ret = stm_ts_cmd_preparation(sec, false); if (ret < 0) return; all_strbuff = kzalloc(ts->tx_count * ts->rx_count * 7 + 1, GFP_KERNEL); if (!all_strbuff) { input_err(true, &ts->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; } stm_ts_read_frame(ts, TYPE_STRENGTH_DATA, &min, &max); for (i = 0; i < ts->tx_count; i++) { for (j = 0; j < ts->rx_count; j++) { snprintf(buff, sizeof(buff), "%d,", ts->pFrame[(i * ts->rx_count) + j]); strlcat(all_strbuff, buff, ts->tx_count * ts->rx_count * 7); } } sec->cmd_state = SEC_CMD_STATUS_OK; sec_cmd_set_cmd_result(sec, all_strbuff, strlen(all_strbuff)); input_info(true, &ts->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 stm_ts_data *ts = container_of(sec, struct stm_ts_data, sec); char buff[SEC_CMD_STR_LEN] = { 0 }; short val = 0; int node = 0; int ret; ret = stm_ts_cmd_preparation(sec, false); if (ret < 0) return; node = stm_ts_check_index(ts); if (node < 0) return; val = ts->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, &ts->client->dev, "%s: %s\n", __func__, buff); } static void stm_ts_read_self_raw_frame(struct stm_ts_data *ts, bool allnode) { struct sec_cmd_data *sec = &ts->sec; char buff[SEC_CMD_STR_LEN] = { 0 }; struct stm_ts_syncframeheader *psyncframeheader; u8 reg[STM_TS_EVENT_BUFF_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((ts->tx_count + ts->rx_count) * 2 + 1, GFP_KERNEL); if (!data) return; if (ts->plat_data->power_state == SEC_INPUT_STATE_POWER_OFF) { input_err(true, &ts->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 reg[0] = 0xA4; reg[1] = 0x06; reg[2] = TYPE_RAW_DATA; ts->stm_ts_write(ts, ®[0], 3, NULL, 0); do { reg[0] = STM_TS_CMD_FRM_BUFF_R; reg[1] = 0x00; reg[2] = 0x00; ret = ts->stm_ts_read(ts, ®[0], 3, &data[0], STM_TS_COMP_DATA_HEADER_SIZE); if (ret < 0) { input_err(true, &ts->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 stm_ts_syncframeheader *) &data[0]; if ((psyncframeheader->header == 0xA5) && (psyncframeheader->host_data_mem_id == TYPE_RAW_DATA)) break; sec_delay(100); } while (retry--); if (retry == 0) { input_err(true, &ts->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 = STM_TS_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; reg[0] = STM_TS_CMD_FRM_BUFF_R; reg[1] = (u8)(Offset >> 8); reg[2] = (u8)(Offset & 0xFF); ret = ts->stm_ts_read(ts, ®[0], 3, &data[0], totalbytes); if (ret < 0) { input_err(true, &ts->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 < (ts->tx_count); count++) { self_force_raw_data[count] = (s16)(data[count * 2 + Offset] + (data[count * 2 + 1 + Offset] << 8)); /* Only for YOCTA */ if ((count == 0 && ts->chip_id == 0x503601) || (count == 0 && ts->chip_id == 0x393603) || (count == 0 && ts->chip_id == 0x403601)) /* 403601 is rgb */ continue; 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 = (ts->tx_count * 2); for (count = 0; count < ts->rx_count; count++) { self_sense_raw_data[count] = (s16)(data[count * 2 + Offset] + (data[count * 2 + 1 + Offset] << 8)); /* Only for YOCTA */ if ((count == 0 && ts->chip_id == 0x503601) || (count == 0 && ts->chip_id == 0x393603) || (count == 0 && ts->chip_id == 0x403601)) /* 403601 is rgb */ continue; 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]; } stm_ts_print_channel(ts, self_force_raw_data, self_sense_raw_data); input_raw_info_d(true, &ts->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, &ts->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((ts->tx_count + ts->rx_count + 2) * 10, GFP_KERNEL); if (!mbuff) goto out; for (i = 0; i < (ts->tx_count); i++) { snprintf(temp, sizeof(temp), "%d,", (s16)self_force_raw_data[i]); strlcat(mbuff, temp, sizeof(mbuff)); } for (i = 0; i < (ts->rx_count); 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_RX"); 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_TX"); } sec_cmd_set_cmd_result(sec, &buff[0], strnlen(buff, sizeof(buff))); input_info(true, &ts->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 stm_ts_data *ts = container_of(sec, struct stm_ts_data, sec); sec_cmd_set_default_result(sec); input_raw_info_d(true, &ts->client->dev, "%s\n", __func__); stm_ts_read_self_raw_frame(ts, false); } static void get_cx_data(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct stm_ts_data *ts = container_of(sec, struct stm_ts_data, sec); char buff[SEC_CMD_STR_LEN] = { 0 }; short val = 0; int node = 0; int ret; ret = stm_ts_cmd_preparation(sec, false); if (ret < 0) return; node = stm_ts_check_index(ts); if (node < 0) return; if (ts->cx_data) val = ts->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, &ts->client->dev, "%s: %s\n", __func__, buff); } static int read_ms_cx_data(struct stm_ts_data *ts, u8 active, s8 *cx_min, s8 *cx_max) { s8 *rdata = NULL; u8 cdata[STM_TS_COMP_DATA_HEADER_SIZE]; u8 reg[STM_TS_EVENT_BUFF_SIZE] = { 0 }; u8 dataID = 0; u16 comp_start_addr; int i, j, ret = 0; u8 *pStr = NULL; u8 pTmp[16] = { 0 }; ts->stm_ts_command(ts, STM_TS_CMD_CLEAR_ALL_EVENT, true); // Clear FIFO stm_ts_release_all_finger(ts); sec_delay(20); // Request compensation data type if (active == NORMAL_CX2) dataID = 0x11; // MS - LP else if (active == ACTIVE_CX2) dataID = 0x10; // MS - ACTIVE reg[0] = 0xA4; reg[1] = 0x06; reg[2] = dataID; ret = stm_ts_wait_for_echo_event(ts, ®[0], 3, 0); if (ret < 0) return ret; // Read Header reg[0] = STM_TS_CMD_FRM_BUFF_R; reg[1] = 0x00; reg[2] = 0x00; ret = ts->stm_ts_read(ts, ®[0], 3, &cdata[0], STM_TS_COMP_DATA_HEADER_SIZE); if (ret < 0) return ret; if ((cdata[0] != 0xA5) && (cdata[1] != dataID)) { input_info(true, &ts->client->dev, "%s: failed to read signature data of header.\n", __func__); ret = -EIO; return ret; } rdata = kzalloc(ts->rx_count * ts->tx_count + 1, GFP_KERNEL); if (!rdata) return -ENOMEM; comp_start_addr = (u16)STM_TS_COMP_DATA_HEADER_SIZE; reg[0] = STM_TS_CMD_FRM_BUFF_R; reg[1] = (u8)(comp_start_addr >> 8); reg[2] = (u8)(comp_start_addr & 0xFF); ret = ts->stm_ts_read(ts, ®[0], 3, &rdata[0], ts->tx_count * ts->rx_count); if (ret < 0) goto out; pStr = kzalloc(7 * (ts->rx_count + 1), GFP_KERNEL); if (!pStr) { ret = -ENOMEM; goto out; } *cx_min = *cx_max = rdata[0]; for (i = 0; i < ts->tx_count; i++) { memset(pStr, 0x0, 7 * (ts->rx_count + 1)); snprintf(pTmp, sizeof(pTmp), "Tx%02d | ", i); strlcat(pStr, pTmp, 7 * (ts->rx_count + 1)); for (j = 0; j < ts->rx_count; j++) { snprintf(pTmp, sizeof(pTmp), "%4d", rdata[i * ts->rx_count + j]); strlcat(pStr, pTmp, 7 * (ts->rx_count + 1)); *cx_min = min(*cx_min, rdata[i * ts->rx_count + j]); *cx_max = max(*cx_max, rdata[i * ts->rx_count + j]); } input_raw_info_d(true, &ts->client->dev, "%s\n", pStr); } input_raw_info_d(true, &ts->client->dev, "cx min:%d, cx max:%d\n", *cx_min, *cx_max); /* ts->cx_data length: Force * Sense */ if (ts->cx_data && active == NORMAL_CX2) memcpy(&ts->cx_data[0], &rdata[0], ts->tx_count * ts->rx_count); 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 stm_ts_data *ts = container_of(sec, struct stm_ts_data, 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 (ts->plat_data->power_state == SEC_INPUT_STATE_POWER_OFF) { input_err(true, &ts->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, &ts->client->dev, "%s: start\n", __func__); rc = read_ms_cx_data(ts, 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, &ts->client->dev, "%s: %s\n", __func__, buff); } static void get_cx_gap_data(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct stm_ts_data *ts = container_of(sec, struct stm_ts_data, sec); char buff[SEC_CMD_STR_LEN] = { 0 }; int rx_max = 0, tx_max = 0, ii; for (ii = 0; ii < (ts->rx_count * ts->tx_count); ii++) { /* rx(x) gap max */ if ((ii + 1) % (ts->rx_count) != 0) rx_max = max(rx_max, (int)abs(ts->cx_data[ii + 1] - ts->cx_data[ii])); /* tx(y) gap max */ if (ii < (ts->tx_count - 1) * ts->rx_count) tx_max = max(tx_max, (int)abs(ts->cx_data[ii + ts->rx_count] - ts->cx_data[ii])); } input_raw_info(true, &ts->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, "CX2_GAP_RX"); snprintf(buff, sizeof(buff), "%d,%d", 0, tx_max); sec_cmd_set_cmd_result_all(sec, buff, SEC_CMD_STR_LEN, "CX2_GAP_TX"); } } static void run_cx_gap_data_x_all(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct stm_ts_data *ts = container_of(sec, struct stm_ts_data, sec); char *buff = NULL; int ii; char temp[5] = { 0 }; sec_cmd_set_default_result(sec); buff = kzalloc(ts->tx_count * ts->rx_count * 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 < (ts->rx_count * ts->tx_count); ii++) { if ((ii + 1) % (ts->rx_count) != 0) { snprintf(temp, sizeof(temp), "%d,", (int)abs(ts->cx_data[ii + 1] - ts->cx_data[ii])); strlcat(buff, temp, ts->tx_count * ts->rx_count * 5); memset(temp, 0x00, 5); } } sec_cmd_set_cmd_result(sec, buff, strnlen(buff, ts->tx_count * ts->rx_count * 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 stm_ts_data *ts = container_of(sec, struct stm_ts_data, sec); char *buff = NULL; int ii; char temp[5] = { 0 }; sec_cmd_set_default_result(sec); buff = kzalloc(ts->tx_count * ts->rx_count * 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 < (ts->rx_count * ts->tx_count); ii++) { if (ii < (ts->tx_count - 1) * ts->rx_count) { snprintf(temp, sizeof(temp), "%d,", (int)abs(ts->cx_data[ii + ts->rx_count] - ts->cx_data[ii])); strlcat(buff, temp, ts->tx_count * ts->rx_count * 5); memset(temp, 0x00, 5); } } sec_cmd_set_cmd_result(sec, buff, strnlen(buff, ts->tx_count * ts->rx_count * 5)); sec->cmd_state = SEC_CMD_STATUS_OK; kfree(buff); } static void run_cx_data_read(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct stm_ts_data *ts = container_of(sec, struct stm_ts_data, 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 (ts->plat_data->power_state == SEC_INPUT_STATE_POWER_OFF) { input_err(true, &ts->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)), "CX2_DATA"); sec->cmd_state = SEC_CMD_STATUS_FAIL; return; } input_raw_info_d(true, &ts->client->dev, "%s: start\n", __func__); rc = read_ms_cx_data(ts, NORMAL_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)), "CX2_DATA"); sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); input_info(true, &ts->client->dev, "%s: %s\n", __func__, buff); } static void run_cx_data_read_all(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct stm_ts_data *ts = container_of(sec, struct stm_ts_data, sec); char buff[SEC_CMD_STR_LEN] = { 0 }; int rc, i, j; s8 cx_min, cx_max; char *all_strbuff; rc = stm_ts_cmd_preparation(sec, false); if (rc < 0) return; input_raw_info_d(ts->plat_data->support_dual_foldable, &ts->client->dev, "%s\n", __func__); input_info(true, &ts->client->dev, "%s: start\n", __func__); rc = read_ms_cx_data(ts, NORMAL_CX2, &cx_min, &cx_max); enter_factory_mode(ts, 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(ts->tx_count * ts->rx_count * 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 (ts->cx_data) { for (j = 0; j < ts->tx_count; j++) { for (i = 0; i < ts->rx_count; i++) { snprintf(buff, sizeof(buff), "%d,", ts->cx_data[j * ts->rx_count + i]); strlcat(all_strbuff, buff, ts->tx_count * ts->rx_count * 4 + 1); } } } sec->cmd_state = SEC_CMD_STATUS_OK; sec_cmd_set_cmd_result(sec, all_strbuff, strlen(all_strbuff)); input_info(true, &ts->client->dev, "%s: %ld\n", __func__, strlen(all_strbuff)); kfree(all_strbuff); } static void stm_ts_read_ix_data(struct stm_ts_data *ts, bool allnode) { struct sec_cmd_data *sec = &ts->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 reg[STM_TS_EVENT_BUFF_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((ts->tx_count + ts->rx_count) * 2 + 1, GFP_KERNEL); if (!data) return; sec_cmd_set_default_result(sec); if (ts->plat_data->power_state == SEC_INPUT_STATE_POWER_OFF) { input_err(true, &ts->client->dev, "%s: [ERROR] Touch is stopped\n", __func__); snprintf(buff, sizeof(buff), "NG"); sec->cmd_state = SEC_CMD_STATUS_FAIL; goto out; } ts->stm_ts_command(ts, STM_TS_CMD_CLEAR_ALL_EVENT, true); // Clear FIFO stm_ts_release_all_finger(ts); // Request compensation data type dataID = 0x52; reg[0] = 0xA4; reg[1] = 0x06; reg[2] = dataID; // SS - CX total rc = stm_ts_wait_for_echo_event(ts, ®[0], 3, 0); if (rc < 0) { snprintf(buff, sizeof(buff), "NG"); sec->cmd_state = SEC_CMD_STATUS_FAIL; goto out; } // Read Header reg[0] = STM_TS_CMD_FRM_BUFF_R; reg[1] = 0x00; reg[2] = 0x00; ts->stm_ts_read(ts, ®[0], 3, &data[0], STM_TS_COMP_DATA_HEADER_SIZE); if ((data[0] != 0xA5) && (data[1] != dataID)) { 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)STM_TS_COMP_DATA_HEADER_SIZE; reg[0] = STM_TS_CMD_FRM_BUFF_R; reg[1] = (u8)(comp_start_tx_addr >> 8); reg[2] = (u8)(comp_start_tx_addr & 0xFF); ts->stm_ts_read(ts, ®[0], 3, &data[0], tx_num * 2); 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)(STM_TS_COMP_DATA_HEADER_SIZE + (tx_num * 2)); reg[0] = STM_TS_CMD_FRM_BUFF_R; reg[1] = (u8)(comp_start_rx_addr >> 8); reg[2] = (u8)(comp_start_rx_addr & 0xFF); ts->stm_ts_read(ts, ®[0], 3, &data[0], rx_num * 2); 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]; } stm_ts_print_channel(ts, force_ix_data, sense_ix_data); input_raw_info_d(true, &ts->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, &ts->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 = (ts->tx_count + ts->rx_count + 2) * 5; mbuff = kzalloc(buff_size, GFP_KERNEL); } if (mbuff != NULL) { char *pBuf = mbuff; for (i = 0; i < ts->tx_count; 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 < ts->rx_count; 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 < (ts->rx_count - 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_RX"); 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_TX"); } sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); input_info(true, &ts->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 stm_ts_data *ts = container_of(sec, struct stm_ts_data, sec); sec_cmd_set_default_result(sec); input_raw_info_d(true, &ts->client->dev, "%s\n", __func__); stm_ts_read_ix_data(ts, false); } static void run_ix_data_read_all(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct stm_ts_data *ts = container_of(sec, struct stm_ts_data, sec); sec_cmd_set_default_result(sec); enter_factory_mode(ts, true); stm_ts_read_ix_data(ts, true); enter_factory_mode(ts, false); } static void run_self_raw_read_all(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct stm_ts_data *ts = container_of(sec, struct stm_ts_data, sec); sec_cmd_set_default_result(sec); enter_factory_mode(ts, true); stm_ts_read_self_raw_frame(ts, true); enter_factory_mode(ts, false); } static void run_rawdata_read_all(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct stm_ts_data *ts = container_of(sec, struct stm_ts_data, sec); char buff[SEC_CMD_STR_LEN] = { 0 }; #if IS_ENABLED(CONFIG_TOUCHSCREEN_DUAL_FOLDABLE) input_raw_data_clear(MAIN_TOUCH); #else input_raw_data_clear(); #endif ts->tsp_dump_lock = true; input_raw_info_d(true, &ts->client->dev, "%s: start (noise:%d, wet:%d, tc:%d)##\n", __func__, ts->plat_data->touch_noise_status, ts->plat_data->wet_mode, ts->plat_data->touch_count); run_high_frequency_rawcap_read(sec); run_low_frequency_rawcap_read(sec); run_rawcap_read(sec); run_self_raw_read(sec); stm_ts_checking_miscal(ts); run_cx_data_read(sec); run_ix_data_read(sec); stm_ts_panel_ito_test(ts, OPEN_SHORT_CRACK_TEST); run_mutual_jitter(sec); ts->tsp_dump_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, &ts->client->dev, "%s: %s\n", __func__, buff); } void stm_ts_run_rawdata_all(struct stm_ts_data *ts) { struct sec_cmd_data *sec = &ts->sec; run_rawdata_read_all(sec); } static void run_trx_short_test(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct stm_ts_data *ts = container_of(sec, struct stm_ts_data, sec); char buff[SEC_CMD_STR_LEN] = { 0 }; int ret = 0, result = 0; int type = 0; uint8_t regAdd[4] = { 0 }; char test[32]; ret = stm_ts_cmd_preparation(sec, true); if (ret < 0) return; if (sec->cmd_param[0] == 1 && sec->cmd_param[1] == 0) { input_err(true, &ts->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] == 2) { type = MICRO_OPEN_TEST; } else if (sec->cmd_param[0] == 3) { type = MICRO_SHORT_TEST; } input_info(true, &ts->client->dev, "%s : CM%d factory_position[%d]\n", __func__, sec->cmd_param[0], ts->factory_position); /* Prevent F3 12 Error */ stm_ts_systemreset(ts, 0); stm_ts_set_hsync_scanmode(ts, STM_TS_CMD_LPM_ASYNC_SCAN); if (ts->factory_position) { // Set Test mode : prepare save test data & fail history regAdd[0] = 0xE4; regAdd[1] = 0x02; // Set power mode = Test mode ret = stm_ts_wait_for_echo_event(ts, ®Add[0], 2, 0); if (ret < 0) { input_err(true, &ts->client->dev, "%s: fail cm# data save mode on, ret=%d\n", __func__, ret); goto test_fail; } } ts->stm_ts_command(ts, STM_TS_CMD_CLEAR_ALL_EVENT, true); // Clear FIFO stm_ts_release_all_finger(ts); if (ts->factory_position && (type == MICRO_OPEN_TEST || type == MICRO_SHORT_TEST)) { // set factory for save data & fail history regAdd[0] = 0x74; regAdd[1] = ts->factory_position + 1; /* sub #2 : 1 + 1, main #3 : 2 + 1 */ ret = stm_ts_wait_for_echo_event(ts, ®Add[0], 2, 0); if (ret < 0) { input_err(true, &ts->client->dev, "%s: fail set factory position[%d], ret=%d\n", __func__, regAdd[1], ret); goto test_fail; } } if (type == OPEN_TEST || type == SHORT_TEST) { result = stm_ts_panel_test_result(ts, type); } else if (type == MICRO_OPEN_TEST || type == MICRO_SHORT_TEST) { result = stm_ts_panel_test_micro_result(ts, type); } if (ts->factory_position) { sec_delay(100); // Set Normal mode : save test data & fail history regAdd[0] = 0xE4; regAdd[1] = 0x00; ret = stm_ts_wait_for_echo_event(ts, ®Add[0], 2, 100); if (ret < 0) { input_err(true, &ts->client->dev, "%s: fail set normal mode\n", __func__); goto test_fail; } } /* reinit */ stm_ts_reinit(ts); ts->plat_data->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, &ts->client->dev, "%s : test done\n", __func__); return; test_fail: stm_ts_reinit(ts); ts->plat_data->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]); sec_cmd_send_event_to_user(sec, test, "RESULT=FAIL"); 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, &ts->client->dev, "%s : test fail\n", __func__); return; } #ifdef TCLM_CONCEPT static void get_pat_information(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct stm_ts_data *ts = container_of(sec, struct stm_ts_data, sec); char buff[50] = { 0 }; sec_cmd_set_default_result(sec); #ifdef CONFIG_SEC_FACTORY if (ts->factory_position == 1) { sec_tclm_initialize(ts->tdata); stm_tclm_data_read(ts, 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", ts->tdata->nvdata.cal_count, ts->tdata->nvdata.tune_fix_ver, ts->tdata->tclm_string[ts->tdata->nvdata.cal_position].f_name, (ts->tdata->tclm_level == TCLM_LEVEL_LOCKDOWN) ? ".L " : " ", ts->tdata->cal_pos_hist_last3[0], ts->tdata->cal_pos_hist_last3[1], ts->tdata->cal_pos_hist_last3[2], ts->tdata->cal_pos_hist_last3[3], ts->tdata->cal_pos_hist_last3[4], ts->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, &ts->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 stm_ts_data *ts = container_of(sec, struct stm_ts_data, sec); char buff[SEC_CMD_STR_LEN] = { 0 }; sec_cmd_set_default_result(sec); ts->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, &ts->client->dev, "%s: %s\n", __func__, buff); } static void tclm_test_cmd(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct stm_ts_data *ts = container_of(sec, struct stm_ts_data, sec); struct sec_tclm_data *data = ts->tdata; char buff[SEC_CMD_STR_LEN] = { 0 }; int ret = 0; sec_cmd_set_default_result(sec); if (!ts->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 stm_ts_data *ts = container_of(sec, struct stm_ts_data, sec); char buff[SEC_CMD_STR_LEN] = { 0 }; sec_cmd_set_default_result(sec); if (!ts->tdata->support_tclm_test) goto not_support; snprintf(buff, sizeof(buff), "%d", ts->is_cal_done); ts->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 static void run_factory_miscalibration(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct stm_ts_data *ts = container_of(sec, struct stm_ts_data, sec); char buff[SEC_CMD_STR_LEN]; char data[STM_TS_EVENT_BUFF_SIZE]; char echo; int ret; int retry = 200; short min = SHRT_MIN, max = SHRT_MAX; sec_cmd_set_default_result(sec); disable_irq(ts->irq); memset(data, 0x00, sizeof(data)); memset(buff, 0x00, sizeof(buff)); data[0] = 0xC7; data[1] = 0x02; ret = ts->stm_ts_write(ts, data, 2, NULL, 0); if (ret < 0) { input_err(true, &ts->client->dev, "%s: write failed: %d\n", __func__, ret); goto error; } sec_delay(200); /* maximum timeout 2sec ? */ while (retry-- >= 0) { memset(data, 0x00, sizeof(data)); echo = STM_TS_READ_ONE_EVENT; ret = ts->stm_ts_read(ts, &echo, 1, data, STM_TS_EVENT_BUFF_SIZE); if (ret < 0) { input_err(true, &ts->client->dev, "%s: read failed: %d\n", __func__, ret); goto error; } input_info(true, &ts->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]); sec_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; stm_ts_reinit(ts); enable_irq(ts->irq); return; error: 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)), "MIS_CAL"); sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); sec->cmd_state = SEC_CMD_STATUS_FAIL; stm_ts_reinit(ts); enable_irq(ts->irq); } static void run_factory_miscalibration_read_all(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct stm_ts_data *ts = container_of(sec, struct stm_ts_data, sec); char buff[SEC_CMD_STR_LEN] = { 0 }; u8 reg[3] = { 0 }; short min = 0x7FFF; short max = 0x8000; char *all_strbuff; int i, j; sec_cmd_set_default_result(sec); if (ts->plat_data->power_state == SEC_INPUT_STATE_POWER_OFF) { input_err(true, &ts->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(ts->tx_count * ts->rx_count * 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; } ts->stm_ts_systemreset(ts, 0); stm_ts_command(ts, STM_TS_CMD_CLEAR_ALL_EVENT, true); stm_ts_release_all_finger(ts); /* get the raw data after C7 02 : mis cal test */ reg[0] = 0xC7; reg[1] = 0x02; ts->stm_ts_write(ts, ®[0], 2, NULL, 0); sec_delay(300); stm_ts_read_nonsync_frame(ts, &min, &max); stm_ts_set_scanmode(ts, ts->scan_mode); for (j = 0; j < ts->tx_count; j++) { for (i = 0; i < ts->rx_count; i++) { snprintf(buff, sizeof(buff), "%d,", ts->pFrame[j * ts->rx_count + i]); strlcat(all_strbuff, buff, ts->tx_count * ts->rx_count * 7); } } sec->cmd_state = SEC_CMD_STATUS_OK; sec_cmd_set_cmd_result(sec, all_strbuff, strlen(all_strbuff)); input_info(true, &ts->client->dev, "%s: %ld\n", __func__, strlen(all_strbuff)); kfree(all_strbuff); } static void run_miscalibration(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct stm_ts_data *ts = container_of(sec, struct stm_ts_data, sec); char buff[SEC_CMD_STR_LEN]; char data[STM_TS_EVENT_BUFF_SIZE]; char echo; int ret; int retry = 200; short min = SHRT_MIN, max = SHRT_MAX; sec_cmd_set_default_result(sec); disable_irq(ts->irq); memset(data, 0x00, sizeof(data)); memset(buff, 0x00, sizeof(buff)); data[0] = 0xA4; data[1] = 0x0B; data[2] = 0x00; data[3] = 0xC0; ret = ts->stm_ts_write(ts, data, 4, NULL, 0); if (ret < 0) { input_err(true, &ts->client->dev, "%s: write failed: %d\n", __func__, ret); goto error; } sec_delay(5); /* maximum timeout 2sec ? */ while (retry-- >= 0) { memset(data, 0x00, sizeof(data)); echo = STM_TS_READ_ONE_EVENT; ret = ts->stm_ts_read(ts, &echo, 1, data, STM_TS_EVENT_BUFF_SIZE); if (ret < 0) { input_err(true, &ts->client->dev, "%s: read failed: %d\n", __func__, ret); goto error; } input_info(true, &ts->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]); sec_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; stm_ts_reinit(ts); enable_irq(ts->irq); 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; stm_ts_reinit(ts); enable_irq(ts->irq); } static void check_connection(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct stm_ts_data *ts = container_of(sec, struct stm_ts_data, sec); char buff[SEC_CMD_STR_LEN] = { 0 }; int ret = 0; ret = stm_ts_cmd_preparation(sec, false); if (ret < 0) return; ret = stm_ts_panel_ito_test(ts, 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, &ts->client->dev, "%s: %s\n", __func__, buff); } int stm_ts_get_tsp_test_result(struct stm_ts_data *ts) { u8 data; int ret; ret = get_nvm_data(ts, STM_TS_NVM_OFFSET_FAC_RESULT, &data); if (ret < 0) goto err_read; if (data == 0xFF) data = 0; ts->test_result.data[0] = data; err_read: return ret; } EXPORT_SYMBOL(stm_ts_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 stm_ts_data *ts = container_of(sec, struct stm_ts_data, sec); char buff[SEC_CMD_STR_LEN] = { 0 }; int ret; ret = stm_ts_cmd_preparation(sec, false); if (ret < 0) return; ret = stm_ts_get_tsp_test_result(ts); if (ret < 0) { input_err(true, &ts->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", ts->test_result.module_result == 0 ? "NONE" : ts->test_result.module_result == 1 ? "FAIL" : ts->test_result.module_result == 2 ? "PASS" : "A", ts->test_result.module_count, ts->test_result.assy_result == 0 ? "NONE" : ts->test_result.assy_result == 1 ? "FAIL" : ts->test_result.assy_result == 2 ? "PASS" : "A", ts->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 stm_ts_data *ts = container_of(sec, struct stm_ts_data, sec); char buff[SEC_CMD_STR_LEN] = { 0 }; int ret; ret = stm_ts_cmd_preparation(sec, false); if (ret < 0) return; ret = stm_ts_get_tsp_test_result(ts); if (ret < 0) { input_err(true, &ts->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) { ts->test_result.assy_result = sec->cmd_param[1]; if (ts->test_result.assy_count < 3) ts->test_result.assy_count++; } else if (sec->cmd_param[0] == TEST_OCTA_MODULE) { ts->test_result.module_result = sec->cmd_param[1]; if (ts->test_result.module_count < 3) ts->test_result.module_count++; } input_info(true, &ts->client->dev, "%s: [0x%X] M:%s, M:%d, A:%s, A:%d\n", __func__, ts->test_result.data[0], ts->test_result.module_result == 0 ? "NONE" : ts->test_result.module_result == 1 ? "FAIL" : ts->test_result.module_result == 2 ? "PASS" : "A", ts->test_result.module_count, ts->test_result.assy_result == 0 ? "NONE" : ts->test_result.assy_result == 1 ? "FAIL" : ts->test_result.assy_result == 2 ? "PASS" : "A", ts->test_result.assy_count); ret = set_nvm_data(ts, STM_TS_NVM_OFFSET_FAC_RESULT, ts->test_result.data); if (ret < 0) { input_err(true, &ts->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, &ts->client->dev, "%s: %s\n", __func__, buff); } int stm_ts_get_disassemble_count(struct stm_ts_data *ts) { u8 data; int ret; ret = get_nvm_data(ts, STM_TS_NVM_OFFSET_DISASSEMBLE_COUNT, &data); if (ret < 0) goto err_read; if (data == 0xFF) data = 0; ts->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 stm_ts_data *ts = container_of(sec, struct stm_ts_data, sec); char buff[SEC_CMD_STR_LEN] = { 0 }; int ret; ret = stm_ts_cmd_preparation(sec, false); if (ret < 0) return; ret = stm_ts_get_disassemble_count(ts); if (ret < 0) { input_err(true, &ts->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 (ts->disassemble_count < 0xFE) ts->disassemble_count++; ret = set_nvm_data(ts, STM_TS_NVM_OFFSET_DISASSEMBLE_COUNT, &ts->disassemble_count); if (ret < 0) { input_err(true, &ts->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, &ts->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 stm_ts_data *ts = container_of(sec, struct stm_ts_data, sec); char buff[SEC_CMD_STR_LEN] = { 0 }; int ret; ret = stm_ts_cmd_preparation(sec, false); if (ret < 0) return; ret = stm_ts_get_disassemble_count(ts); if (ret < 0) { input_err(true, &ts->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", ts->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 stm_ts_data *ts = container_of(sec, struct stm_ts_data, sec); char buff[SEC_CMD_STR_LEN] = { 0 }; int ret; ret = stm_ts_cmd_preparation(sec, false); if (ret < 0) return; ret = ts->stm_ts_systemreset(ts, 0); if (ret == -STM_TS_ERROR_BROKEN_OSC_TRIM) { snprintf(buff, sizeof(buff), "1"); } else { snprintf(buff, sizeof(buff), "0"); } stm_ts_set_scanmode(ts, ts->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, &ts->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 stm_ts_data *ts = container_of(sec, struct stm_ts_data, sec); char buff[SEC_CMD_STR_LEN] = { 0 }; int ret; unsigned char data[4]; unsigned char reg[3]; ret = stm_ts_cmd_preparation(sec, false); if (ret < 0) return; ret = stm_ts_get_sysinfo_data(ts, STM_TS_SI_OSC_TRIM_INFO, 2, data); if (ret < 0) { input_err(true, &ts->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; } reg[0] = STM_TS_CMD_FRM_BUFF_R; reg[1] = data[1]; reg[2] = data[0]; memset(data, 0x00, 4); ret = ts->stm_ts_read(ts, reg, 3, data, 4); if (ret < 0) { input_err(true, &ts->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, &ts->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 stm_ts_data *ts = container_of(sec, struct stm_ts_data, sec); char buff[SEC_CMD_STR_LEN] = { 0 }; int ret; u8 data[STM_TS_EVENT_BUFF_SIZE + 1]; int retry = 10; ret = stm_ts_cmd_preparation(sec, false); if (ret < 0) return; stm_ts_systemreset(ts, 0); disable_irq(ts->irq); memset(data, 0x00, 8); data[0] = 0xA4; data[1] = 0x04; data[2] = 0x00; data[3] = 0x04; ret = ts->stm_ts_write(ts, &data[0], 4, NULL, 0); if (ret < 0) { input_err(true, &ts->client->dev, "%s: write 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; stm_ts_reinit(ts); enable_irq(ts->irq); return; } sec_delay(5); memset(data, 0x00, STM_TS_EVENT_BUFF_SIZE); data[0] = STM_TS_READ_ONE_EVENT; while (ts->stm_ts_read(ts, &data[0], 1, &data[1], STM_TS_EVENT_BUFF_SIZE) >= 0) { input_info(true, &ts->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] == STM_TS_EVENT_ERROR_REPORT) { snprintf(buff, sizeof(buff), "NG"); sec->cmd_state = SEC_CMD_STATUS_FAIL; break; } else if (data[1] == 0x03) { snprintf(buff, sizeof(buff), "OK"); sec->cmd_state = SEC_CMD_STATUS_OK; break; } else if (retry < 0) { snprintf(buff, sizeof(buff), "NG"); sec->cmd_state = SEC_CMD_STATUS_FAIL; break; } retry--; sec_delay(50); } stm_ts_reinit(ts); enable_irq(ts->irq); sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); input_info(true, &ts->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 stm_ts_data *ts = container_of(sec, struct stm_ts_data, 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; ret = stm_ts_cmd_preparation(sec, false); if (ret < 0) return; if (sec->cmd_param[0] < 1 || sec->cmd_param[0] > 1000) { input_err(true, &ts->client->dev, "%s: strange value frame:%d\n", __func__, sec->cmd_param[0]); goto ERROR_INIT; } ret = stm_ts_fix_active_mode(ts, STM_TS_ACTIVE_TRUE); if (ret < 0) { input_err(true, &ts->client->dev, "%s: failed to set active mode\n", __func__); goto ERROR_INIT; } /* 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 = ts->stm_ts_write(ts, &address[0], 5, NULL, 0); if (ret < 0) { input_err(true, &ts->client->dev, "%s: i2c_write failed\n", __func__); goto ERROR; } /* enter SNR mode */ address[0] = 0x70; address[1] = 0x25; ret = ts->stm_ts_write(ts, &address[0], 2, NULL, 0); if (ret < 0) { input_err(true, &ts->client->dev, "%s: i2c_write failed\n", __func__); goto ERROR; } wait_time = (sec->cmd_param[0] * 1000) / 120 + 200; /* frame count * 1000 / frame rate + 200 msec margin*/ sec_delay(wait_time); retry_cnt = 50; address[0] = STM_TS_CMD_SNR_R; while ((ts->stm_ts_read(ts, &address[0], 1, (u8 *)&status, STM_TS_CMD_SNR_R_SIZE) >= 0) && (retry_cnt-- > 0)) { if (status == 1) break; sec_delay(20); } if (status == 0) { input_err(true, &ts->client->dev, "%s: failed non-touched status:%d\n", __func__, status); goto ERROR; } 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; ts->stm_ts_write(ts, &address[0], 2, NULL, 0); stm_ts_fix_active_mode(ts, STM_TS_ACTIVE_FALSE_SNR); input_info(true, &ts->client->dev, "%s: %s\n", __func__, buff); return; ERROR: address[0] = 0x70; address[1] = 0x00; ts->stm_ts_write(ts, &address[0], 2, NULL, 0); stm_ts_fix_active_mode(ts, STM_TS_ACTIVE_FALSE_SNR); ERROR_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, &ts->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 stm_ts_data *ts = container_of(sec, struct stm_ts_data, 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; ret = stm_ts_cmd_preparation(sec, false); if (ret < 0) return; memset(&snr_result, 0, sizeof(struct stm_ts_snr_result)); memset(&snr_cmd_result, 0, sizeof(struct stm_ts_snr_result_cmd)); if (sec->cmd_param[0] < 1 || sec->cmd_param[0] > 1000) { input_err(true, &ts->client->dev, "%s: strange value frame:%d\n", __func__, sec->cmd_param[0]); goto ERROR_INIT; } ret = stm_ts_fix_active_mode(ts, STM_TS_ACTIVE_TRUE); if (ret < 0) { input_err(true, &ts->client->dev, "%s: failed to set active mode\n", __func__); goto ERROR_INIT; } /* 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 = ts->stm_ts_write(ts, &address[0], 5, NULL, 0); if (ret < 0) { input_err(true, &ts->client->dev, "%s: i2c_write failed\n", __func__); goto ERROR; } /* enter SNR mode */ address[0] = 0x70; address[1] = 0x25; ret = ts->stm_ts_write(ts, &address[0], 2, NULL, 0); if (ret < 0) { input_err(true, &ts->client->dev, "%s: i2c_write failed\n", __func__); goto ERROR; } wait_time = (sec->cmd_param[0] * 1000) / 120 + 200; /* frame count * 1000 / frame rate + 200 msec margin*/ sec_delay(wait_time); retry_cnt = 50; memset(address, 0x00, 5); address[0] = STM_TS_CMD_SNR_R; while ((ts->stm_ts_read(ts, &address[0], 1, (u8 *)&snr_cmd_result, 6) >= 0) && (retry_cnt-- > 0)) { if (snr_cmd_result.status == 1) break; sec_delay(20); } if (snr_cmd_result.status == 0) { input_err(true, &ts->client->dev, "%s: failed non-touched status:%d\n", __func__, snr_cmd_result.status); goto ERROR; } else { input_info(true, &ts->client->dev, "%s: status:%d, point:%d, average:%d\n", __func__, snr_cmd_result.status, snr_cmd_result.point, snr_cmd_result.average); } memset(address, 0x00, 5); address[0] = STM_TS_CMD_SNR_R; ret = ts->stm_ts_read(ts, &address[0], 1, (u8 *)&snr_result, sizeof(struct stm_ts_snr_result)); if (ret < 0) { input_err(true, &ts->client->dev, "%s: i2c_write failed size:%ld\n", __func__, sizeof(struct stm_ts_snr_result)); goto ERROR; } for (i = 0; i < 9; i++) { input_info(true, &ts->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; ts->stm_ts_write(ts, &address[0], 2, NULL, 0); stm_ts_fix_active_mode(ts, STM_TS_ACTIVE_FALSE_SNR); input_info(true, &ts->client->dev, "%s: %s\n", __func__, buff); return; ERROR: address[0] = 0x70; address[1] = 0x00; ts->stm_ts_write(ts, &address[0], 2, NULL, 0); stm_ts_fix_active_mode(ts, STM_TS_ACTIVE_FALSE_SNR); ERROR_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, &ts->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 stm_ts_data *ts = container_of(sec, struct stm_ts_data, sec); char buff[SEC_CMD_STR_LEN]; u8 reg; u8 data[STM_TS_EVENT_BUFF_SIZE]; int rc, retry = 0; sec_cmd_set_default_result(sec); ts->stm_ts_systemreset(ts, 0); mutex_lock(&ts->fn_mutex); disable_irq(ts->irq); reg = STM_TS_CMD_RUN_SRAM_TEST; rc = ts->stm_ts_write(ts, ®, 1, NULL, 0); if (rc < 0) { input_err(true, &ts->client->dev, "%s: failed to write cmd\n", __func__); goto error; } sec_delay(300); memset(data, 0x0, STM_TS_EVENT_BUFF_SIZE); rc = -EIO; reg = STM_TS_READ_ONE_EVENT; while (ts->stm_ts_read(ts, ®, 1, data, STM_TS_EVENT_BUFF_SIZE) >= 0) { if (data[0] != 0x00) input_info(true, &ts->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] == STM_TS_EVENT_PASS_REPORT && data[1] == STM_TS_EVENT_SRAM_TEST_RESULT) { rc = 0; /* PASS */ break; } else if (data[0] == STM_TS_EVENT_ERROR_REPORT && data[1] == STM_TS_EVENT_SRAM_TEST_RESULT) { rc = 1; /* FAIL */ break; } if (retry++ > STM_TS_RETRY_COUNT * 25) { input_err(true, &ts->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; } sec_delay(20); } error: mutex_unlock(&ts->fn_mutex); 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))); stm_ts_reinit(ts); enable_irq(ts->irq); } static void run_polarity_test(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct stm_ts_data *ts = container_of(sec, struct stm_ts_data, sec); char buff[SEC_CMD_STR_LEN]; u8 reg; u8 data[STM_TS_EVENT_BUFF_SIZE]; int rc, retry = 0; sec_cmd_set_default_result(sec); ts->stm_ts_systemreset(ts, 0); mutex_lock(&ts->fn_mutex); disable_irq(ts->irq); reg = STM_TS_CMD_RUN_POLARITY_TEST; rc = ts->stm_ts_write(ts, ®, 1, NULL, 0); if (rc < 0) { input_err(true, &ts->client->dev, "%s: failed to write cmd\n", __func__); goto error; } sec_delay(300); memset(data, 0x0, STM_TS_EVENT_BUFF_SIZE); rc = -EIO; reg = STM_TS_READ_ONE_EVENT; while (ts->stm_ts_read(ts, ®, 1, data, STM_TS_EVENT_BUFF_SIZE) >= 0) { input_info(true, &ts->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] == STM_TS_EVENT_PASS_REPORT) { rc = 0; /* PASS */ break; } else if (data[0] == STM_TS_EVENT_ERROR_REPORT) { rc = 1; /* FAIL */ break; } if (retry++ > STM_TS_RETRY_COUNT * 25) { input_err(true, &ts->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; } sec_delay(20); } error: mutex_unlock(&ts->fn_mutex); if (rc == 0) { snprintf(buff, sizeof(buff), "0"); sec->cmd_state = SEC_CMD_STATUS_OK; } else { snprintf(buff, sizeof(buff), "1"); sec->cmd_state = SEC_CMD_STATUS_FAIL; } if (sec->cmd_all_factory_state == SEC_CMD_STATUS_RUNNING) sec_cmd_set_cmd_result_all(sec, buff, strnlen(buff, sizeof(buff)), "POLARITY"); sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); stm_ts_reinit(ts); enable_irq(ts->irq); } static void run_force_calibration(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct stm_ts_data *ts = container_of(sec, struct stm_ts_data, sec); char buff[SEC_CMD_STR_LEN] = { 0 }; bool touch_on = false; sec_cmd_set_default_result(sec); if (ts->plat_data->power_state == SEC_INPUT_STATE_POWER_OFF) { input_err(true, &ts->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 ts->tdata->external_factory = false; #endif return; } if (ts->tsp_dump_lock == 1) { input_err(true, &ts->client->dev, "%s: ramdump mode is running, %d\n", __func__, ts->tsp_dump_lock); goto autotune_fail; } if (ts->plat_data->touch_count > 0) { touch_on = true; input_err(true, &ts->client->dev, "%s: finger on touch(%d)\n", __func__, ts->plat_data->touch_count); } ts->stm_ts_systemreset(ts, 0); stm_ts_release_all_finger(ts); if (touch_on) { input_err(true, &ts->client->dev, "%s: finger! do not run autotune\n", __func__); } else { input_info(true, &ts->client->dev, "%s: run autotune\n", __func__); input_err(true, &ts->client->dev, "%s: RUN OFFSET CALIBRATION\n", __func__); if (stm_ts_execute_autotune(ts, true) < 0) { stm_ts_set_scanmode(ts, ts->scan_mode); goto autotune_fail; } #ifdef TCLM_CONCEPT /* devide tclm case */ sec_tclm_case(ts->tdata, sec->cmd_param[0]); input_info(true, &ts->client->dev, "%s: param, %d, %c, %d\n", __func__, sec->cmd_param[0], sec->cmd_param[0], ts->tdata->root_of_calibration); if (sec_execute_tclm_package(ts->tdata, 1) < 0) input_err(true, &ts->client->dev, "%s: sec_execute_tclm_package\n", __func__); sec_tclm_root_of_cal(ts->tdata, CALPOSITION_NONE); #endif } stm_ts_set_scanmode(ts, ts->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 ts->tdata->external_factory = false; #endif input_info(true, &ts->client->dev, "%s: %s\n", __func__, buff); return; autotune_fail: #ifdef TCLM_CONCEPT ts->tdata->external_factory = false; #endif 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, &ts->client->dev, "%s: %s\n", __func__, buff); } static void run_interrupt_gpio_test(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct stm_ts_data *ts = container_of(sec, struct stm_ts_data, sec); char buff[SEC_CMD_STR_LEN]; u8 drv_data[3] = { 0xA4, 0x01, 0x01 }; u8 irq_data[3] = { 0xA4, 0x01, 0x00 }; int drv_value = -1; int irq_value = -1; sec_cmd_set_default_result(sec); disable_irq(ts->irq); ts->stm_ts_write(ts, drv_data, 3, NULL, 0); sec_delay(50); drv_value = gpio_get_value(ts->plat_data->irq_gpio); ts->stm_ts_write(ts, irq_data, 3, NULL, 0); sec_delay(50); irq_value = gpio_get_value(ts->plat_data->irq_gpio); input_info(true, &ts->client->dev, "%s: drv_value:%d, irq_value:%d\n", __func__, drv_value, irq_value); if (drv_value == 0 && irq_value == 1) { snprintf(buff, sizeof(buff), "0"); sec->cmd_state = SEC_CMD_STATUS_OK; } else { if (drv_value != 0) snprintf(buff, sizeof(buff), "1:HIGH"); else if (irq_value != 1) snprintf(buff, sizeof(buff), "1:LOW"); else snprintf(buff, sizeof(buff), "1:FAIL"); sec->cmd_state = SEC_CMD_STATUS_FAIL; } if (sec->cmd_all_factory_state == SEC_CMD_STATUS_RUNNING) sec_cmd_set_cmd_result_all(sec, buff, strnlen(buff, sizeof(buff)), "INT_GPIO"); sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); stm_ts_reinit(ts); enable_irq(ts->irq); } static void set_factory_level(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct stm_ts_data *ts = container_of(sec, struct stm_ts_data, sec); char buff[SEC_CMD_STR_LEN] = { 0 }; sec_cmd_set_default_result(sec); if (ts->plat_data->power_state == SEC_INPUT_STATE_POWER_OFF) { input_err(true, &ts->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, &ts->client->dev, "%s: cmd data is abnormal, %d\n", __func__, sec->cmd_param[0]); goto NG; } ts->factory_position = sec->cmd_param[0]; input_info(true, &ts->client->dev, "%s: %d\n", __func__, ts->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))); } static void factory_cmd_result_all(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct stm_ts_data *ts = container_of(sec, struct stm_ts_data, sec); sec->item_count = 0; memset(sec->cmd_result_all, 0x00, SEC_CMD_RESULT_STR_LEN); if (ts->plat_data->power_state == SEC_INPUT_STATE_POWER_OFF) { input_err(true, &ts->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(ts, true); run_lp_single_ended_rawcap_read(sec); /* Mutual raw */ run_self_raw_read(sec); stm_ts_set_scanmode(ts, STM_TS_SCAN_MODE_SCAN_OFF); stm_ts_release_all_finger(ts); 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); enter_factory_mode(ts, false); run_mutual_jitter(sec); run_self_jitter(sec); run_factory_miscalibration(sec); run_sram_test(sec); run_polarity_test(sec); run_interrupt_gpio_test(sec); sec->cmd_all_factory_state = SEC_CMD_STATUS_OK; out: input_info(true, &ts->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 stm_ts_data *ts = container_of(sec, struct stm_ts_data, sec); sec->item_count = 0; memset(sec->cmd_result_all, 0x00, SEC_CMD_RESULT_STR_LEN); if (ts->plat_data->power_state == SEC_INPUT_STATE_POWER_OFF) { input_err(true, &ts->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, &ts->client->dev, "%s: %d%s\n", __func__, sec->item_count, sec->cmd_result_all); } static void glove_mode(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct stm_ts_data *ts = container_of(sec, struct stm_ts_data, 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 { ts->glove_enabled = sec->cmd_param[0]; if (ts->plat_data->power_state != SEC_INPUT_STATE_POWER_OFF) { if (ts->glove_enabled) ts->plat_data->touch_functions = ts->plat_data->touch_functions | STM_TS_TOUCHTYPE_BIT_GLOVE; else ts->plat_data->touch_functions = (ts->plat_data->touch_functions & (~STM_TS_TOUCHTYPE_BIT_GLOVE)); } if (ts->probe_done) stm_ts_set_touch_function(ts); else input_info(true, &ts->client->dev, "%s: probe is not done\n", __func__); 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, &ts->client->dev, "%s: %s\n", __func__, buff); } static void clear_cover_mode(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct stm_ts_data *ts = container_of(sec, struct stm_ts_data, 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) ts->plat_data->cover_type = sec->cmd_param[1]; if (ts->probe_done) { if (sec->cmd_param[0] > 1) stm_ts_set_cover_type(ts, true); else stm_ts_set_cover_type(ts, false); } else { input_info(true, &ts->client->dev, "%s: probe is not done\n", __func__); } 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, &ts->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 stm_ts_data *ts = container_of(sec, struct stm_ts_data, sec); char buff[SEC_CMD_STR_LEN] = { 0 }; u8 scan_rate; sec_cmd_set_default_result(sec); if (ts->plat_data->power_state == SEC_INPUT_STATE_POWER_OFF) { input_err(true, &ts->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]; stm_ts_change_scan_rate(ts, 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, &ts->client->dev, "%s: %s\n", __func__, buff); } static void set_wirelesscharger_mode(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct stm_ts_data *ts = container_of(sec, struct stm_ts_data, sec); char buff[SEC_CMD_STR_LEN] = { 0 }; #if IS_ENABLED(CONFIG_INPUT_SEC_NOTIFIER) u8 reg[3]; #endif int ret = 0; sec_cmd_set_default_result(sec); ret = sec_input_check_wirelesscharger_mode(&ts->client->dev, sec->cmd_param[0], sec->cmd_param[1]); if (ret == SEC_ERROR) goto NG; else if (ret == SEC_SKIP) goto OK; #if IS_ENABLED(CONFIG_INPUT_SEC_NOTIFIER) reg[0] = STM_TS_CMD_SET_FUNCTION_ONOFF; reg[1] = STM_TS_CMD_FUNCTION_SET_TSP_BLOCK; reg[2] = 0; ret = ts->stm_ts_write(ts, reg, 3, NULL, 0); input_info(true, &ts->client->dev, "%s: force tsp unblock, ret=%d\n", __func__, ret); sec_input_gesture_report(&ts->client->dev, SPONGE_EVENT_TYPE_TSP_SCAN_UNBLOCK, 0, 0); #endif ret = stm_ts_set_wirelesscharger_mode(ts); if (ret < 0) goto NG; OK: 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); }; /* * 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 stm_ts_data *ts = container_of(sec, struct stm_ts_data, sec); char buff[SEC_CMD_STR_LEN] = { 0 }; u8 mode = G_NONE; sec_cmd_set_default_result(sec); mutex_lock(&ts->device_mutex); if (sec->cmd_param[0] == 0) { // edge handler if (sec->cmd_param[1] == 0) { // clear ts->plat_data->grip_data.edgehandler_direction = 0; } else if (sec->cmd_param[1] < 3) { ts->plat_data->grip_data.edgehandler_direction = sec->cmd_param[1]; ts->plat_data->grip_data.edgehandler_start_y = sec->cmd_param[2]; ts->plat_data->grip_data.edgehandler_end_y = sec->cmd_param[3]; } else { input_err(true, &ts->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; stm_set_grip_data_to_ic(&ts->client->dev, mode); } else if (sec->cmd_param[0] == 1) { // normal mode if (ts->plat_data->grip_data.edge_range != sec->cmd_param[1]) mode = mode | G_SET_EDGE_ZONE; ts->plat_data->grip_data.edge_range = sec->cmd_param[1]; ts->plat_data->grip_data.deadzone_up_x = sec->cmd_param[2]; ts->plat_data->grip_data.deadzone_dn_x = sec->cmd_param[3]; ts->plat_data->grip_data.deadzone_y = sec->cmd_param[4]; /* 3rd reject zone */ ts->plat_data->grip_data.deadzone_dn2_x = sec->cmd_param[5]; ts->plat_data->grip_data.deadzone_dn_y = sec->cmd_param[6]; mode = mode | G_SET_NORMAL_MODE; if (ts->plat_data->grip_data.landscape_mode == 1) { ts->plat_data->grip_data.landscape_mode = 0; mode = mode | G_CLR_LANDSCAPE_MODE; } stm_set_grip_data_to_ic(&ts->client->dev, mode); } else if (sec->cmd_param[0] == 2) { // landscape mode if (sec->cmd_param[1] == 0) { // normal mode ts->plat_data->grip_data.landscape_mode = 0; mode = mode | G_CLR_LANDSCAPE_MODE; } else if (sec->cmd_param[1] == 1) { ts->plat_data->grip_data.landscape_mode = 1; ts->plat_data->grip_data.landscape_edge = sec->cmd_param[2]; ts->plat_data->grip_data.landscape_deadzone = sec->cmd_param[3]; ts->plat_data->grip_data.landscape_top_deadzone = sec->cmd_param[4]; ts->plat_data->grip_data.landscape_bottom_deadzone = sec->cmd_param[5]; ts->plat_data->grip_data.landscape_top_gripzone = sec->cmd_param[6]; ts->plat_data->grip_data.landscape_bottom_gripzone = sec->cmd_param[7]; mode = mode | G_SET_LANDSCAPE_MODE; } else { input_err(true, &ts->client->dev, "%s: cmd1 is abnormal, %d (%d)\n", __func__, sec->cmd_param[1], __LINE__); goto err_grip_data; } stm_set_grip_data_to_ic(&ts->client->dev, mode); } else { input_err(true, &ts->client->dev, "%s: cmd0 is abnormal, %d", __func__, sec->cmd_param[0]); goto err_grip_data; } mutex_unlock(&ts->device_mutex); input_cmd_result(SEC_CMD_STATUS_OK, INPUT_CMD_RESULT_NEED_EXIT); return; err_grip_data: mutex_unlock(&ts->device_mutex); input_cmd_result(SEC_CMD_STATUS_FAIL, INPUT_CMD_RESULT_NEED_EXIT); } static void dead_zone_enable(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct stm_ts_data *ts = container_of(sec, struct stm_ts_data, sec); char buff[SEC_CMD_STR_LEN] = { 0 }; u8 reg[3] = {STM_TS_CMD_SET_FUNCTION_ONOFF, STM_TS_FUNCTION_ENABLE_DEAD_ZONE, 0x00}; int ret; sec_cmd_set_default_result(sec); if (sec->cmd_param[0] < 0 || sec->cmd_param[0] > 1) { input_cmd_result(SEC_CMD_STATUS_FAIL, INPUT_CMD_RESULT_NEED_EXIT); } else { if (sec->cmd_param[0] == 0) reg[2] = 0x01; /* dead zone disable */ else reg[2] = 0x00; /* dead zone enable */ ret = ts->stm_ts_write(ts, reg, 3, NULL, 0); if (ret < 0) { input_err(true, &ts->client->dev, "%s: failed. ret: %d\n", __func__, ret); input_cmd_result(SEC_CMD_STATUS_FAIL, INPUT_CMD_RESULT_NEED_EXIT); } else { input_info(true, &ts->client->dev, "%s: reg:%d, ret: %d\n", __func__, sec->cmd_param[0], ret); input_cmd_result(SEC_CMD_STATUS_OK, INPUT_CMD_RESULT_NEED_EXIT); } } } static void drawing_test_enable(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct stm_ts_data *ts = container_of(sec, struct stm_ts_data, 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, &ts->client->dev, "%s: %s\n", __func__, buff); } static void vvc_enable(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct stm_ts_data *ts = container_of(sec, struct stm_ts_data, sec); char buff[SEC_CMD_STR_LEN] = { 0 }; sec_cmd_set_default_result(sec); if (sec->cmd_param[0]) ts->plat_data->lowpower_mode |= SEC_TS_MODE_SPONGE_VVC; else ts->plat_data->lowpower_mode &= ~SEC_TS_MODE_SPONGE_VVC; ts->vvc_mode = sec->cmd_param[0]; input_info(true, &ts->client->dev, "%s: %s, mode: %02X\n", __func__, sec->cmd_param[0] ? "on" : "off", ts->vvc_mode); 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, &ts->client->dev, "%s: %d\n", __func__, sec->cmd_param[0]); } static void spay_enable(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct stm_ts_data *ts = container_of(sec, struct stm_ts_data, 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; sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); sec_cmd_set_cmd_exit(sec); return; } if (sec->cmd_param[0]) ts->plat_data->lowpower_mode |= SEC_TS_MODE_SPONGE_SWIPE; else ts->plat_data->lowpower_mode &= ~SEC_TS_MODE_SPONGE_SWIPE; input_info(true, &ts->client->dev, "%s: %s, %02X\n", __func__, sec->cmd_param[0] ? "on" : "off", ts->plat_data->lowpower_mode); stm_ts_set_custom_library(ts); 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, &ts->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 stm_ts_data *ts = container_of(sec, struct stm_ts_data, 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; sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); sec_cmd_set_cmd_exit(sec); return; } if (sec->cmd_param[0]) ts->plat_data->lowpower_mode |= SEC_TS_MODE_SPONGE_DOUBLETAP_TO_WAKEUP; else ts->plat_data->lowpower_mode &= ~SEC_TS_MODE_SPONGE_DOUBLETAP_TO_WAKEUP; input_info(true, &ts->client->dev, "%s: %s, %02X\n", __func__, sec->cmd_param[0] ? "on" : "off", ts->plat_data->lowpower_mode); if (ts->probe_done) stm_ts_set_custom_library(ts); else input_info(true, &ts->client->dev, "%s: probe is not done\n", __func__); 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, &ts->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 stm_ts_data *ts = container_of(sec, struct stm_ts_data, 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; sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); sec_cmd_set_cmd_exit(sec); return; } if (sec->cmd_param[0]) ts->plat_data->lowpower_mode |= SEC_TS_MODE_SPONGE_SINGLE_TAP; else ts->plat_data->lowpower_mode &= ~SEC_TS_MODE_SPONGE_SINGLE_TAP; input_info(true, &ts->client->dev, "%s: %s, %02X\n", __func__, sec->cmd_param[0] ? "on" : "off", ts->plat_data->lowpower_mode); if (ts->probe_done) stm_ts_set_custom_library(ts); else input_info(true, &ts->client->dev, "%s: probe is not done\n", __func__); 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, &ts->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 stm_ts_data *ts = container_of(sec, struct stm_ts_data, 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; sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); sec_cmd_set_cmd_exit(sec); return; } if (sec->cmd_param[0]) ts->plat_data->lowpower_mode |= SEC_TS_MODE_SPONGE_AOD; else ts->plat_data->lowpower_mode &= ~SEC_TS_MODE_SPONGE_AOD; input_info(true, &ts->client->dev, "%s: %s, %02X\n", __func__, sec->cmd_param[0] ? "on" : "off", ts->plat_data->lowpower_mode); if (ts->probe_done) stm_ts_set_custom_library(ts); else input_info(true, &ts->client->dev, "%s: probe is not done\n", __func__); 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, &ts->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 stm_ts_data *ts = container_of(sec, struct stm_ts_data, sec); char buff[SEC_CMD_STR_LEN] = { 0 }; int i, ret = -1; sec_cmd_set_default_result(sec); #if !defined(CONFIG_SAMSUNG_PRODUCT_SHIP) input_info(true, &ts->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++) ts->plat_data->aod_data.rect_data[i] = sec->cmd_param[i]; ret = stm_ts_set_aod_rect(ts); if (ret < 0) { input_err(true, &ts->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); } static void get_aod_rect(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct stm_ts_data *ts = container_of(sec, struct stm_ts_data, 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); data[0] = STM_TS_CMD_SPONGE_OFFSET_AOD_RECT; ret = ts->stm_ts_read_sponge(ts, data, sizeof(data)); if (ret < 0) { input_err(true, &ts->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, &ts->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 stm_ts_data *ts = container_of(sec, struct stm_ts_data, 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; sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); sec_cmd_set_cmd_exit(sec); return; } else if (!ts->plat_data->support_fod) { 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); return; } if (sec->cmd_param[0]) ts->plat_data->lowpower_mode |= SEC_TS_MODE_SPONGE_PRESS; else ts->plat_data->lowpower_mode &= ~SEC_TS_MODE_SPONGE_PRESS; ts->plat_data->fod_data.press_prop = (sec->cmd_param[1] & 0x01) | ((sec->cmd_param[2] & 0x01) << 1); input_info(true, &ts->client->dev, "%s: %s, fast:%s, strict:%s, %02X\n", __func__, sec->cmd_param[0] ? "on" : "off", ts->plat_data->fod_data.press_prop & 1 ? "on" : "off", ts->plat_data->fod_data.press_prop & 2 ? "on" : "off", ts->plat_data->lowpower_mode); #if IS_ENABLED(CONFIG_INPUT_SEC_SECURE_TOUCH) #if IS_ENABLED(CONFIG_GH_RM_DRV) if (atomic_read(&ts->trusted_touch_enabled)) { input_info(true, &ts->client->dev, "%s trusted touch is enabled. skip\n", __func__); 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; } #endif #endif mutex_lock(&ts->modechange); if (!ts->plat_data->enabled && !ts->plat_data->lowpower_mode && !ts->plat_data->pocket_mode && !ts->plat_data->ed_enable && !ts->plat_data->fod_lp_mode) { if (device_may_wakeup(&ts->client->dev) && ts->plat_data->power_state == SEC_INPUT_STATE_LPM) disable_irq_wake(ts->client->irq); ts->plat_data->stop_device(ts); } else { stm_ts_set_custom_library(ts); stm_ts_set_press_property(ts); stm_ts_set_fod_finger_merge(ts); } mutex_unlock(&ts->modechange); 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; } static void fod_lp_mode(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct stm_ts_data *ts = container_of(sec, struct stm_ts_data, sec); char buff[64] = { 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; sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); sec_cmd_set_cmd_exit(sec); return; } else if (!ts->plat_data->support_fod_lp_mode) { 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); return; } ts->plat_data->fod_lp_mode = sec->cmd_param[0]; input_info(true, &ts->client->dev, "%s: %d\n", __func__, ts->plat_data->fod_lp_mode); snprintf(buff, sizeof(buff), "%s", "OK"); sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); sec->cmd_state = SEC_CMD_STATUS_OK; sec_cmd_set_cmd_exit(sec); } static void set_fod_rect(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct stm_ts_data *ts = container_of(sec, struct stm_ts_data, sec); char buff[SEC_CMD_STR_LEN] = { 0 }; int ret = 0; sec_cmd_set_default_result(sec); input_info(true, &ts->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]); if (!ts->plat_data->support_fod) { 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); return; } if (!sec_input_set_fod_rect(&ts->client->dev, sec->cmd_param)) goto NG; if (ts->plat_data->power_state == SEC_INPUT_STATE_POWER_OFF) { input_err(true, &ts->client->dev, "%s: Touch is stopped! Set data at reinit()\n", __func__); goto OK; } ret = stm_ts_set_fod_rect(ts); if (ret < 0) goto NG; OK: 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 fp_int_control(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct stm_ts_data *ts = container_of(sec, struct stm_ts_data, sec); char buff[SEC_CMD_STR_LEN] = { 0 }; int ret; u8 reg[2] = {STM_TS_CMD_SET_FOD_INT_CONTROL, 0x00}; u8 enable; sec_cmd_set_default_result(sec); if (ts->plat_data->power_state == SEC_INPUT_STATE_POWER_OFF) { input_err(true, &ts->client->dev, "%s: Touch is stopped!\n", __func__); goto NG; } if (sec->cmd_param[0] < 0 || sec->cmd_param[0] > 1) { input_err(true, &ts->client->dev, "%s: invalid param %d\n", __func__, sec->cmd_param[0]); goto NG; } else if (!ts->plat_data->support_fod) { snprintf(buff, sizeof(buff), "NA"); sec->cmd_state = SEC_CMD_STATUS_NOT_APPLICABLE; sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); return; } enable = sec->cmd_param[0]; if (enable) reg[1] = 0x01; else reg[1] = 0x00; ret = ts->stm_ts_write(ts, reg, 2, NULL, 0); if (ret < 0) { input_err(true, &ts->client->dev, "%s: failed. ret: %d\n", __func__, ret); goto NG; } input_info(true, &ts->client->dev, "%s: fod int %d\n", __func__, enable); snprintf(buff, sizeof(buff), "OK"); sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); sec->cmd_state = SEC_CMD_STATUS_OK; 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))); } /* * 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 stm_ts_data *ts = container_of(sec, struct stm_ts_data, 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, &ts->client->dev, "%s: not support param\n", __func__); goto NG; } if (sec->cmd_param[1] == 1) ts->plat_data->external_noise_mode |= 1 << sec->cmd_param[0]; else ts->plat_data->external_noise_mode &= ~(1 << sec->cmd_param[0]); ret = stm_ts_set_external_noise_mode(ts, ts->plat_data->external_noise_mode); 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 stm_ts_data *ts = container_of(sec, struct stm_ts_data, sec); char buff[SEC_CMD_STR_LEN] = { 0 }; u8 reg[3] = {STM_TS_CMD_SET_FUNCTION_ONOFF, STM_TS_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; } ts->brush_mode = sec->cmd_param[0]; if (ts->plat_data->power_state == SEC_INPUT_STATE_POWER_OFF) { input_err(true, &ts->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, &ts->client->dev, "%s: set brush mode %s\n", __func__, ts->brush_mode ? "enable" : "disable"); if (ts->brush_mode == 0) reg[2] = 0x00; /* 0: Disable Artcanvas min phi mode */ else reg[2] = 0x01; /* 1: Enable Artcanvas min phi mode */ ret = ts->stm_ts_write(ts, ®[0], 3, NULL, 0); if (ret < 0) { input_err(true, &ts->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, &ts->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 stm_ts_data *ts = container_of(sec, struct stm_ts_data, 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; goto out; } ts->plat_data->touchable_area = sec->cmd_param[0]; if (ts->plat_data->power_state == SEC_INPUT_STATE_POWER_OFF) { input_err(true, &ts->client->dev, "%s: Touch is stopped!\n", __func__); snprintf(buff, sizeof(buff), "NG"); sec->cmd_state = SEC_CMD_STATUS_FAIL; goto out; } ret = stm_ts_set_touchable_area(ts); if (ret < 0) { 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, &ts->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 stm_ts_data *ts = container_of(sec, struct stm_ts_data, sec); char buff[SEC_CMD_STR_LEN] = { 0 }; sec_cmd_set_default_result(sec); ts->debug_flag = sec->cmd_param[0]; input_info(true, &ts->client->dev, "%s: command is %d\n", __func__, ts->debug_flag); 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, &ts->client->dev, "%s: %s\n", __func__, buff); } static void rawdata_init(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct stm_ts_data *ts = container_of(sec, struct stm_ts_data, sec); char buff[SEC_CMD_STR_LEN] = { 0 }; sec_cmd_set_default_result(sec); #ifdef ENABLE_RAWDATA_SERVICE if (sec->cmd_param[0] == 0) { ts->raw_mode = sec->cmd_param[0]; ts->raw_addr_h = 0; ts->raw_addr_l = 0; } else { // param : 1 -> strength // param : 2 -> raw ts->raw_mode = sec->cmd_param[0]; if (!ts->raw) stm_ts_rawdata_buffer_alloc(ts); else input_info(true, &ts->client->dev, "%s: already init\n", __func__); stm_ts_read_rawdata_address(ts); } #endif snprintf(buff, sizeof(buff), "OK:%d", ts->plat_data->support_rawdata_map_num); sec->cmd_state = SEC_CMD_STATUS_OK; sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff))); input_info(true, &ts->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 stm_ts_data *ts = container_of(sec, struct stm_ts_data, 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 (ts->plat_data->power_state == SEC_INPUT_STATE_POWER_ON) stm_ts_fix_active_mode(ts, !!sec->cmd_param[0]); ts->fix_active_mode = !!sec->cmd_param[0]; 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, &ts->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 stm_ts_data *ts = container_of(sec, struct stm_ts_data, sec); char buff[SEC_CMD_STR_LEN] = { 0 }; char reg[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 { ts->touch_aging_mode = sec->cmd_param[0]; if (ts->touch_aging_mode) { reg[0] = 0xA0; reg[1] = 0x03; reg[2] = 0x20; ts->stm_ts_write(ts, ®[0], 3, NULL, 0); } else { stm_ts_reinit(ts); } 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, &ts->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 stm_ts_data *ts = container_of(sec, struct stm_ts_data, sec); char buff[SEC_CMD_STR_LEN] = { 0 }; int ret = 0; sec_cmd_set_default_result(sec); if (!ts->plat_data->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 { ts->plat_data->ed_enable = sec->cmd_param[0]; if (ts->probe_done) ret = stm_ts_ear_detect_enable(ts, ts->plat_data->ed_enable); else input_info(true, &ts->client->dev, "%s: probe is not done\n", __func__); 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, &ts->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 stm_ts_data *ts = container_of(sec, struct stm_ts_data, sec); char buff[SEC_CMD_STR_LEN] = { 0 }; int ret; sec_cmd_set_default_result(sec); if (!ts->plat_data->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 { ts->plat_data->pocket_mode = sec->cmd_param[0]; ret = stm_ts_pocket_mode_enable(ts, ts->plat_data->pocket_mode); 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, &ts->client->dev, "%s: %s\n", __func__, buff); } static void low_sensitivity_mode_enable(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct stm_ts_data *ts = container_of(sec, struct stm_ts_data, sec); char buff[SEC_CMD_STR_LEN] = { 0 }; int ret; u8 reg[2] = { 0 }; sec_cmd_set_default_result(sec); #if IS_ENABLED(CONFIG_INPUT_SEC_SECURE_TOUCH) #if IS_ENABLED(CONFIG_GH_RM_DRV) if (atomic_read(&ts->trusted_touch_enabled)) { input_info(true, &ts->client->dev, "%s trusted touch is enabled. skip\n", __func__); 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); return; } #endif #endif if (sec->cmd_param[0] < 0 || sec->cmd_param[0] > 3) { snprintf(buff, sizeof(buff), "NG"); sec->cmd_state = SEC_CMD_STATUS_FAIL; } else { mutex_lock(&ts->modechange); ts->plat_data->low_sensitivity_mode = sec->cmd_param[0]; reg[0] = STM_TS_CMD_FUNCTION_SET_LOW_SENSITIVITY_MODE; reg[1] = sec->cmd_param[0]; ret = ts->stm_ts_write(ts, reg, 2, NULL, 0); if (ret < 0) { snprintf(buff, sizeof(buff), "NG"); sec->cmd_state = SEC_CMD_STATUS_FAIL; } else { input_info(true, &ts->client->dev, "%s: %s\n", __func__, reg[1] ? "enable" : "disable"); snprintf(buff, sizeof(buff), "OK"); sec->cmd_state = SEC_CMD_STATUS_OK; } mutex_unlock(&ts->modechange); } 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, &ts->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 stm_ts_data *ts = container_of(sec, struct stm_ts_data, 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] = STM_TS_CMD_SET_FUNCTION_ONOFF; reg[1] = STM_TS_FUNCTION_ENABLE_SIP_MODE; reg[2] = sec->cmd_param[0]; ret = ts->stm_ts_write(ts, reg, 3, NULL, 0); if (ret < 0) { snprintf(buff, sizeof(buff), "NG"); sec->cmd_state = SEC_CMD_STATUS_FAIL; } else { input_info(true, &ts->client->dev, "%s: %s\n", __func__, reg[2] ? "enable" : "disable"); 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, &ts->client->dev, "%s: %s\n", __func__, buff); } static void set_game_mode(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct stm_ts_data *ts = container_of(sec, struct stm_ts_data, 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] = STM_TS_CMD_SET_FUNCTION_ONOFF; reg[1] = STM_TS_CMD_FUNCTION_SET_GAME_MODE; reg[2] = sec->cmd_param[0]; ret = ts->stm_ts_write(ts, reg, 3, NULL, 0); if (ret < 0) { snprintf(buff, sizeof(buff), "NG"); sec->cmd_state = SEC_CMD_STATUS_FAIL; } else { input_info(true, &ts->client->dev, "%s: %s\n", __func__, reg[2] ? "enable" : "disable"); 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, &ts->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 stm_ts_data *ts = container_of(sec, struct stm_ts_data, 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] = STM_TS_CMD_SET_FUNCTION_ONOFF; reg[1] = STM_TS_CMD_FUNCTION_SET_NOTE_MODE; reg[2] = sec->cmd_param[0]; ret = ts->stm_ts_write(ts, reg, 3, NULL, 0); if (ret < 0) { snprintf(buff, sizeof(buff), "NG"); sec->cmd_state = SEC_CMD_STATUS_FAIL; } else { input_info(true, &ts->client->dev, "%s: %s\n", __func__, reg[2] ? "enable" : "disable"); 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, &ts->client->dev, "%s: %s\n", __func__, buff); } static void not_support_cmd(void *device_data) { struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data; struct stm_ts_data *ts = container_of(sec, struct stm_ts_data, 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, &ts->client->dev, "%s: %s\n", __func__, buff); } struct sec_cmd sec_cmds[] = { {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("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("run_lcdoff_mutual_jitter", run_lcdoff_mutual_jitter),}, {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_prox_intensity_read_all", run_prox_intensity_read_all),}, {SEC_CMD("run_cs_raw_read_all", run_cs_raw_read_all),}, {SEC_CMD("run_cs_delta_read_all", run_cs_delta_read_all),}, {SEC_CMD("run_rawdata_read_all_for_ghost", run_rawdata_read_all),}, {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_trx_short_test", run_trx_short_test),}, #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_factory_miscalibration", run_factory_miscalibration),}, {SEC_CMD("run_factory_miscalibration_read_all", run_factory_miscalibration_read_all),}, {SEC_CMD("run_miscalibration", run_miscalibration),}, {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_cx_data_read", run_cx_data_read),}, {SEC_CMD("run_cx_data_read_all", run_cx_data_read_all),}, {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("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_elvss_test", run_elvss_test),}, {SEC_CMD("run_snr_non_touched", run_snr_non_touched),}, {SEC_CMD("run_snr_touched", run_snr_touched),}, {SEC_CMD("run_sram_test", run_sram_test),}, {SEC_CMD("run_polarity_test", run_polarity_test),}, {SEC_CMD("run_force_calibration", run_force_calibration),}, {SEC_CMD("run_interrupt_gpio_test", run_interrupt_gpio_test),}, {SEC_CMD("set_factory_level", set_factory_level),}, {SEC_CMD("factory_cmd_result_all", factory_cmd_result_all),}, {SEC_CMD("factory_cmd_result_all_imagetest", factory_cmd_result_all_imagetest),}, {SEC_CMD_H("glove_mode", glove_mode),}, {SEC_CMD_H("clear_cover_mode", clear_cover_mode),}, {SEC_CMD("report_rate", report_rate),}, {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("singletap_enable", singletap_enable),}, {SEC_CMD_H("vvc_enable", vvc_enable),}, {SEC_CMD_H("aot_enable", aot_enable),}, {SEC_CMD_H("aod_enable", aod_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_H("fod_lp_mode", fod_lp_mode),}, {SEC_CMD("set_fod_rect", set_fod_rect),}, {SEC_CMD_H("fp_int_control", fp_int_control),}, {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("rawdata_init", rawdata_init),}, {SEC_CMD_H("fix_active_mode", fix_active_mode),}, {SEC_CMD("touch_aging_mode", touch_aging_mode),}, {SEC_CMD_H("ear_detect_enable", ear_detect_enable),}, {SEC_CMD_H("pocket_mode_enable", pocket_mode_enable),}, {SEC_CMD("low_sensitivity_mode_enable", low_sensitivity_mode_enable),}, {SEC_CMD("set_sip_mode", set_sip_mode),}, {SEC_CMD("set_game_mode", set_game_mode),}, {SEC_CMD("set_note_mode", set_note_mode),}, {SEC_CMD("not_support_cmd", not_support_cmd),}, }; int stm_ts_fn_init(struct stm_ts_data *ts) { int retval = 0; #if IS_ENABLED(CONFIG_TOUCHSCREEN_DUAL_FOLDABLE) if (ts->plat_data->support_dual_foldable == MAIN_TOUCH) retval = sec_cmd_init(&ts->sec, sec_cmds, ARRAY_SIZE(sec_cmds), SEC_CLASS_DEVT_TSP1); else if (ts->plat_data->support_dual_foldable == SUB_TOUCH) retval = sec_cmd_init(&ts->sec, sec_cmds, ARRAY_SIZE(sec_cmds), SEC_CLASS_DEVT_TSP2); else retval = sec_cmd_init(&ts->sec, sec_cmds, ARRAY_SIZE(sec_cmds), SEC_CLASS_DEVT_TSP1); #else retval = sec_cmd_init(&ts->sec, sec_cmds, ARRAY_SIZE(sec_cmds), SEC_CLASS_DEVT_TSP); #endif if (retval < 0) { input_err(true, &ts->client->dev, "%s: Failed to sec_cmd_init\n", __func__); goto exit; } retval = sysfs_create_group(&ts->sec.fac_dev->kobj, &cmd_attr_group); if (retval < 0) { input_err(true, &ts->client->dev, "%s: Failed to create sysfs attributes\n", __func__); #if IS_ENABLED(CONFIG_TOUCHSCREEN_DUAL_FOLDABLE) if (ts->plat_data->support_dual_foldable == MAIN_TOUCH) sec_cmd_exit(&ts->sec, SEC_CLASS_DEVT_TSP1); else if (ts->plat_data->support_dual_foldable == SUB_TOUCH) sec_cmd_exit(&ts->sec, SEC_CLASS_DEVT_TSP2); else sec_cmd_exit(&ts->sec, SEC_CLASS_DEVT_TSP1); #else sec_cmd_exit(&ts->sec, SEC_CLASS_DEVT_TSP); #endif goto exit; } retval = sysfs_create_link(&ts->sec.fac_dev->kobj, &ts->plat_data->input_dev->dev.kobj, "input"); if (retval < 0) { input_err(true, &ts->client->dev, "%s: Failed to create input symbolic link\n", __func__); sysfs_remove_group(&ts->sec.fac_dev->kobj, &cmd_attr_group); #if IS_ENABLED(CONFIG_TOUCHSCREEN_DUAL_FOLDABLE) if (ts->plat_data->support_dual_foldable == MAIN_TOUCH) sec_cmd_exit(&ts->sec, SEC_CLASS_DEVT_TSP1); else if (ts->plat_data->support_dual_foldable == SUB_TOUCH) sec_cmd_exit(&ts->sec, SEC_CLASS_DEVT_TSP2); else sec_cmd_exit(&ts->sec, SEC_CLASS_DEVT_TSP1); #else sec_cmd_exit(&ts->sec, SEC_CLASS_DEVT_TSP); #endif goto exit; } retval = sec_input_sysfs_create(&ts->plat_data->input_dev->dev.kobj); if (retval < 0) { input_err(true, &ts->client->dev, "%s: Failed to create sec_input_sysfs attributes\n", __func__); sysfs_remove_link(&ts->sec.fac_dev->kobj, "input"); sysfs_remove_group(&ts->sec.fac_dev->kobj, &cmd_attr_group); #if IS_ENABLED(CONFIG_TOUCHSCREEN_DUAL_FOLDABLE) if (ts->plat_data->support_dual_foldable == MAIN_TOUCH) sec_cmd_exit(&ts->sec, SEC_CLASS_DEVT_TSP1); else if (ts->plat_data->support_dual_foldable == SUB_TOUCH) sec_cmd_exit(&ts->sec, SEC_CLASS_DEVT_TSP2); else sec_cmd_exit(&ts->sec, SEC_CLASS_DEVT_TSP1); #else sec_cmd_exit(&ts->sec, SEC_CLASS_DEVT_TSP); #endif goto exit; } #if IS_ENABLED(CONFIG_TOUCHSCREEN_DUAL_FOLDABLE) ts->sec.sysfs_functions->sec_tsp_support_feature_show = support_feature_show; ts->sec.sysfs_functions->sec_tsp_prox_power_off_show = prox_power_off_show; ts->sec.sysfs_functions->sec_tsp_prox_power_off_store = prox_power_off_store; ts->sec.sysfs_functions->dualscreen_policy_store = dualscreen_policy_store; #endif return 0; exit: return retval; } void stm_ts_fn_remove(struct stm_ts_data *ts) { input_err(true, &ts->client->dev, "%s\n", __func__); #if IS_ENABLED(CONFIG_TOUCHSCREEN_DUAL_FOLDABLE) ts->sec.sysfs_functions->sec_tsp_support_feature_show = NULL; ts->sec.sysfs_functions->sec_tsp_prox_power_off_show = NULL; ts->sec.sysfs_functions->sec_tsp_prox_power_off_store = NULL; ts->sec.sysfs_functions->dualscreen_policy_store = NULL; #endif sec_input_sysfs_remove(&ts->plat_data->input_dev->dev.kobj); sysfs_remove_link(&ts->sec.fac_dev->kobj, "input"); sysfs_remove_group(&ts->sec.fac_dev->kobj, &cmd_attr_group); #if IS_ENABLED(CONFIG_TOUCHSCREEN_DUAL_FOLDABLE) if (ts->plat_data->support_dual_foldable == MAIN_TOUCH) sec_cmd_exit(&ts->sec, SEC_CLASS_DEVT_TSP1); else if (ts->plat_data->support_dual_foldable == SUB_TOUCH) sec_cmd_exit(&ts->sec, SEC_CLASS_DEVT_TSP2); else sec_cmd_exit(&ts->sec, SEC_CLASS_DEVT_TSP1); #else sec_cmd_exit(&ts->sec, SEC_CLASS_DEVT_TSP); #endif } MODULE_LICENSE("GPL");