// SPDX-License-Identifier: GPL-2.0-or-later #define LOG_TAG "Oem" #include "cts_config.h" #include "cts_platform.h" #include "cts_core.h" #include "cts_oem.h" #include "cts_test.h" #include "cts_tcs.h" #include "cts_firmware.h" #include #include #include /* Following options override device tree settings */ #define OEM_OF_DEF_PROPVAL_TEST_RESET_PIN true #ifdef CFG_CTS_PLATFORM_MTK_TPD_SUPPORTED #define OEM_OF_DEF_PROPVAL_TEST_INT_PIN false #else #define OEM_OF_DEF_PROPVAL_TEST_INT_PIN true #endif #define OEM_OF_DEF_PROPVAL_TEST_RAWDATA true #define OEM_OF_DEF_PROPVAL_TEST_NOISE true #define OEM_OF_DEF_PROPVAL_TEST_OPEN true #define OEM_OF_DEF_PROPVAL_TEST_SHORT true #define OEM_OF_DEF_PROPVAL_TEST_COMP_CAP true /* Default settings if device tree NOT exist */ #define OEM_OF_DEF_PROPVAL_RAWDATA_FRAMES 1 #define OEM_OF_DEF_PROPVAL_RAWDATA_MIN 1000 #define OEM_OF_DEF_PROPVAL_RAWDATA_MAX 2000 #define OEM_OF_DEF_PROPVAL_NOISE_FRAMES 50 #define OEM_OF_DEF_PROPVAL_NOISE_MAX 80 #define OEM_OF_DEF_PROPVAL_OPEN_MIN 1000 #define OEM_OF_DEF_PROPVAL_SHORT_MIN 500 #define OEM_OF_DEF_PROPVAL_COMP_CAP_MIN 1 #define OEM_OF_DEF_PROPVAL_COMP_CAP_MAX 126 #define OEM_OF_PROPNAME_PREFIX "chipone," //modify #define OEM_OF_PROPNAME_TEST_RESET_PIN OEM_OF_PROPNAME_PREFIX"test-reset-pin" #define OEM_OF_PROPNAME_TEST_INT_PIN OEM_OF_PROPNAME_PREFIX"test-int-pin" #define OEM_OF_PROPNAME_TEST_RAWDATA OEM_OF_PROPNAME_PREFIX"test-rawdata" #define OEM_OF_PROPNAME_RAWDATA_FRAMES OEM_OF_PROPNAME_PREFIX"test-rawdata-frames" #define OEM_OF_PROPNAME_RAWDATA_MIN OEM_OF_PROPNAME_PREFIX"rawdata-min" #define OEM_OF_PROPNAME_RAWDATA_MAX OEM_OF_PROPNAME_PREFIX"rawdata-max" #define OEM_OF_PROPNAME_TEST_NOISE OEM_OF_PROPNAME_PREFIX"test-noise" #define OEM_OF_PROPNAME_NOISE_FRAMES OEM_OF_PROPNAME_PREFIX"test-noise-frames" #define OEM_OF_PROPNAME_NOISE_MAX OEM_OF_PROPNAME_PREFIX"noise-max" #define OEM_OF_PROPNAME_TEST_OPEN OEM_OF_PROPNAME_PREFIX"test-open" #define OEM_OF_PROPNAME_OPEN_MIN OEM_OF_PROPNAME_PREFIX"open-min" #define OEM_OF_PROPNAME_TEST_SHORT OEM_OF_PROPNAME_PREFIX"test-short" #define OEM_OF_PROPNAME_SHORT_MIN OEM_OF_PROPNAME_PREFIX"short-min" #define OEM_OF_PROPNAME_TEST_COMP_CAP OEM_OF_PROPNAME_PREFIX"test-compensate-cap" #define OEM_OF_PROPNAME_COMP_CAP_MIN OEM_OF_PROPNAME_PREFIX"compensate-cap-min" #define OEM_OF_PROPNAME_COMP_CAP_MAX OEM_OF_PROPNAME_PREFIX"compensate-cap-max" #define OEM_SELFTEST_PROC_FILENAME "cts_selftest" #define OEM_LIMIT_PROC_FILENAME "cts_limit" #define OEM_FACTORY_TEST_PROC_FILENAME "cts_factory_test" #define OEM_RAWDATA_PROC_FILENAME "cts_rawdata" #define OEM_MANUAL_PROC_FILENAME "cts_manual" #define OEM_DIFFDATA_PROC_FILENAME "cts_diffdata" #define OEM_CNEGDATA_PROC_FILENAME "cts_compensate_cap" #define OEM_TEST_DATA_DIR "/sdcard" #define OEM_RAWDATA_TEST_DATA_FILEPATH OEM_TEST_DATA_DIR"/FWMutualTest.csv" #define OEM_NOISE_TEST_DATA_FILEPATH OEM_TEST_DATA_DIR"/NoiseTest.csv" #define OEM_OPEN_TEST_DATA_FILEPATH OEM_TEST_DATA_DIR"/OpenTest.csv" #define OEM_SHORT_TEST_DATA_FILEPATH OEM_TEST_DATA_DIR"/ShortTest.csv" #define OEM_COMP_CAP_TEST_DATA_FILEPATH OEM_TEST_DATA_DIR"/FWCCTest.csv" #define TOUCH_DATA_DIRECTORY_PREFIX "/sdcard" #define RAWDATA_TEST_DATA_FILENAME "rawdata-test-data.txt" #define NOISE_TEST_DATA_FILENAME "noise-test-data.txt" #define OPEN_TEST_DATA_FILENAME "open-test-data.txt" #define SHORT_TEST_DATA_FILENAME "short-test-data.txt" #define COMP_CAP_TEST_DATA_FILENAME "comp-cap-test-data.txt" #define STYLUS_RAWDATA_TEST_DATA_FILENAME "stylus-rawdata-test-data.txt" #define STYLUS_NOISE_TEST_DATA_FILENAME "stylus-noise-test-data.txt" #define STYLUS_MNT_NOISE_TEST_DATA_FILENAME "stylus-mnt-noise-test-data.txt" #pragma pack(1) struct cts_limit { u8 header[7]; u8 version; u16 int_item : 1; u16 reset_item : 1; u16 normal_rawdata_item : 1; u16 normal_noise_item : 1; u16 open_item : 1; u16 short_item : 1; u16 comp_cap_item : 1; u16 gstr_rawdata_item : 1; u16 gstrlp_rawdata_item : 1; u16 gstr_noise_item : 1; u16 gstrlp_noise_item : 1; u16 stylus_rawdata_item : 1; u16 stylus_noise_item : 1; u16 stylus_mnt_rawdata_item : 1; u16 type : 2; u16 normal_rawdata_frames; u16 normal_rawdata_min; u16 normal_rawdata_max; u16 normal_noise_frames; u16 normal_noise_max; u16 normal_open_min; u16 normal_short_min; u16 normal_compcap_min; u16 normal_compcap_max; u16 gstr_rawdata_frames; u16 gstr_rawdata_min; u16 gstr_rawdata_max; u16 gstrlp_rawdata_frames; u16 gstrlp_rawdata_min; u16 gstrlp_rawdata_max; u16 gstr_noise_frames; u16 gstr_noise_max; u16 gstrlp_noise_frames; u16 gstrlp_noise_max; u16 stylus_rawdata_frames; u16 stylus_rawdata_min; u16 stylus_rawdata_max; u16 stylus_noise_frames; u16 stylus_noise_max; u16 stylus_mnt_rawdata_frames; u16 stylus_mnt_rawdata_min; u16 stylus_mnt_rawdata_max; }; #pragma pack() struct cts_oem_data { struct proc_dir_entry *selftest_proc_entry; struct proc_dir_entry *limit_entry; struct proc_dir_entry *factory_test_entry; struct proc_dir_entry *manual_proc_entry; struct proc_dir_entry *diffdata_proc_entry; struct proc_dir_entry *rawdata_proc_entry; struct proc_dir_entry *cnegdata_proc_entry; bool test_config_from_dt_has_parsed; /* Test configuration from device tree */ bool test_reset_pin; int reset_pin_test_result; bool test_int_pin; int int_pin_test_result; bool test_rawdata; u32 rawdata_test_frames; int rawdata_test_result; u16 *rawdata_test_data; int rawdata_test_data_buff_size; int rawdata_test_data_wr_size; int rawdata_min; int rawdata_max; bool test_noise; u32 noise_test_frames; int noise_test_result; u16 *noise_test_data; int noise_test_data_buff_size; int noise_test_data_wr_size; int noise_max; bool test_open; int open_test_result; u16 *open_test_data; int open_test_data_buff_size; int open_test_data_wr_size; int open_min; bool test_short; int short_test_result; u16 *short_test_data; int short_test_data_buff_size; int short_test_data_wr_size; int short_min; bool test_comp_cap; int comp_cap_test_result; u8 *comp_cap_test_data; int comp_cap_test_data_buff_size; int comp_cap_test_data_wr_size; int comp_cap_min; int comp_cap_max; bool test_stylus_rawdata; u32 stylus_rawdata_test_frames; int stylus_rawdata_test_result; u8 *stylus_rawdata_test_data; int stylus_rawdata_test_data_buff_size; int stylus_rawdata_test_data_wr_size; int stylus_rawdata_min; int stylus_rawdata_max; bool test_stylus_noise; u32 stylus_noise_test_frames; int stylus_noise_test_result; u8 *stylus_noise_test_data; int stylus_noise_test_data_buff_size; int stylus_noise_test_data_wr_size; int stylus_noise_max; bool test_stylus_mnt_rawdata; u32 stylus_mnt_rawdata_test_frames; int stylus_mnt_rawdata_test_result; u8 *stylus_mnt_rawdata_test_data; int stylus_mnt_rawdata_test_data_buff_size; int stylus_mnt_rawdata_test_data_wr_size; int stylus_mnt_rawdata_min; int stylus_mnt_rawdata_max; struct chipone_ts_data *cts_data; }; /* struct proc_dir_entry *cts_tp_work_proc; */ #define ALLOC_TEST_DATA_MEM(type, size) \ do { \ if (oem_data->test_##type) { \ if (oem_data->type##_test_data == NULL) { \ cts_info(" - Alloc " #type " test data mem size %d", size); \ oem_data->type##_test_data = kmalloc(size, GFP_KERNEL); \ if (oem_data->type##_test_data == NULL) { \ cts_err("Alloc " #type " test data mem failed"); \ return -ENOMEM; \ } \ oem_data->type##_test_data_buff_size = size; \ } \ memset(oem_data->type##_test_data, 0, size); \ } \ } while (0) /* NOTE: Any test data mem alloc failed will NOT clean other mem */ static int alloc_selftest_data_mem(struct cts_oem_data *oem_data, int nodes) { cts_info("Alloc selftest data"); ALLOC_TEST_DATA_MEM(rawdata, nodes * 2 * oem_data->rawdata_test_frames); ALLOC_TEST_DATA_MEM(noise, nodes * 2 * (oem_data->noise_test_frames + 3)); ALLOC_TEST_DATA_MEM(open, nodes * 2); ALLOC_TEST_DATA_MEM(short, nodes * 2 * 5); ALLOC_TEST_DATA_MEM(comp_cap, nodes); return 0; } #define FREE_TEST_DATA_MEM(type) \ do { \ if (oem_data->type##_test_data) { \ cts_info("- Free " #type " test data mem"); \ kfree(oem_data->type##_test_data); \ oem_data->type##_test_data = NULL; \ oem_data->type##_test_data_buff_size = 0; \ } \ } while(0) static void free_selftest_data_mem(struct cts_oem_data *oem_data) { cts_info("Free selftest data"); FREE_TEST_DATA_MEM(rawdata); FREE_TEST_DATA_MEM(noise); FREE_TEST_DATA_MEM(open); FREE_TEST_DATA_MEM(short); FREE_TEST_DATA_MEM(comp_cap); } /* NOTE: Any test data mem alloc failed will NOT clean other mem static int alloc_stylus_test_data_mem(struct cts_oem_data *oem_data, int nodes) { cts_info("Alloc stylus selftest data"); ALLOC_TEST_DATA_MEM(stylus_rawdata, nodes * 2 * oem_data->stylus_rawdata_test_frames); ALLOC_TEST_DATA_MEM(stylus_noise, nodes * 2 * (oem_data->stylus_noise_test_frames + 3)); ALLOC_TEST_DATA_MEM(stylus_mnt_rawdata, nodes * 2 * oem_data->stylus_mnt_rawdata_test_frames); return 0; } static void free_stylus_test_data_mem(struct cts_oem_data *oem_data) { cts_info("Free stylus selftest data"); FREE_TEST_DATA_MEM(stylus_rawdata); FREE_TEST_DATA_MEM(stylus_noise); FREE_TEST_DATA_MEM(stylus_mnt_rawdata); } */ #undef ALLOC_TEST_DATA_MEM #undef FREE_TEST_DATA_MEM static int parse_selftest_dt(struct cts_oem_data *oem_data, struct device_node *np) { int ret; cts_info("Parse selftest dt"); /** reset pin **/ oem_data->test_reset_pin = OEM_OF_DEF_PROPVAL_TEST_RESET_PIN || of_property_read_bool(np, OEM_OF_PROPNAME_TEST_RESET_PIN); /** int pin **/ oem_data->test_int_pin = OEM_OF_DEF_PROPVAL_TEST_INT_PIN || of_property_read_bool(np, OEM_OF_PROPNAME_TEST_INT_PIN); /** rawdata **/ oem_data->test_rawdata = OEM_OF_DEF_PROPVAL_TEST_RAWDATA || of_property_read_bool(np, OEM_OF_PROPNAME_TEST_RAWDATA); if (oem_data->test_rawdata) { oem_data->rawdata_test_frames = OEM_OF_DEF_PROPVAL_RAWDATA_FRAMES; ret = of_property_read_u32(np, OEM_OF_PROPNAME_RAWDATA_FRAMES, &oem_data->rawdata_test_frames); if (ret) { cts_warn("Parse '"OEM_OF_PROPNAME_RAWDATA_FRAMES"' failed %d", ret); } oem_data->rawdata_min = OEM_OF_DEF_PROPVAL_RAWDATA_MIN; ret = of_property_read_u32(np, OEM_OF_PROPNAME_RAWDATA_MIN, (u32 *)&oem_data->rawdata_min); if (ret) { cts_warn("Parse '"OEM_OF_PROPNAME_RAWDATA_MIN"' failed %d", ret); } oem_data->rawdata_max = OEM_OF_DEF_PROPVAL_RAWDATA_MAX; ret = of_property_read_u32(np, OEM_OF_PROPNAME_RAWDATA_MAX, (u32 *)&oem_data->rawdata_max); if (ret) { cts_warn("Parse '"OEM_OF_PROPNAME_RAWDATA_MAX"' failed %d", ret); } } /** nosie **/ oem_data->test_noise = OEM_OF_DEF_PROPVAL_TEST_NOISE || of_property_read_bool(np, OEM_OF_PROPNAME_TEST_NOISE); if (oem_data->test_noise) { oem_data->noise_test_frames = OEM_OF_DEF_PROPVAL_NOISE_FRAMES; ret = of_property_read_u32(np, OEM_OF_PROPNAME_NOISE_FRAMES, &oem_data->noise_test_frames); if (ret) { cts_warn("Parse '"OEM_OF_PROPNAME_NOISE_FRAMES"' failed %d", ret); } oem_data->noise_max = OEM_OF_DEF_PROPVAL_NOISE_MAX; ret = of_property_read_u32(np, OEM_OF_PROPNAME_NOISE_MAX, (u32 *)&oem_data->noise_max); if (ret) { cts_warn("Parse '"OEM_OF_PROPNAME_NOISE_MAX"' failed %d", ret); } } /** open **/ oem_data->test_open = OEM_OF_DEF_PROPVAL_TEST_OPEN || of_property_read_bool(np, OEM_OF_PROPNAME_TEST_OPEN); if (oem_data->test_open) { oem_data->open_min = OEM_OF_DEF_PROPVAL_OPEN_MIN; ret = of_property_read_u32(np, OEM_OF_PROPNAME_OPEN_MIN, (u32 *)&oem_data->open_min); if (ret) { cts_warn("Parse '"OEM_OF_PROPNAME_OPEN_MIN"' failed %d", ret); } } /** short **/ oem_data->test_short = OEM_OF_DEF_PROPVAL_TEST_SHORT || of_property_read_bool(np, OEM_OF_PROPNAME_TEST_SHORT); if (oem_data->test_short) { oem_data->short_min = OEM_OF_DEF_PROPVAL_SHORT_MIN; ret = of_property_read_u32(np, OEM_OF_PROPNAME_SHORT_MIN, (u32 *)&oem_data->short_min); if (ret) { cts_warn("Parse '"OEM_OF_PROPNAME_SHORT_MIN"' failed %d", ret); } } /** comp cap **/ oem_data->test_comp_cap = OEM_OF_DEF_PROPVAL_TEST_COMP_CAP || of_property_read_bool(np, OEM_OF_PROPNAME_TEST_COMP_CAP); if (oem_data->test_comp_cap) { oem_data->comp_cap_min = OEM_OF_DEF_PROPVAL_COMP_CAP_MIN; ret = of_property_read_u32(np, OEM_OF_PROPNAME_COMP_CAP_MIN, (u32 *)&oem_data->comp_cap_min); if (ret) { cts_warn("Parse '"OEM_OF_PROPNAME_COMP_CAP_MIN"' failed %d", ret); } oem_data->comp_cap_max = OEM_OF_DEF_PROPVAL_COMP_CAP_MAX; ret = of_property_read_u32(np, OEM_OF_PROPNAME_COMP_CAP_MAX, (u32 *)&oem_data->comp_cap_max); if (ret) { cts_warn("Parse '"OEM_OF_PROPNAME_COMP_CAP_MAX"' failed %d", ret); } } oem_data->test_config_from_dt_has_parsed = true; return 0; } static void print_selftest_config(const struct cts_oem_data *oem_data) { cts_info("Seltest configuration:"); /** reset pin **/ cts_info(" - %-32s = %c", OEM_OF_PROPNAME_TEST_RESET_PIN, oem_data->test_reset_pin ? 'Y' : 'N'); /** int pin **/ cts_info(" - %-32s = %c", OEM_OF_PROPNAME_TEST_INT_PIN, oem_data->test_int_pin ? 'Y' : 'N'); /** rawdata **/ cts_info(" - %-32s = %c", OEM_OF_PROPNAME_TEST_RAWDATA, oem_data->test_rawdata ? 'Y' : 'N'); if (oem_data->test_rawdata) { cts_info(" - %-32s = %u", OEM_OF_PROPNAME_RAWDATA_FRAMES, oem_data->rawdata_test_frames); cts_info(" - %-32s = %d", OEM_OF_PROPNAME_RAWDATA_MIN, oem_data->rawdata_min); cts_info(" - %-32s = %d", OEM_OF_PROPNAME_RAWDATA_MAX, oem_data->rawdata_max); } /** noise **/ cts_info(" - %-32s = %c", OEM_OF_PROPNAME_TEST_NOISE, oem_data->test_noise ? 'Y' : 'N'); if (oem_data->test_noise) { cts_info(" - %-32s = %u", OEM_OF_PROPNAME_NOISE_FRAMES , oem_data->noise_test_frames); cts_info(" - %-32s = %d", OEM_OF_PROPNAME_NOISE_MAX, oem_data->noise_max); } /** open **/ cts_info(" - %-32s = %c", OEM_OF_PROPNAME_TEST_OPEN, oem_data->test_open ? 'Y' : 'N'); if (oem_data->test_open) { cts_info(" - %-32s = %d", OEM_OF_PROPNAME_OPEN_MIN, oem_data->open_min); } /** short **/ cts_info(" - %-32s = %c", OEM_OF_PROPNAME_TEST_SHORT, oem_data->test_short ? 'Y' : 'N'); if (oem_data->test_short) { cts_info(" - %-32s = %d", OEM_OF_PROPNAME_SHORT_MIN, oem_data->short_min); } /** comp cap **/ cts_info(" - %-32s = %c", OEM_OF_PROPNAME_TEST_COMP_CAP, oem_data->test_comp_cap ? 'Y' : 'N'); if (oem_data->test_comp_cap) { cts_info(" - %-32s = %d", OEM_OF_PROPNAME_COMP_CAP_MIN, oem_data->comp_cap_min); cts_info(" - %-32s = %d", OEM_OF_PROPNAME_COMP_CAP_MAX, oem_data->comp_cap_max); } } static void do_selftest(struct cts_oem_data *oem_data) { struct cts_test_param test_param; int retry = 3; cts_info("Do selftest"); /** reset pin test **/ if (oem_data->test_reset_pin) { memset(&test_param, 0, sizeof(test_param)); test_param.test_item = CTS_TEST_RESET_PIN; oem_data->reset_pin_test_result = cts_test_reset_pin(&oem_data->cts_data->cts_dev, &test_param); if (oem_data->reset_pin_test_result) { cts_err("Test reset pin failed %d", oem_data->reset_pin_test_result); } } /** int pin test **/ if (oem_data->test_int_pin) { memset(&test_param, 0, sizeof(test_param)); test_param.test_item = CTS_TEST_INT_PIN; oem_data->int_pin_test_result = cts_test_int_pin(&oem_data->cts_data->cts_dev, &test_param); if (oem_data->int_pin_test_result) { cts_err("Test int pin failed %d", oem_data->int_pin_test_result); } } /** rawdata test **/ if (oem_data->test_rawdata) { struct cts_rawdata_test_priv_param priv_param = {0}; memset(&test_param, 0, sizeof(test_param)); oem_data->rawdata_test_data_wr_size = 0; test_param.test_item = CTS_TEST_RAWDATA; test_param.flags = CTS_TEST_FLAG_VALIDATE_DATA | CTS_TEST_FLAG_VALIDATE_MIN | CTS_TEST_FLAG_VALIDATE_MAX | CTS_TEST_FLAG_STOP_TEST_IF_VALIDATE_FAILED | CTS_TEST_FLAG_DUMP_TEST_DATA_TO_USERSPACE; test_param.min = &oem_data->rawdata_min; test_param.max = &oem_data->rawdata_max; test_param.test_data_buf = oem_data->rawdata_test_data; test_param.test_data_buf_size = oem_data->rawdata_test_data_buff_size; test_param.test_data_wr_size = &oem_data->rawdata_test_data_wr_size; priv_param.frames = oem_data->rawdata_test_frames; test_param.priv_param = &priv_param; test_param.priv_param_size = sizeof(priv_param); retry = 3; do { oem_data->rawdata_test_result = cts_test_rawdata(&oem_data->cts_data->cts_dev, &test_param); } while (oem_data->rawdata_test_result < 0 && retry--); if (oem_data->rawdata_test_result) { cts_err("Test rawdata failed %d", oem_data->rawdata_test_result); } } /** noise test **/ if (oem_data->test_noise) { struct cts_noise_test_priv_param priv_param = {0}; memset(&test_param, 0, sizeof(test_param)); oem_data->noise_test_data_wr_size = 0; test_param.test_item = CTS_TEST_NOISE; test_param.flags = CTS_TEST_FLAG_VALIDATE_DATA | CTS_TEST_FLAG_VALIDATE_MAX | CTS_TEST_FLAG_STOP_TEST_IF_VALIDATE_FAILED | CTS_TEST_FLAG_DUMP_TEST_DATA_TO_USERSPACE; test_param.max = &oem_data->noise_max; test_param.test_data_buf = oem_data->noise_test_data; test_param.test_data_buf_size = oem_data->noise_test_data_buff_size; test_param.test_data_wr_size = &oem_data->noise_test_data_wr_size; priv_param.frames = oem_data->noise_test_frames; test_param.priv_param = &priv_param; test_param.priv_param_size = sizeof(priv_param); retry = 3; do { oem_data->noise_test_result = cts_test_noise(&oem_data->cts_data->cts_dev, &test_param); } while (oem_data->noise_test_result < 0 && retry--); if (oem_data->noise_test_result) { cts_err("Test noise failed %d", oem_data->noise_test_result); } } /** open test **/ if (oem_data->test_open) { memset(&test_param, 0, sizeof(test_param)); oem_data->open_test_data_wr_size = 0; test_param.test_item = CTS_TEST_OPEN; test_param.flags = CTS_TEST_FLAG_VALIDATE_DATA | CTS_TEST_FLAG_VALIDATE_MIN | CTS_TEST_FLAG_STOP_TEST_IF_VALIDATE_FAILED | CTS_TEST_FLAG_DUMP_TEST_DATA_TO_USERSPACE; test_param.min = &oem_data->open_min; test_param.test_data_buf = oem_data->open_test_data; test_param.test_data_buf_size = oem_data->open_test_data_buff_size; test_param.test_data_wr_size = &oem_data->open_test_data_wr_size; retry = 3; do { oem_data->open_test_result = cts_test_open(&oem_data->cts_data->cts_dev, &test_param); } while (oem_data->open_test_result < 0 && retry--); if (oem_data->open_test_result) { cts_err("Test open failed %d", oem_data->open_test_result); } } /** short test **/ if (oem_data->test_short) { memset(&test_param, 0, sizeof(test_param)); oem_data->short_test_data_wr_size = 0; test_param.test_item = CTS_TEST_SHORT; test_param.flags = CTS_TEST_FLAG_VALIDATE_DATA | CTS_TEST_FLAG_VALIDATE_MIN | CTS_TEST_FLAG_STOP_TEST_IF_VALIDATE_FAILED | CTS_TEST_FLAG_DUMP_TEST_DATA_TO_USERSPACE; test_param.min = &oem_data->short_min; test_param.test_data_buf = oem_data->short_test_data; test_param.test_data_buf_size = oem_data->short_test_data_buff_size; test_param.test_data_wr_size = &oem_data->short_test_data_wr_size; retry = 3; do { oem_data->short_test_result = cts_test_short(&oem_data->cts_data->cts_dev, &test_param); } while (oem_data->short_test_result < 0 && retry--); if (oem_data->short_test_result) { cts_err("Test short failed %d", oem_data->short_test_result); } } /** comp cap test **/ if (oem_data->test_comp_cap) { memset(&test_param, 0, sizeof(test_param)); oem_data->comp_cap_test_data_wr_size = 0; test_param.test_item = CTS_TEST_COMPENSATE_CAP; test_param.flags = CTS_TEST_FLAG_VALIDATE_DATA | CTS_TEST_FLAG_VALIDATE_MIN | CTS_TEST_FLAG_VALIDATE_MAX | CTS_TEST_FLAG_STOP_TEST_IF_VALIDATE_FAILED | CTS_TEST_FLAG_DUMP_TEST_DATA_TO_USERSPACE; test_param.min = &oem_data->comp_cap_min; test_param.max = &oem_data->comp_cap_max; test_param.test_result = &oem_data->comp_cap_test_result; test_param.test_data_buf = oem_data->comp_cap_test_data; test_param.test_data_buf_size = oem_data->comp_cap_test_data_buff_size; test_param.test_data_wr_size = &oem_data->comp_cap_test_data_wr_size; retry = 3; do { oem_data->comp_cap_test_result = cts_test_compensate_cap(&oem_data->cts_data->cts_dev, &test_param); } while (oem_data->comp_cap_test_result < 0 && retry--); if (oem_data->comp_cap_test_result) { cts_err("Test compensate cap failed %d", oem_data->comp_cap_test_result); } } /* if (oem_data->test_stylus_rawdata) { struct cts_rawdata_test_priv_param priv_param = {0}; memset(&test_param, 0, sizeof(test_param)); oem_data->stylus_rawdata_test_data_wr_size = 0; test_param.test_item = CTS_TEST_STYLUS_RAWDATA; test_param.flags = CTS_TEST_FLAG_VALIDATE_DATA | CTS_TEST_FLAG_VALIDATE_MIN | CTS_TEST_FLAG_VALIDATE_MAX | CTS_TEST_FLAG_STOP_TEST_IF_VALIDATE_FAILED | CTS_TEST_FLAG_DUMP_TEST_DATA_TO_USERSPACE; test_param.min = &oem_data->stylus_rawdata_min; test_param.max = &oem_data->stylus_rawdata_max; test_param.test_data_buf = oem_data->stylus_rawdata_test_data; test_param.test_data_buf_size = oem_data->stylus_rawdata_test_data_buff_size; test_param.test_data_wr_size = &oem_data->stylus_rawdata_test_data_wr_size; priv_param.frames = oem_data->stylus_rawdata_test_frames; test_param.priv_param = &priv_param; test_param.priv_param_size = sizeof(priv_param); retry = 3; do { oem_data->stylus_rawdata_test_result = cts_test_stylus_rawdata(&oem_data->cts_data->cts_dev, &test_param); } while (oem_data->stylus_rawdata_test_result < 0 && retry--); if (oem_data->stylus_rawdata_test_result) { cts_err("stylus test rawdata failed %d", oem_data->stylus_rawdata_test_result); } } if (oem_data->stylus_test_noise) { struct cts_noise_test_priv_param priv_param = {0}; memset(&test_param, 0, sizeof(test_param)); oem_data->stylus_noise_test_data_wr_size = 0; test_param.test_item = CTS_TEST_STYLUS_NOISE; test_param.flags = CTS_TEST_FLAG_VALIDATE_DATA | CTS_TEST_FLAG_VALIDATE_MAX | CTS_TEST_FLAG_STOP_TEST_IF_VALIDATE_FAILED | CTS_TEST_FLAG_DUMP_TEST_DATA_TO_USERSPACE; test_param.max = &oem_data->stylus_noise_max; test_param.test_data_buf = oem_data->stylus_noise_test_data; test_param.test_data_buf_size = oem_data->stylus_noise_test_data_buff_size; test_param.test_data_wr_size = &oem_data->stylus_noise_test_data_wr_size; priv_param.frames = oem_data->stylus_noise_test_frames; test_param.priv_param = &priv_param; test_param.priv_param_size = sizeof(priv_param); retry = 3; do { oem_data->stylus_noise_test_result = cts_test_stylus_noise(&oem_data->cts_data->cts_dev, &test_param); } while (oem_data->stylus_noise_test_result < 0 && retry--); if (oem_data->stylus_noise_test_result) { cts_err("stylus test noise failed %d", oem_data->stylus_noise_test_result); } } */ } static int dump_tsdata_row_to_buffer(char *buf, size_t size, const u16 *data, int cols, const char *prefix, const char *suffix, char seperator) { int c, count = 0; if (prefix) { count += scnprintf(buf, size, "%s", prefix); } for (c = 0; c < cols; c++) { count += scnprintf(buf + count, size - count, "%4u%c ", data[c], seperator); } if (suffix) { count += scnprintf(buf + count, size - count, "%s", suffix); } return count; } static int dump_tsdata_to_csv_file(const char *filepath, int flags, const u16 *data, int frames, int rows, int cols) { #ifdef CFG_CTS_FOR_GKI cts_info("%s(): some functions are forbiddon with GKI Version!", __func__); return -EPERM; #else loff_t pos = 0; int i, r, ret; struct file *file; cts_info("Dump tsdata to csv file: '%s' flags: 0x%x data: %p frames: %d row: %d col: %d", filepath, flags, data, frames, cols, rows); file = filp_open(filepath, flags, 0666); if (IS_ERR(file)) { cts_err("Open file '%s' failed %ld", filepath, PTR_ERR(file)); return PTR_ERR(file); } for (i = 0; i < frames; i++) { for (r = 0; r < rows; r++) { char linebuf[256]; int len; len = dump_tsdata_row_to_buffer(linebuf, sizeof(linebuf), data, cols, NULL, "\n", ','); #if LINUX_VERSION_CODE >= KERNEL_VERSION(4,14,0) ret = kernel_write(file, linebuf, len, &pos); #else ret = kernel_write(file, linebuf, len, pos); pos += len; #endif if (ret != len) { cts_err("Write to file '%s' failed %d", filepath, ret); goto close_file; } data += cols; } #if LINUX_VERSION_CODE >= KERNEL_VERSION(4,14,0) ret = kernel_write(file, "\n", 1, &pos); #else ret = kernel_write(file, "\n", 1, pos); pos ++; #endif if (ret != 1) { cts_err("Write newline to file '%s' failed %d", filepath, ret); goto close_file; } } close_file: { int r = filp_close(file, NULL); if (r) { cts_err("Close file '%s' failed %d", filepath, r); } } return ret; #endif } static void dump_tsdata_to_seq_file(struct seq_file *m, const u16 *data, int rows, int cols) { int r; for (r = 0; r < rows; r++) { char linebuf[256]; int len; len = dump_tsdata_row_to_buffer(linebuf, sizeof(linebuf), data, cols, NULL, "\n", ','); seq_puts(m, linebuf); data += cols; } } static int dump_comp_cap_row_to_buffer(char *buf, size_t size, const u8 *cap, int cols, const char *prefix, const char *suffix, char seperator) { int c, count = 0; if (prefix) { count += scnprintf(buf, size, "%s", prefix); } for (c = 0; c < cols; c++) { count += scnprintf(buf + count, size - count, "%3u%c ", cap[c], seperator); } if (suffix) { count += scnprintf(buf + count, size - count, "%s", suffix); } return count; } static int dump_comp_cap_to_csv_file(const char *filepath, int flags, const u8 *cap, int rows, int cols) { #ifdef CFG_CTS_FOR_GKI cts_info("%s(): some functions are forbiddon with GKI Version!", __func__); return -EPERM; #else struct file *file; int r, ret = 0; loff_t pos = 0; cts_info("Dump compensate cap to csv file: '%s' flags: 0x%x row: %d col: %d", filepath, flags, rows, cols); file = filp_open(filepath, flags, 0666); if (IS_ERR(file)) { cts_err("Open file '%s' failed %ld", filepath, PTR_ERR(file)); return PTR_ERR(file); } for (r = 0; r < rows; r++) { char linebuf[256]; int len; len = dump_comp_cap_row_to_buffer(linebuf, sizeof(linebuf), cap, cols, NULL, "\n", ','); #if LINUX_VERSION_CODE >= KERNEL_VERSION(4,14,0) ret = kernel_write(file, linebuf, len, &pos); #else ret = kernel_write(file, linebuf, len, pos); pos += len; #endif if (ret != len) { cts_err("Write to file '%s' failed %d", filepath, ret); goto close_file; } cap += cols; } close_file: { int r = filp_close(file, NULL); if (r) { cts_err("Close file '%s' failed %d", filepath, ret); } } return ret; #endif } static void dump_comp_cap_to_seq_file(struct seq_file *m, const u8 *data, int rows, int cols) { int r; for (r = 0; r < rows; r++) { char linebuf[256]; int len; len = dump_comp_cap_row_to_buffer(linebuf, sizeof(linebuf), data, cols, NULL, "\n", ','); seq_puts(m, linebuf); data += cols; } } static int save_selftest_data_to_file(struct cts_oem_data *oem_data) { int rows, cols; int ret; cts_info("Save selftest data to file"); rows = oem_data->cts_data->cts_dev.fwdata.rows; cols = oem_data->cts_data->cts_dev.fwdata.cols; if (oem_data->test_rawdata) { ret = dump_tsdata_to_csv_file(OEM_RAWDATA_TEST_DATA_FILEPATH, O_RDWR | O_CREAT | O_TRUNC, oem_data->rawdata_test_data, oem_data->rawdata_test_frames, cols, rows); if (ret < 0) { cts_err("Dump rawdata test data to file failed"); return ret; } } if (oem_data->test_noise) { ret = dump_tsdata_to_csv_file(OEM_NOISE_TEST_DATA_FILEPATH, O_RDWR | O_CREAT | O_TRUNC, oem_data->noise_test_data, oem_data->noise_test_frames + 3, cols, rows); if (ret < 0) { cts_err("Dump noise test data to file failed"); return ret; } } if (oem_data->test_open) { ret = dump_tsdata_to_csv_file(OEM_OPEN_TEST_DATA_FILEPATH, O_RDWR | O_CREAT | O_TRUNC, oem_data->open_test_data, 1, cols, rows); if (ret < 0) { cts_err("Dump open test data to file failed"); return ret; } } if (oem_data->test_short) { ret = dump_tsdata_to_csv_file(OEM_SHORT_TEST_DATA_FILEPATH, O_RDWR | O_CREAT | O_TRUNC, oem_data->short_test_data, 5, cols, rows); if (ret < 0) { cts_err("Dump short test data to file failed"); return ret; } } if (oem_data->test_comp_cap) { ret = dump_comp_cap_to_csv_file(OEM_COMP_CAP_TEST_DATA_FILEPATH, O_RDWR | O_CREAT | O_TRUNC, oem_data->comp_cap_test_data, cols, rows); if (ret < 0) { cts_err("Dump compensate cap test data to file failed"); return ret; } } return 0; } static void *selftest_seq_start(struct seq_file *m, loff_t *pos) { return *pos < 1 ? (void *)1 : NULL; } static void *selftest_seq_next(struct seq_file *m, void *v, loff_t *pos) { ++*pos; return NULL; } static void selftest_seq_stop(struct seq_file *m, void *v) { return; } static int selftest_seq_show(struct seq_file *m, void *v) { struct chipone_ts_data *cts_data = (struct chipone_ts_data *)m->private; struct cts_oem_data *oem_data = NULL; int i, rows, cols; cts_info("Show seq selftest"); if (cts_data == NULL) { cts_err("Selftest seq file private data = NULL"); return -EFAULT; } oem_data = cts_data->oem_data; rows = cts_data->cts_dev.fwdata.rows; cols = cts_data->cts_dev.fwdata.cols; seq_printf(m, "FW Version %04x!\n\n", cts_data->cts_dev.fwdata.version); if (oem_data->test_reset_pin) { seq_printf(m, "Reset-Pin Test %s!\n\n", oem_data->reset_pin_test_result == 0 ? "PASS" : "FAIL"); } if (oem_data->test_int_pin) { seq_printf(m, "Int-Pin Test %s!\n\n", oem_data->int_pin_test_result == 0 ? "PASS" : "FAIL"); } if (oem_data->test_rawdata) { seq_printf(m, "FW Rawdata Test"); if (oem_data->rawdata_test_result == 0) { seq_printf(m, " PASS!\n\n"); } else if (oem_data->rawdata_test_result > 0) { seq_printf(m, " FAIL!\n"); for(i = 0; i < oem_data->rawdata_test_frames; i++) { dump_tsdata_to_seq_file(m, oem_data->rawdata_test_data + i * rows * cols, cols, rows); seq_putc(m, '\n'); } } else { seq_printf(m, " ERROR(%d)!\n\n", oem_data->rawdata_test_result); } } if (oem_data->test_noise) { seq_printf(m, "Noise Test"); if (oem_data->noise_test_result == 0) { seq_printf(m, " PASS!\n\n"); } else if (oem_data->noise_test_result > 0) { seq_printf(m, " FAIL!\n"); for(i = 0; i < oem_data->noise_test_frames; i++) { dump_tsdata_to_seq_file(m, oem_data->noise_test_data + i * rows * cols, rows, cols); seq_putc(m, '\n'); } } else { seq_printf(m, " ERROR(%d)!\n\n", oem_data->noise_test_result); } } if (oem_data->test_open) { seq_printf(m, "Open Test"); if (oem_data->open_test_result == 0) { seq_printf(m, " PASS!\n\n"); } else if (oem_data->open_test_result > 0) { seq_printf(m, " FAIL!\n"); dump_tsdata_to_seq_file(m, oem_data->open_test_data, rows, cols); } else { seq_printf(m, " ERROR(%d)!\n\n", oem_data->open_test_result); } } if (oem_data->test_short) { seq_printf(m, "Short Test"); if (oem_data->short_test_result == 0) { seq_printf(m, " PASS!\n\n"); } else if (oem_data->short_test_result > 0) { seq_printf(m, " FAIL!\n"); for (i = 0; i < 10; i++) { dump_tsdata_to_seq_file(m, oem_data->short_test_data + i * rows * cols, cols, rows); seq_putc(m, '\n'); } } else { seq_printf(m, " ERROR(%d)!\n\n", oem_data->short_test_result); } } if (oem_data->test_comp_cap) { seq_printf(m, "Compensate-Cap Test"); if (oem_data->comp_cap_test_result == 0) { seq_printf(m, " PASS!\n\n"); } else if (oem_data->comp_cap_test_result > 0) { seq_printf(m, " FAIL!\n"); dump_comp_cap_to_seq_file(m, oem_data->comp_cap_test_data, rows, cols); } else { seq_printf(m, " ERROR(%d)!\n\n", oem_data->comp_cap_test_result); } } return 0; } static const struct seq_operations selftest_seq_ops = { .start = selftest_seq_start, .next = selftest_seq_next, .stop = selftest_seq_stop, .show = selftest_seq_show, }; static int32_t selftest_proc_open(struct inode *inode, struct file *file) { struct chipone_ts_data *cts_data = pde_data(inode); struct cts_oem_data *oem_data = NULL; int ret; if (cts_data == NULL) { cts_err("Open selftest proc with cts_data = NULL"); return -EFAULT; } oem_data = cts_data->oem_data; if (oem_data == NULL) { cts_err("Open selftest proc with oem_data = NULL"); return -EFAULT; } cts_info("Open '/proc/" OEM_SELFTEST_PROC_FILENAME "'"); if (!oem_data->test_config_from_dt_has_parsed) { #ifndef CONFIG_CTS_I2C_HOST ret = parse_selftest_dt(oem_data, cts_data->pdata->spi_client->dev.of_node); #else ret = parse_selftest_dt(oem_data, cts_data->device->of_node); #endif if (ret) { cts_err("Parse selftest dt failed %d", ret); return ret; } } print_selftest_config(oem_data); ret = alloc_selftest_data_mem(oem_data, cts_data->cts_dev.fwdata.rows * cts_data->cts_dev.fwdata.cols); if (ret) { cts_err("Alloc test data mem failed"); return ret; } do_selftest(oem_data); ret = save_selftest_data_to_file(oem_data); if (ret) { cts_err("Save selftest data to file failed %d", ret); } ret = seq_open(file, &selftest_seq_ops); if (ret) { cts_err("Open selftest seq file failed %d", ret); return ret; } ((struct seq_file *)file->private_data)->private = cts_data; return 0; } #if LINUX_VERSION_CODE < KERNEL_VERSION(5, 6, 0) static const struct file_operations selftest_proc_fops = { .owner = THIS_MODULE, .open = selftest_proc_open, .read = seq_read, .llseek = seq_lseek, .release = seq_release, }; #else static const struct proc_ops selftest_proc_fops = { .proc_open = selftest_proc_open, .proc_read = seq_read, .proc_lseek = seq_lseek, .proc_release = seq_release, }; #endif static int cts_rawdata_show(struct seq_file *m, void *v) { struct chipone_ts_data *cts_data = m->private; struct cts_device *cts_dev; u8 *rawdata; s16 *data; u8 hwrows, hwcols, fwrows, fwcols; u8 i, j; cts_dev = &cts_data->cts_dev; hwrows = cts_dev->hwdata->num_row; hwcols = cts_dev->hwdata->num_col; fwrows = cts_dev->fwdata.rows; fwcols = cts_dev->fwdata.cols; rawdata = kzalloc(hwrows * hwcols * 2, GFP_KERNEL); if (rawdata == NULL) { cts_err("Allocate rawdata failed"); return -ENOMEM; } cts_lock_device(cts_dev); cts_tcs_top_get_rawdata(cts_dev, rawdata, hwrows * hwcols * 2, 0); cts_unlock_device(cts_dev); data = (s16 *)rawdata; for (i = 0; i < fwcols; i++) { for (j = 0; j < fwrows; j++) { seq_printf(m, "%5d", *data++); } seq_printf(m, "\n"); } kfree(rawdata); return 0; } static int cts_rawdata_open(struct inode *inode, struct file *file) { return single_open(file, cts_rawdata_show, pde_data(inode)); } #if LINUX_VERSION_CODE < KERNEL_VERSION(5, 6, 0) static const struct file_operations cts_rawdata_ops = { .owner = THIS_MODULE, .open = cts_rawdata_open, .read = seq_read, }; #else static const struct proc_ops cts_rawdata_ops = { .proc_open = cts_rawdata_open, .proc_read = seq_read, }; #endif static int cts_diffdata_show(struct seq_file *m, void *v) { struct chipone_ts_data *cts_data = m->private; struct cts_device *cts_dev; u8 *rawdata; s16 *data; u8 hwrows, hwcols, fwrows, fwcols; u8 i, j; cts_dev = &cts_data->cts_dev; hwrows = cts_dev->hwdata->num_row; hwcols = cts_dev->hwdata->num_col; fwrows = cts_dev->fwdata.rows; fwcols = cts_dev->fwdata.cols; rawdata = kzalloc(hwrows * hwcols * 2, GFP_KERNEL); if (rawdata == NULL) { cts_err("Allocate rawdata failed"); return -ENOMEM; } cts_lock_device(cts_dev); cts_tcs_top_get_real_diff(cts_dev, rawdata, hwrows * hwcols * 2, 0); cts_unlock_device(cts_dev); data = (s16 *)rawdata; for (i = 0; i < fwcols; i++) { for (j = 0; j < fwrows; j++) { seq_printf(m, "%5d", *data++); } seq_printf(m, "\n"); } kfree(rawdata); return 0; } static int cts_diffdata_open(struct inode *inode, struct file *file) { return single_open(file, cts_diffdata_show, pde_data(inode)); } #if LINUX_VERSION_CODE < KERNEL_VERSION(5, 6, 0) static const struct file_operations cts_diffdata_ops = { .owner = THIS_MODULE, .open = cts_diffdata_open, .read = seq_read, }; #else static const struct proc_ops cts_diffdata_ops = { .proc_open = cts_diffdata_open, .proc_read = seq_read, }; #endif static int cts_manual_show(struct seq_file *m, void *v) { struct chipone_ts_data *cts_data = m->private; struct cts_device *cts_dev; u8 *rawdata; s16 *data; u8 hwrows, hwcols, fwrows, fwcols; u8 i, j; cts_dev = &cts_data->cts_dev; hwrows = cts_dev->hwdata->num_row; hwcols = cts_dev->hwdata->num_col; fwrows = cts_dev->fwdata.rows; fwcols = cts_dev->fwdata.cols; rawdata = kzalloc(hwrows * hwcols * 2, GFP_KERNEL); if (rawdata == NULL) { cts_err("Allocate rawdata failed"); return -ENOMEM; } cts_lock_device(cts_dev); cts_tcs_top_get_manual_diff(cts_dev, rawdata, hwrows * hwcols * 2, 0); cts_unlock_device(cts_dev); data = (s16 *)rawdata; for (i = 0; i < fwcols; i++) { for (j = 0; j < fwrows; j++) { seq_printf(m, "%5d", *data++); } seq_printf(m, "\n"); } kfree(rawdata); return 0; } static int cts_manual_open(struct inode *inode, struct file *file) { return single_open(file, cts_manual_show, pde_data(inode)); } #if LINUX_VERSION_CODE < KERNEL_VERSION(5, 6, 0) static const struct file_operations cts_manual_ops = { .owner = THIS_MODULE, .open = cts_manual_open, .read = seq_read, }; #else static const struct proc_ops cts_manual_ops = { .proc_open = cts_manual_open, .proc_read = seq_read, }; #endif static int cts_cnegdata_show(struct seq_file *m, void *v) { struct chipone_ts_data *cts_data = m->private; struct cts_device *cts_dev; u8 *rawdata; u8 *data; u8 hwrows, hwcols, fwrows, fwcols; u8 i, j; cts_dev = &cts_data->cts_dev; hwrows = cts_dev->hwdata->num_row; hwcols = cts_dev->hwdata->num_col; fwrows = cts_dev->fwdata.rows; fwcols = cts_dev->fwdata.cols; rawdata = kzalloc(hwrows * hwcols, GFP_KERNEL); if (rawdata == NULL) { cts_err("Allocate rawdata failed"); return -ENOMEM; } cts_lock_device(cts_dev); cts_tcs_top_get_cnegdata(cts_dev, rawdata, hwrows * hwcols, 0); cts_unlock_device(cts_dev); data = (u8 *)rawdata; for (i = 0; i < fwcols; i++) { for (j = 0; j < fwrows; j++) { seq_printf(m, "%5d", *data++); } seq_printf(m, "\n"); } kfree(rawdata); return 0; } static int cts_cnegdata_open(struct inode *inode, struct file *file) { return single_open(file, cts_cnegdata_show, pde_data(inode)); } #if LINUX_VERSION_CODE < KERNEL_VERSION(5, 6, 0) static const struct file_operations cts_cnegdata_ops = { .owner = THIS_MODULE, .open = cts_cnegdata_open, .read = seq_read, }; #else static const struct proc_ops cts_cnegdata_ops = { .proc_open = cts_cnegdata_open, .proc_read = seq_read, }; #endif /* Use limit bin */ static int cts_limit_show(struct seq_file *m, void *v) { struct chipone_ts_data *cts_data = m->private; struct cts_device *cts_dev = &cts_data->cts_dev; const struct firmware *limit_fw = NULL; struct cts_limit limit; char header[7] = {'C', 'h', 'i', 'p', 'o', 'n', 'e'}; int ret; ret = request_firmware(&limit_fw, CFG_CTS_FACTORY_LIMIT_FILENAME, &cts_dev->pdata->ts_input_dev->dev); if (ret) { seq_printf(m, "Request %s failed!\n", CFG_CTS_FACTORY_LIMIT_FILENAME); return 0; } ret = memcmp(header, limit_fw->data, sizeof(header)); if (ret) { seq_printf(m, "LIMIT file was not matched\n"); release_firmware(limit_fw); return 0; } else { cts_info("Matched limit file!"); } memcpy(&limit, limit_fw->data, limit_fw->size); release_firmware(limit_fw); seq_printf(m, "Limit version: %x, type:%d\n", limit.version, limit.type); seq_printf(m, "\n"); seq_printf(m, "Switch status:\n"); seq_printf(m, " int_item : %d\n", limit.int_item); seq_printf(m, " reset_item : %d\n", limit.reset_item); seq_printf(m, " normal_rawdata_item : %d\n", limit.normal_rawdata_item); seq_printf(m, " normal_noise_item : %d\n", limit.normal_noise_item); seq_printf(m, " open_item : %d\n", limit.open_item); seq_printf(m, " short_item : %d\n", limit.short_item); seq_printf(m, " comp_cap_item : %d\n", limit.comp_cap_item); seq_printf(m, " gstr_rawdata_item : %d\n", limit.gstr_rawdata_item); seq_printf(m, " gstrlp_rawdata_item : %d\n", limit.gstrlp_rawdata_item); seq_printf(m, " gstr_noise_item : %d\n", limit.gstr_noise_item); seq_printf(m, " gstrlp_noise_item : %d\n", limit.gstrlp_noise_item); seq_printf(m, " stylus_rawdata_item : %d\n", limit.stylus_rawdata_item); seq_printf(m, " stylus_noise_item : %d\n", limit.stylus_noise_item); seq_printf(m, " stylus_mnt_rawdata_item : %d\n", limit.stylus_mnt_rawdata_item); seq_printf(m, "\n"); seq_printf(m, "Threshold:\n"); seq_printf(m, " normal_rawdata_frames : %d\n", limit.normal_rawdata_frames); seq_printf(m, " normal_rawdata_min : %d\n", limit.normal_rawdata_min); seq_printf(m, " normal_rawdata_max : %d\n", limit.normal_rawdata_max); seq_printf(m, " normal_noise_frames : %d\n", limit.normal_noise_frames); seq_printf(m, " normal_noise_max : %d\n", limit.normal_noise_max); seq_printf(m, " normal_open_min : %d\n", limit.normal_open_min); seq_printf(m, " normal_short_min : %d\n", limit.normal_short_min); seq_printf(m, " normal_compcap_min : %d\n", limit.normal_compcap_min); seq_printf(m, " normal_compcap_max : %d\n", limit.normal_compcap_max); seq_printf(m, " gstr_rawdata_frames : %d\n", limit.gstr_rawdata_frames); seq_printf(m, " gstr_rawdata_min : %d\n", limit.gstr_rawdata_min); seq_printf(m, " gstr_rawdata_max : %d\n", limit.gstr_rawdata_max); seq_printf(m, " gstrlp_rawdata_frames : %d\n", limit.gstrlp_rawdata_frames); seq_printf(m, " gstrlp_rawdata_min : %d\n", limit.gstrlp_rawdata_min); seq_printf(m, " gstrlp_rawdata_max : %d\n", limit.gstrlp_rawdata_max); seq_printf(m, " gstr_noise_frames : %d\n", limit.gstr_noise_frames); seq_printf(m, " gstr_noise_max : %d\n", limit.gstr_noise_max); seq_printf(m, " gstrlp_noise_frames : %d\n", limit.gstrlp_noise_frames); seq_printf(m, " gstrlp_noise_max : %d\n", limit.gstrlp_noise_max); seq_printf(m, " stylus_rawdata_frames : %d\n", limit.stylus_rawdata_frames); seq_printf(m, " stylus_rawdata_min : %d\n", limit.stylus_rawdata_min); seq_printf(m, " stylus_rawdata_max : %d\n", limit.stylus_rawdata_max); seq_printf(m, " stylus_noise_frames : %d\n", limit.stylus_noise_frames); seq_printf(m, " stylus_noise_max : %d\n", limit.stylus_noise_max); seq_printf(m, " stylus_mnt_rawdata_frames : %d\n", limit.stylus_mnt_rawdata_frames); seq_printf(m, " stylus_mnt_rawdata_min : %d\n", limit.stylus_mnt_rawdata_min); seq_printf(m, " stylus_mnt_rawdata_max : %d\n", limit.stylus_mnt_rawdata_max); return 0; } static int cts_limit_open(struct inode *inode, struct file *file) { return single_open(file, cts_limit_show, pde_data(inode)); } #if LINUX_VERSION_CODE < KERNEL_VERSION(5, 6, 0) static const struct file_operations cts_limit_ops = { .owner = THIS_MODULE, .open = cts_limit_open, .read = seq_read, }; #else static const struct proc_ops cts_limit_ops = { .proc_open = cts_limit_open, .proc_read = seq_read, }; #endif static void cts_print_limit_value(struct cts_limit limit) { cts_info("limit version : %x", limit.version); cts_info("int_item : %d", limit.int_item); cts_info("reset_item : %d", limit.reset_item); cts_info("normal_rawdata_item : %d", limit.normal_rawdata_item); cts_info("normal_noise_item : %d", limit.normal_noise_item); cts_info("open_item : %d", limit.open_item); cts_info("short_item : %d", limit.short_item); cts_info("comp_cap_item : %d", limit.comp_cap_item); cts_info("gstr_rawdata_item : %d", limit.gstr_rawdata_item); cts_info("gstrlp_rawdata_item : %d", limit.gstrlp_rawdata_item); cts_info("gstr_noise_item : %d", limit.gstr_noise_item); cts_info("gstrlp_noise_item : %d", limit.gstrlp_noise_item); cts_info("stylus_rawdata_item : %d", limit.stylus_rawdata_item); cts_info("stylus_noise_item : %d", limit.stylus_noise_item); cts_info("stylus_mnt_raw_item : %d", limit.stylus_mnt_rawdata_item); cts_info("type : %d", limit.type); cts_info("----------------------------"); cts_info("normal_rawdata_frames : %d", limit.normal_rawdata_frames); cts_info("normal_rawdata_min : %d", limit.normal_rawdata_min); cts_info("normal_rawdata_max : %d", limit.normal_rawdata_max); cts_info("normal_noise_frames : %d", limit.normal_noise_frames); cts_info("normal_noise_max : %d", limit.normal_noise_max); cts_info("normal_open_min : %d", limit.normal_open_min); cts_info("normal_short_min : %d", limit.normal_short_min); cts_info("normal_compcap_min : %d", limit.normal_compcap_min); cts_info("normal_compcap_max : %d", limit.normal_compcap_max); cts_info("gstr_rawdata_frames : %d", limit.gstr_rawdata_frames); cts_info("gstr_rawdata_min : %d", limit.gstr_rawdata_min); cts_info("gstr_rawdata_max : %d", limit.gstr_rawdata_max); cts_info("gstrlp_rawdata_frames : %d", limit.gstrlp_rawdata_frames); cts_info("gstrlp_rawdata_min : %d", limit.gstrlp_rawdata_min); cts_info("gstrlp_rawdata_max : %d", limit.gstrlp_rawdata_max); cts_info("gstr_noise_frames : %d", limit.gstr_noise_frames); cts_info("gstr_noise_max : %d", limit.gstr_noise_max); cts_info("gstrlp_noise_frames : %d", limit.gstrlp_noise_frames); cts_info("gstrlp_noise_max : %d", limit.gstrlp_noise_max); cts_info("stylus_rawdata_frames : %d", limit.stylus_rawdata_frames); cts_info("stylus_rawdata_min : %d", limit.stylus_rawdata_min); cts_info("stylus_rawdata_max : %d", limit.stylus_rawdata_max); cts_info("stylus_noise_frames : %d", limit.stylus_noise_frames); cts_info("stylus_noise_max : %d", limit.stylus_noise_max); cts_info("stylus_mnt_raw_frames : %d", limit.stylus_mnt_rawdata_frames); cts_info("stylus_mnt_raw_min : %d", limit.stylus_mnt_rawdata_min); cts_info("stylus_mnt_raw_max : %d", limit.stylus_mnt_rawdata_max); } static int cts_touch_test(struct seq_file *m, void *v, struct cts_limit limit) { struct chipone_ts_data *cts_data = m->private; struct cts_device *cts_dev = &cts_data->cts_dev; s64 reset_pin_test_elapsed_time = 0; struct cts_test_param reset_pin_test_param = { .test_item = CTS_TEST_RESET_PIN, .flags = 0, .elapsed_time_ms = &reset_pin_test_elapsed_time, }; s64 int_pin_test_elapsed_time = 0; struct cts_test_param int_pin_test_param = { .test_item = CTS_TEST_INT_PIN, .flags = 0, .elapsed_time_ms = &int_pin_test_elapsed_time, }; struct cts_rawdata_test_priv_param rawdata_test_priv_param = { .frames = 16, //.work_mode = 0, }; s64 rawdata_test_elapsed_time = 0; struct cts_test_param rawdata_test_param = { .test_item = CTS_TEST_RAWDATA, .flags = CTS_TEST_FLAG_VALIDATE_DATA | CTS_TEST_FLAG_VALIDATE_MIN | CTS_TEST_FLAG_VALIDATE_MAX | CTS_TEST_FLAG_STOP_TEST_IF_VALIDATE_FAILED | CTS_TEST_FLAG_DUMP_TEST_DATA_TO_CONSOLE | CTS_TEST_FLAG_DUMP_TEST_DATA_TO_FILE, .test_data_filepath = NULL, .num_invalid_node = 0, .invalid_nodes = NULL, .elapsed_time_ms = &rawdata_test_elapsed_time, .priv_param = &rawdata_test_priv_param, .priv_param_size = sizeof(rawdata_test_priv_param), }; struct cts_noise_test_priv_param noise_test_priv_param = { .frames = 50, //.work_mode = 0, }; s64 noise_test_elapsed_time = 0; struct cts_test_param noise_test_param = { .test_item = CTS_TEST_NOISE, .flags = CTS_TEST_FLAG_VALIDATE_DATA | CTS_TEST_FLAG_VALIDATE_MAX | CTS_TEST_FLAG_STOP_TEST_IF_VALIDATE_FAILED | CTS_TEST_FLAG_DUMP_TEST_DATA_TO_CONSOLE | CTS_TEST_FLAG_DUMP_TEST_DATA_TO_FILE, .test_data_filepath = NULL, .num_invalid_node = 0, .invalid_nodes = NULL, .elapsed_time_ms = &noise_test_elapsed_time, .priv_param = &noise_test_priv_param, .priv_param_size = sizeof(noise_test_priv_param), }; s64 open_test_elapsed_time = 0; struct cts_test_param open_test_param = { .test_item = CTS_TEST_OPEN, .flags = CTS_TEST_FLAG_VALIDATE_DATA | CTS_TEST_FLAG_VALIDATE_MIN | CTS_TEST_FLAG_STOP_TEST_IF_VALIDATE_FAILED | CTS_TEST_FLAG_DUMP_TEST_DATA_TO_CONSOLE | CTS_TEST_FLAG_DUMP_TEST_DATA_TO_FILE, .test_data_filepath = NULL, .num_invalid_node = 0, .invalid_nodes = NULL, .elapsed_time_ms = &open_test_elapsed_time, }; s64 short_test_elapsed_time = 0; struct cts_test_param short_test_param = { .test_item = CTS_TEST_SHORT, .flags = CTS_TEST_FLAG_VALIDATE_DATA | CTS_TEST_FLAG_VALIDATE_MIN | CTS_TEST_FLAG_STOP_TEST_IF_VALIDATE_FAILED | CTS_TEST_FLAG_DUMP_TEST_DATA_TO_CONSOLE | CTS_TEST_FLAG_DUMP_TEST_DATA_TO_FILE, .test_data_filepath = NULL, .num_invalid_node = 0, .invalid_nodes = NULL, .elapsed_time_ms = &short_test_elapsed_time, }; s64 comp_cap_test_elapsed_time = 0; struct cts_test_param comp_cap_test_param = { .test_item = CTS_TEST_COMPENSATE_CAP, .flags = CTS_TEST_FLAG_VALIDATE_DATA | CTS_TEST_FLAG_VALIDATE_MIN | CTS_TEST_FLAG_VALIDATE_MAX | CTS_TEST_FLAG_STOP_TEST_IF_VALIDATE_FAILED | CTS_TEST_FLAG_DUMP_TEST_DATA_TO_CONSOLE | CTS_TEST_FLAG_DUMP_TEST_DATA_TO_FILE, .test_data_filepath = NULL, .num_invalid_node = 0, .invalid_nodes = NULL, .elapsed_time_ms = &comp_cap_test_elapsed_time, }; int normal_rawdata_frames; int normal_rawdata_min; int normal_rawdata_max; int normal_noise_frames; int normal_noise_max; int normal_open_min; int normal_short_min; int normal_compcap_min; int normal_compcap_max; int rawdata_test_result = 0; int noise_test_result = 0; int open_test_result = 0; int short_test_result = 0; int comp_cap_test_result = 0; char touch_data_filepath[256]; int retry; int result_all = 0; snprintf(touch_data_filepath, sizeof(touch_data_filepath), TOUCH_DATA_DIRECTORY_PREFIX"/"RAWDATA_TEST_DATA_FILENAME); rawdata_test_param.test_data_filepath = kstrdup(touch_data_filepath, GFP_KERNEL); snprintf(touch_data_filepath, sizeof(touch_data_filepath), TOUCH_DATA_DIRECTORY_PREFIX"/"NOISE_TEST_DATA_FILENAME); noise_test_param.test_data_filepath = kstrdup(touch_data_filepath, GFP_KERNEL); snprintf(touch_data_filepath, sizeof(touch_data_filepath), TOUCH_DATA_DIRECTORY_PREFIX"/"OPEN_TEST_DATA_FILENAME); open_test_param.test_data_filepath = kstrdup(touch_data_filepath, GFP_KERNEL); snprintf(touch_data_filepath, sizeof(touch_data_filepath), TOUCH_DATA_DIRECTORY_PREFIX"/"SHORT_TEST_DATA_FILENAME); short_test_param.test_data_filepath = kstrdup(touch_data_filepath, GFP_KERNEL); snprintf(touch_data_filepath, sizeof(touch_data_filepath), TOUCH_DATA_DIRECTORY_PREFIX"/"COMP_CAP_TEST_DATA_FILENAME); comp_cap_test_param.test_data_filepath = kstrdup(touch_data_filepath, GFP_KERNEL); normal_rawdata_frames = limit.normal_rawdata_frames; normal_rawdata_min = limit.normal_rawdata_min; normal_rawdata_max = limit.normal_rawdata_max; normal_noise_frames = limit.normal_noise_frames; normal_noise_max = limit.normal_noise_max; normal_open_min = limit.normal_open_min; normal_short_min = limit.normal_short_min; normal_compcap_min = limit.normal_compcap_min; normal_compcap_max = limit.normal_compcap_max; rawdata_test_priv_param.frames = normal_rawdata_frames; rawdata_test_param.min = &normal_rawdata_min; rawdata_test_param.max = &normal_rawdata_max; noise_test_priv_param.frames = normal_noise_frames; noise_test_param.max = &normal_noise_max; open_test_param.min = &normal_open_min; short_test_param.min = &normal_short_min; comp_cap_test_param.min = &normal_compcap_min; comp_cap_test_param.max = &normal_compcap_max; if (limit.int_item && cts_test_int_pin(cts_dev, &int_pin_test_param)) { result_all++; } if (limit.reset_item && cts_test_reset_pin(cts_dev, &reset_pin_test_param)) { result_all++; } if (limit.normal_rawdata_item) { retry = 3; do { rawdata_test_result = cts_test_rawdata(cts_dev, &rawdata_test_param); } while (rawdata_test_result < 0 && retry--); if (rawdata_test_result) { result_all++; } } if (limit.normal_noise_item) { retry = 3; do { noise_test_result = cts_test_noise(cts_dev, &noise_test_param); } while (noise_test_result < 0 && retry--); if (noise_test_result) { result_all++; } } if (limit.open_item) { retry = 3; do { open_test_result = cts_test_open(cts_dev, &open_test_param); } while (open_test_result < 0 && retry--); if (open_test_result) { result_all++; } } if (limit.short_item) { retry = 3; do { short_test_result = cts_test_short(cts_dev, &short_test_param); } while (short_test_result < 0 && retry--); if (short_test_result) { result_all++; } } if (limit.comp_cap_item) { retry = 3; do { comp_cap_test_result = cts_test_compensate_cap(cts_dev, &comp_cap_test_param); } while (comp_cap_test_result < 0 && retry--); if (comp_cap_test_result) { result_all++; } } if (rawdata_test_param.test_data_filepath) { kfree(rawdata_test_param.test_data_filepath); } if (noise_test_param.test_data_filepath) { kfree(noise_test_param.test_data_filepath); } if (open_test_param.test_data_filepath) { kfree(open_test_param.test_data_filepath); } if (short_test_param.test_data_filepath) { kfree(short_test_param.test_data_filepath); } if (comp_cap_test_param.test_data_filepath) { kfree(comp_cap_test_param.test_data_filepath); } return result_all; } static int cts_stylus_test(struct seq_file *m, void *v, struct cts_limit limit) { struct chipone_ts_data *cts_data = m->private; struct cts_device *cts_dev = &cts_data->cts_dev; struct cts_rawdata_test_priv_param stylus_rawdata_test_priv_param = { .frames = 16, //.work_mode = 0, }; s64 stylus_rawdata_test_elapsed_time = 0; struct cts_test_param stylus_rawdata_test_param = { .test_item = CTS_TEST_STYLUS_RAWDATA, .flags = CTS_TEST_FLAG_VALIDATE_DATA | CTS_TEST_FLAG_VALIDATE_MIN | CTS_TEST_FLAG_VALIDATE_MAX | CTS_TEST_FLAG_STOP_TEST_IF_VALIDATE_FAILED | CTS_TEST_FLAG_DUMP_TEST_DATA_TO_CONSOLE | CTS_TEST_FLAG_DUMP_TEST_DATA_TO_FILE, .test_data_filepath = NULL, .num_invalid_node = 0, .invalid_nodes = NULL, .elapsed_time_ms = &stylus_rawdata_test_elapsed_time, .priv_param = &stylus_rawdata_test_priv_param, .priv_param_size = sizeof(stylus_rawdata_test_priv_param), }; struct cts_noise_test_priv_param stylus_noise_test_priv_param = { .frames = 50, //.work_mode = 0, }; s64 stylus_noise_test_elapsed_time = 0; struct cts_test_param stylus_noise_test_param = { .test_item = CTS_TEST_NOISE, .flags = CTS_TEST_FLAG_VALIDATE_DATA | CTS_TEST_FLAG_VALIDATE_MAX | CTS_TEST_FLAG_STOP_TEST_IF_VALIDATE_FAILED | CTS_TEST_FLAG_DUMP_TEST_DATA_TO_CONSOLE | CTS_TEST_FLAG_DUMP_TEST_DATA_TO_FILE, .test_data_filepath = NULL, .num_invalid_node = 0, .invalid_nodes = NULL, .elapsed_time_ms = &stylus_noise_test_elapsed_time, .priv_param = &stylus_noise_test_priv_param, .priv_param_size = sizeof(stylus_noise_test_priv_param), }; struct cts_rawdata_test_priv_param stylus_mnt_rawdata_test_priv_param = { .frames = 16, //.work_mode = 0, }; s64 stylus_mnt_rawdata_test_elapsed_time = 0; struct cts_test_param stylus_mnt_rawdata_test_param = { .test_item = CTS_TEST_STYLUS_RAWDATA, .flags = CTS_TEST_FLAG_VALIDATE_DATA | CTS_TEST_FLAG_VALIDATE_MIN | CTS_TEST_FLAG_VALIDATE_MAX | CTS_TEST_FLAG_STOP_TEST_IF_VALIDATE_FAILED | CTS_TEST_FLAG_DUMP_TEST_DATA_TO_CONSOLE | CTS_TEST_FLAG_DUMP_TEST_DATA_TO_FILE, .test_data_filepath = NULL, .num_invalid_node = 0, .invalid_nodes = NULL, .elapsed_time_ms = &stylus_mnt_rawdata_test_elapsed_time, .priv_param = &stylus_mnt_rawdata_test_priv_param, .priv_param_size = sizeof(stylus_mnt_rawdata_test_priv_param), }; int stylus_rawdata_frames; int stylus_rawdata_min; int stylus_rawdata_max; int stylus_noise_frames; int stylus_noise_max; int stylus_mnt_rawdata_frames; int stylus_mnt_rawdata_min; int stylus_mnt_rawdata_max; int stylus_rawdata_test_result = 0; int stylus_noise_test_result = 0; int stylus_mnt_rawdata_test_result = 0; char touch_data_filepath[256]; int retry; int result_all = 0; snprintf(touch_data_filepath, sizeof(touch_data_filepath), TOUCH_DATA_DIRECTORY_PREFIX"/"STYLUS_RAWDATA_TEST_DATA_FILENAME); stylus_rawdata_test_param.test_data_filepath = kstrdup(touch_data_filepath, GFP_KERNEL); snprintf(touch_data_filepath, sizeof(touch_data_filepath), TOUCH_DATA_DIRECTORY_PREFIX"/"STYLUS_NOISE_TEST_DATA_FILENAME); stylus_noise_test_param.test_data_filepath = kstrdup(touch_data_filepath, GFP_KERNEL); snprintf(touch_data_filepath, sizeof(touch_data_filepath), TOUCH_DATA_DIRECTORY_PREFIX"/"STYLUS_MNT_NOISE_TEST_DATA_FILENAME); stylus_mnt_rawdata_test_param.test_data_filepath = kstrdup(touch_data_filepath, GFP_KERNEL); stylus_rawdata_frames = limit.stylus_rawdata_frames; stylus_rawdata_min = limit.stylus_rawdata_min; stylus_rawdata_max = limit.stylus_rawdata_max; stylus_noise_frames = limit.stylus_noise_frames; stylus_noise_max = limit.stylus_noise_max; stylus_mnt_rawdata_frames = limit.stylus_mnt_rawdata_frames; stylus_mnt_rawdata_min = limit.stylus_mnt_rawdata_min; stylus_mnt_rawdata_max = limit.stylus_mnt_rawdata_max; stylus_rawdata_test_priv_param.frames = stylus_rawdata_frames; stylus_rawdata_test_param.min = &stylus_rawdata_min; stylus_rawdata_test_param.max = &stylus_rawdata_max; stylus_noise_test_priv_param.frames = stylus_noise_frames; stylus_noise_test_param.max = &stylus_noise_max; stylus_mnt_rawdata_test_priv_param.frames = stylus_mnt_rawdata_frames; stylus_mnt_rawdata_test_param.min = &stylus_mnt_rawdata_min; stylus_mnt_rawdata_test_param.max = &stylus_mnt_rawdata_max; if (limit.stylus_rawdata_item) { retry = 3; do { stylus_rawdata_test_result = cts_test_stylus_rawdata(cts_dev, &stylus_rawdata_test_param); } while (stylus_rawdata_test_result < 0 && retry--); if (stylus_rawdata_test_result) { result_all++; } } if (limit.stylus_noise_item) { retry = 3; do { stylus_noise_test_result = cts_test_stylus_noise(cts_dev, &stylus_noise_test_param); } while (stylus_noise_test_result < 0 && retry--); if (stylus_noise_test_result) { result_all++; } } if (limit.stylus_mnt_rawdata_item) { retry = 3; do { stylus_mnt_rawdata_test_result = cts_test_stylus_mnt_rawdata(cts_dev, &stylus_mnt_rawdata_test_param); } while (stylus_mnt_rawdata_test_result < 0 && retry--); if (stylus_mnt_rawdata_test_result) { result_all++; } } if (stylus_rawdata_test_param.test_data_filepath) { kfree(stylus_rawdata_test_param.test_data_filepath); } if (stylus_noise_test_param.test_data_filepath) { kfree(stylus_noise_test_param.test_data_filepath); } if (stylus_mnt_rawdata_test_param.test_data_filepath) { kfree(stylus_mnt_rawdata_test_param.test_data_filepath); } return result_all; } static int cts_factory_test_show(struct seq_file *m, void *v) { struct chipone_ts_data *cts_data = m->private; struct cts_device *cts_dev = &cts_data->cts_dev; const struct firmware *limit_fw = NULL; struct cts_limit limit; char header[7] = {'C', 'h', 'i', 'p', 'o', 'n', 'e'}; ktime_t start_time, end_time, delta_time; u16 fw_version; int result_all = 0; int ret; ret = request_firmware(&limit_fw, CFG_CTS_FACTORY_LIMIT_FILENAME, &cts_dev->pdata->ts_input_dev->dev); if (ret) { cts_err("Request %s failed!", CFG_CTS_FACTORY_LIMIT_FILENAME); return 0; } ret = memcmp(header, limit_fw->data, sizeof(header)); if (ret) { cts_err("LIMIT file was not matched"); release_firmware(limit_fw); return 0; } else { cts_info("Matched limit file!"); } memcpy(&limit, limit_fw->data, limit_fw->size); release_firmware(limit_fw); cts_print_limit_value(limit); start_time = ktime_get(); ret = cts_tcs_get_fw_ver(cts_dev, &fw_version); if (ret) { cts_err("Factory test get firmware version failed"); fw_version = 0; } cts_info("Firmware Version: 0x%04X", fw_version); result_all += cts_touch_test(m, v, limit); result_all += cts_stylus_test(m, v, limit); end_time = ktime_get(); delta_time = ktime_sub(end_time, start_time); cts_info("Factory test, total ELAPSED TIME: %lldms", ktime_to_ms(delta_time)); seq_printf(m, "%s\n", result_all ? "FAIL" : "PASS"); return 0; } static int cts_factory_test_open(struct inode *inode, struct file *file) { return single_open(file, cts_factory_test_show, pde_data(inode)); } #if LINUX_VERSION_CODE < KERNEL_VERSION(5, 6, 0) static const struct file_operations cts_factory_test_ops = { .owner = THIS_MODULE, .open = cts_factory_test_open, .read = seq_read, }; #else static const struct proc_ops cts_factory_test_ops = { .proc_open = cts_factory_test_open, .proc_read = seq_read, }; #endif int cts_oem_init(struct chipone_ts_data *cts_data) { struct cts_oem_data *oem_data = NULL; int ret; if (cts_data == NULL) { cts_err("Init with cts_data = NULL"); return -EINVAL; } cts_info("Init"); cts_data->oem_data = NULL; oem_data = kzalloc(sizeof(*oem_data), GFP_KERNEL); if (oem_data == NULL) { cts_err("Alloc oem data failed"); return -ENOMEM; } cts_info(" - Create '/proc/"OEM_SELFTEST_PROC_FILENAME"'"); oem_data->selftest_proc_entry = proc_create_data(OEM_SELFTEST_PROC_FILENAME, S_IRUGO, NULL, &selftest_proc_fops, cts_data); if (oem_data->selftest_proc_entry == NULL) { cts_err("Create '/proc/"OEM_SELFTEST_PROC_FILENAME"' failed"); ret = -EFAULT; goto free_oem_data; } oem_data->limit_entry = proc_create_data(OEM_LIMIT_PROC_FILENAME, S_IRUGO, NULL, &cts_limit_ops, cts_data); if (oem_data->limit_entry == NULL) { cts_err("Create '/proc/"OEM_LIMIT_PROC_FILENAME"' failed"); ret = -EFAULT; goto free_oem_data; } oem_data->factory_test_entry = proc_create_data(OEM_FACTORY_TEST_PROC_FILENAME, S_IRUGO, NULL, &cts_factory_test_ops, cts_data); if (oem_data->factory_test_entry == NULL) { cts_err("Create '/proc/"OEM_FACTORY_TEST_PROC_FILENAME"' failed"); ret = -EFAULT; goto free_oem_data; } oem_data->rawdata_proc_entry = proc_create_data(OEM_RAWDATA_PROC_FILENAME, S_IRUGO, NULL, &cts_rawdata_ops, cts_data); if (oem_data->rawdata_proc_entry == NULL) { cts_err("Create '/proc/"OEM_RAWDATA_PROC_FILENAME"' failed"); ret = -EFAULT; goto free_oem_data; } oem_data->manual_proc_entry = proc_create_data(OEM_MANUAL_PROC_FILENAME, S_IRUGO, NULL, &cts_manual_ops, cts_data); if (oem_data->manual_proc_entry == NULL) { cts_err("Create '/proc/"OEM_MANUAL_PROC_FILENAME"' failed"); ret = -EFAULT; goto free_oem_data; } oem_data->diffdata_proc_entry = proc_create_data(OEM_DIFFDATA_PROC_FILENAME, S_IRUGO, NULL, &cts_diffdata_ops, cts_data); if (oem_data->diffdata_proc_entry == NULL) { cts_err("Create '/proc/"OEM_DIFFDATA_PROC_FILENAME"' failed"); ret = -EFAULT; goto free_oem_data; } oem_data->cnegdata_proc_entry = proc_create_data(OEM_CNEGDATA_PROC_FILENAME, S_IRUGO, NULL, &cts_cnegdata_ops, cts_data); if (oem_data->cnegdata_proc_entry == NULL) { cts_err("Create '/proc/"OEM_CNEGDATA_PROC_FILENAME"' failed"); ret = -EFAULT; goto free_oem_data; } cts_data->oem_data = oem_data; oem_data->cts_data = cts_data; return 0; free_oem_data: kfree(oem_data); return ret; } int cts_oem_deinit(struct chipone_ts_data *cts_data) { struct cts_oem_data *oem_data = NULL; if (cts_data == NULL) { cts_err("Deinit with cts_data = NULL"); return -EINVAL; } if (cts_data->oem_data == NULL) { cts_warn("Deinit with oem_data = NULL"); return 0; } cts_info("Deinit"); oem_data = cts_data->oem_data; if (oem_data->cnegdata_proc_entry) { cts_info(" Remove '/proc/"OEM_CNEGDATA_PROC_FILENAME"'"); remove_proc_entry(OEM_CNEGDATA_PROC_FILENAME, NULL); } if (oem_data->selftest_proc_entry) { cts_info(" Remove '/proc/"OEM_SELFTEST_PROC_FILENAME"'"); remove_proc_entry(OEM_SELFTEST_PROC_FILENAME, NULL); } if (oem_data->limit_entry) { cts_info(" Remove '/proc/"OEM_LIMIT_PROC_FILENAME"'"); remove_proc_entry(OEM_LIMIT_PROC_FILENAME, NULL); } if (oem_data->factory_test_entry) { cts_info(" Remove '/proc/"OEM_FACTORY_TEST_PROC_FILENAME"'"); remove_proc_entry(OEM_FACTORY_TEST_PROC_FILENAME, NULL); } if (oem_data->rawdata_proc_entry) { cts_info(" Remove '/proc/"OEM_RAWDATA_PROC_FILENAME"'"); remove_proc_entry(OEM_RAWDATA_PROC_FILENAME, NULL); } if (oem_data->manual_proc_entry) { cts_info(" Remove '/proc/"OEM_MANUAL_PROC_FILENAME"'"); remove_proc_entry(OEM_MANUAL_PROC_FILENAME, NULL); } if (oem_data->diffdata_proc_entry) { cts_info(" Remove '/proc/"OEM_DIFFDATA_PROC_FILENAME"'"); remove_proc_entry(OEM_DIFFDATA_PROC_FILENAME, NULL); } free_selftest_data_mem(oem_data); kfree(cts_data->oem_data); cts_data->oem_data = NULL; return 0; }