diff options
author | Wendly Li <wendlyli@google.com> | 2022-02-23 16:35:22 +0000 |
---|---|---|
committer | Wendly Li <wendlyli@google.com> | 2022-02-23 16:42:51 +0000 |
commit | ccb598ed429baf2522cacef90fc27ef6af8ca39f (patch) | |
tree | 0f2bca6e44dfcef82a435bc44661f1051799280c /goodix_ts_proc.c | |
parent | 1437c5883fe85a5e543371f37d376c5a2c3f7ab7 (diff) | |
download | goodix_touch-ccb598ed429baf2522cacef90fc27ef6af8ca39f.tar.gz |
Import v1.0.3 driver
- Improve test APIs
- Fix set_scan_mode API
- Add continue mode API
Bug: 214118804
Test: Check APIs works properly
Change-Id: I0610c41fac5bc38758fde1221fe1602bbfa7595c
Signed-off-by: Wendly Li <wendlyli@google.com>
Diffstat (limited to 'goodix_ts_proc.c')
-rw-r--r-- | goodix_ts_proc.c | 1844 |
1 files changed, 1756 insertions, 88 deletions
diff --git a/goodix_ts_proc.c b/goodix_ts_proc.c index 43955cb..d4f58d9 100644 --- a/goodix_ts_proc.c +++ b/goodix_ts_proc.c @@ -6,7 +6,10 @@ #define CMD_FW_UPDATE "fw_update" #define CMD_AUTO_TEST "auto_test" +#define CMD_OPEN_TEST "open_test" +#define CMD_SELF_OPEN_TEST "self_open_test" #define CMD_NOISE_TEST "noise_test" +#define CMD_SHORT_TEST "short_test" #define CMD_GET_PACKAGE_ID "get_package_id" #define CMD_GET_VERSION "get_version" #define CMD_GET_RAWDATA "get_raw" @@ -22,19 +25,713 @@ #define CMD_SET_ESD_ENABLE "set_esd_enable" #define CMD_SET_DEBUG_LOG "set_debug_log" #define CMD_SET_SCAN_MODE "set_scan_mode" +#define CMD_SET_CONTINUE_MODE "set_continue_mode" #define CMD_GET_CHANNEL_NUM "get_channel_num" #define CMD_GET_TX_FREQ "get_tx_freq" #define CMD_RESET "reset" #define CMD_SET_SENSE_ENABLE "set_sense_enable" +/* test limits keyword */ +#define CSV_TP_SPECIAL_RAW_MIN "special_raw_min" +#define CSV_TP_SPECIAL_RAW_MAX "special_raw_max" +#define CSV_TP_SPECIAL_RAW_DELTA "special_raw_delta" +#define CSV_TP_SHORT_THRESHOLD "shortciurt_threshold" +#define CSV_TP_SPECIAL_SELFRAW_MAX "special_selfraw_max" +#define CSV_TP_SPECIAL_SELFRAW_MIN "special_selfraw_min" +#define CSV_TP_NOISE_LIMIT "noise_data_limit" +#define CSV_TP_SELFNOISE_LIMIT "noise_selfdata_limit" +#define CSV_TP_TEST_CONFIG "test_config" + #define SHORT_SIZE 100 #define LARGE_SIZE 4096 +#define HUGE_SIZE 100 * 1024 static struct goodix_ts_core *cd; static char wbuf[SHORT_SIZE]; static char *rbuf; static uint32_t index; +/* factory test */ #define ABS(x) ((x >= 0) ? x : -x) +#define MAX(a, b) ((a > b) ? a : b) + +#define GTP_CAP_TEST 1 +#define GTP_DELTA_TEST 2 +#define GTP_NOISE_TEST 3 +#define GTP_SHORT_TEST 5 +#define GTP_SELFCAP_TEST 6 +#define GTP_SELFNOISE_TEST 7 +#define MAX_TEST_ITEMS 10 /* 0P-1P-2P-3P-5P total test items */ + +#define TEST_OK 1 +#define TEST_NG 0 + +#define MAX_LINE_LEN (1024 * 6) +#define MAX_FRAME_CNT 16 +#define MAX_DRV_NUM 17 +#define MAX_SEN_NUM 35 +#define MAX_SHORT_NUM 15 + +typedef struct __attribute__((packed)) { + u8 result; + u8 drv_drv_num; + u8 sen_sen_num; + u8 drv_sen_num; + u8 drv_gnd_avdd_num; + u8 sen_gnd_avdd_num; + u16 checksum; +} test_result_t; + +/* nottingham drv-sen map */ +static u8 not_drv_map[] = { 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51 }; + +static u8 not_sen_map[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, + 33, 34 }; + +struct ts_short_res { + u8 short_num; + s16 short_msg[4 * MAX_SHORT_NUM]; +}; + +struct ts_test_rawdata { + s16 data[MAX_DRV_NUM * MAX_SEN_NUM]; + u32 size; +}; + +struct ts_test_self_rawdata { + s16 data[MAX_DRV_NUM + MAX_SEN_NUM]; + u32 size; +}; + +struct goodix_ts_test { + bool item[MAX_TEST_ITEMS]; + char result[MAX_TEST_ITEMS]; + s16 min_limits[MAX_DRV_NUM * MAX_SEN_NUM]; + s16 max_limits[MAX_DRV_NUM * MAX_SEN_NUM]; + s16 deviation_limits[MAX_DRV_NUM * MAX_SEN_NUM]; + s16 self_max_limits[MAX_DRV_NUM + MAX_SEN_NUM]; + s16 self_min_limits[MAX_DRV_NUM + MAX_SEN_NUM]; + s16 noise_threshold; + s16 short_threshold; + s16 r_drv_drv_threshold; + s16 r_drv_sen_threshold; + s16 r_sen_sen_threshold; + s16 r_drv_gnd_threshold; + s16 r_sen_gnd_threshold; + s16 avdd_value; + + int freq; + int raw_data_cnt; + struct ts_test_rawdata rawdata[MAX_FRAME_CNT]; + struct ts_test_rawdata deltadata[MAX_FRAME_CNT]; + int noise_data_cnt; + struct ts_test_rawdata noisedata[MAX_FRAME_CNT]; + struct ts_test_self_rawdata selfrawdata; + struct ts_short_res short_res; +}; +static struct goodix_ts_test *ts_test; + +static int malloc_test_resource(void) +{ + ts_test = kzalloc(sizeof(*ts_test), GFP_KERNEL); + if (!ts_test) + return -ENOMEM; + return 0; +} + +static void release_test_resource(void) +{ + kfree(ts_test); + ts_test = NULL; +} + +#define CHN_VDD 0xFF +#define CHN_GND 0x7F +#define DRV_CHANNEL_FLAG 0x80 +#define SHORT_TEST_TIME_REG_NOT 0x1479E +#define SHORT_TEST_STATUS_REG_NOT 0x13400 +#define SHORT_TEST_RESULT_REG_NOT 0x13408 +#define DRV_DRV_SELFCODE_REG_NOT 0x13446 +#define SEN_SEN_SELFCODE_REG_NOT 0x136EE +#define DRV_SEN_SELFCODE_REG_NOT 0x14152 +#define DIFF_CODE_DATA_REG_NOT 0x14734 +#define CAL_CHAN_TO_CHAN_RES(v1, v2) (v1 / v2 - 1) * 55 + 45 +#define CAL_CHAN_TO_AVDD_RES(v1, v2) 64 * (2 * v2 - 25) * 76 / v1 - 15 +#define CAL_CHAN_TO_GND_RES(v) 120000 / v - 16 +static u32 map_die2pin(u32 chn_num) +{ + int i = 0; + u32 res = 255; + + if (chn_num & DRV_CHANNEL_FLAG) + chn_num = (chn_num & ~DRV_CHANNEL_FLAG) + MAX_SEN_NUM; + + for (i = 0; i < MAX_SEN_NUM; i++) { + if (not_sen_map[i] == chn_num) { + res = i; + break; + } + } + /* res != 255 mean found the corresponding channel num */ + if (res != 255) + return res; + /* if cannot find in SenMap try find in DrvMap */ + for (i = 0; i < MAX_DRV_NUM; i++) { + if (not_drv_map[i] == chn_num) { + res = i; + break; + } + } + if (i >= MAX_DRV_NUM) + ts_err("Faild found corrresponding channel num:%d", chn_num); + else + res |= DRV_CHANNEL_FLAG; + + return res; +} + +static void goodix_save_short_res(u16 chn1, u16 chn2, int r) +{ + int i; + u8 repeat_cnt = 0; + u8 repeat = 0; + struct ts_short_res *short_res = &ts_test->short_res; + + if (chn1 == chn2 || short_res->short_num >= MAX_SHORT_NUM) + return; + + for (i = 0; i < short_res->short_num; i++) { + repeat_cnt = 0; + if (short_res->short_msg[4 * i] == chn1) + repeat_cnt++; + if (short_res->short_msg[4 * i] == chn2) + repeat_cnt++; + if (short_res->short_msg[4 * i + 1] == chn1) + repeat_cnt++; + if (short_res->short_msg[4 * i + 1] == chn2) + repeat_cnt++; + if (repeat_cnt >= 2) { + repeat = 1; + break; + } + } + if (repeat == 0) { + short_res->short_msg[4 * short_res->short_num + 0] = chn1; + short_res->short_msg[4 * short_res->short_num + 1] = chn2; + short_res->short_msg[4 * short_res->short_num + 2] = + (r >> 8) & 0xFF; + short_res->short_msg[4 * short_res->short_num + 3] = r & 0xFF; + if (short_res->short_num < MAX_SHORT_NUM) + short_res->short_num++; + } +} + +static int gdix_check_tx_tx_shortcircut(u8 short_ch_num) +{ + int ret = 0, err = 0; + u32 r_threshold = 0, short_r = 0; + int size = 0, i = 0, j = 0; + u16 adc_signal = 0; + u8 master_pin_num, slave_pin_num; + u8 *data_buf; + u32 data_reg = DRV_DRV_SELFCODE_REG_NOT; + int max_drv_num = MAX_DRV_NUM; + int max_sen_num = MAX_SEN_NUM; + u16 self_capdata, short_die_num = 0; + + size = 4 + max_drv_num * 2 + 2; + data_buf = kzalloc(size, GFP_KERNEL); + if (!data_buf) { + ts_err("Failed to alloc memory"); + return -ENOMEM; + } + /* drv&drv shortcircut check */ + for (i = 0; i < short_ch_num; i++) { + ret = cd->hw_ops->read(cd, data_reg, data_buf, size); + if (ret < 0) { + ts_err("Failed read Drv-to-Drv short rawdata"); + err = -EINVAL; + break; + } + + if (checksum_cmp(data_buf, size, CHECKSUM_MODE_U8_LE)) { + ts_err("Drv-to-Drv adc data checksum error"); + err = -EINVAL; + break; + } + + r_threshold = ts_test->r_drv_drv_threshold; + short_die_num = le16_to_cpup((__le16 *)&data_buf[0]); + short_die_num -= max_sen_num; + if (short_die_num >= max_drv_num) { + ts_info("invalid short pad num:%d", + short_die_num + max_sen_num); + continue; + } + + /* TODO: j start position need recheck */ + self_capdata = le16_to_cpup((__le16 *)&data_buf[2]); + if (self_capdata == 0xffff || self_capdata == 0) { + ts_info("invalid self_capdata:0x%x", self_capdata); + continue; + } + + for (j = short_die_num + 1; j < max_drv_num; j++) { + adc_signal = + le16_to_cpup((__le16 *)&data_buf[4 + j * 2]); + + if (adc_signal < ts_test->short_threshold) + continue; + + short_r = + CAL_CHAN_TO_CHAN_RES(self_capdata, adc_signal); + if (short_r < r_threshold) { + master_pin_num = map_die2pin( + short_die_num + max_sen_num); + slave_pin_num = map_die2pin(j + max_sen_num); + if (master_pin_num == 0xFF || + slave_pin_num == 0xFF) { + ts_info("WARNNING invalid pin"); + continue; + } + goodix_save_short_res( + master_pin_num, slave_pin_num, short_r); + ts_err("short circut:R=%dK,R_Threshold=%dK", + short_r, r_threshold); + ts_err("%s%d--%s%d shortcircut", + (master_pin_num & DRV_CHANNEL_FLAG) + ? "DRV" + : "SEN", + (master_pin_num & ~DRV_CHANNEL_FLAG), + (slave_pin_num & DRV_CHANNEL_FLAG) + ? "DRV" + : "SEN", + (slave_pin_num & ~DRV_CHANNEL_FLAG)); + err = -EINVAL; + } + } + data_reg += size; + } + + kfree(data_buf); + return err; +} + +static int gdix_check_rx_rx_shortcircut(u8 short_ch_num) +{ + int ret = 0, err = 0; + u32 r_threshold = 0, short_r = 0; + int size = 0, i = 0, j = 0; + u16 adc_signal = 0; + u8 master_pin_num, slave_pin_num; + u8 *data_buf; + u32 data_reg = SEN_SEN_SELFCODE_REG_NOT; + int max_sen_num = MAX_SEN_NUM; + u16 self_capdata, short_die_num = 0; + + size = 4 + max_sen_num * 2 + 2; + data_buf = kzalloc(size, GFP_KERNEL); + if (!data_buf) { + ts_err("Failed to alloc memory"); + return -ENOMEM; + } + /* drv&drv shortcircut check */ + for (i = 0; i < short_ch_num; i++) { + ret = cd->hw_ops->read(cd, data_reg, data_buf, size); + if (ret) { + ts_err("Failed read Sen-to-Sen short rawdata"); + err = -EINVAL; + break; + } + + if (checksum_cmp(data_buf, size, CHECKSUM_MODE_U8_LE)) { + ts_err("Sen-to-Sen adc data checksum error"); + err = -EINVAL; + break; + } + + r_threshold = ts_test->r_sen_sen_threshold; + short_die_num = le16_to_cpup((__le16 *)&data_buf[0]); + if (short_die_num >= max_sen_num) { + ts_info("invalid short pad num:%d", short_die_num); + continue; + } + + /* TODO: j start position need recheck */ + self_capdata = le16_to_cpup((__le16 *)&data_buf[2]); + if (self_capdata == 0xffff || self_capdata == 0) { + ts_info("invalid self_capdata:0x%x", self_capdata); + continue; + } + + for (j = short_die_num + 1; j < max_sen_num; j++) { + adc_signal = + le16_to_cpup((__le16 *)&data_buf[4 + j * 2]); + + if (adc_signal < ts_test->short_threshold) + continue; + + short_r = + CAL_CHAN_TO_CHAN_RES(self_capdata, adc_signal); + if (short_r < r_threshold) { + master_pin_num = map_die2pin(short_die_num); + slave_pin_num = map_die2pin(j); + if (master_pin_num == 0xFF || + slave_pin_num == 0xFF) { + ts_info("WARNNING invalid pin"); + continue; + } + goodix_save_short_res( + master_pin_num, slave_pin_num, short_r); + ts_err("short circut:R=%dK,R_Threshold=%dK", + short_r, r_threshold); + ts_err("%s%d--%s%d shortcircut", + (master_pin_num & DRV_CHANNEL_FLAG) + ? "DRV" + : "SEN", + (master_pin_num & ~DRV_CHANNEL_FLAG), + (slave_pin_num & DRV_CHANNEL_FLAG) + ? "DRV" + : "SEN", + (slave_pin_num & ~DRV_CHANNEL_FLAG)); + err = -EINVAL; + } + } + data_reg += size; + } + + kfree(data_buf); + return err; +} + +static int gdix_check_tx_rx_shortcircut(u8 short_ch_num) +{ + int ret = 0, err = 0; + u32 r_threshold = 0, short_r = 0; + int size = 0, i = 0, j = 0; + u16 adc_signal = 0; + u8 master_pin_num, slave_pin_num; + u8 *data_buf = NULL; + u32 data_reg = DRV_SEN_SELFCODE_REG_NOT; + int max_drv_num = MAX_DRV_NUM; + int max_sen_num = MAX_SEN_NUM; + u16 self_capdata, short_die_num = 0; + + size = 4 + max_drv_num * 2 + 2; + data_buf = kzalloc(size, GFP_KERNEL); + if (!data_buf) { + ts_err("Failed to alloc memory"); + return -ENOMEM; + } + /* drv&sen shortcircut check */ + for (i = 0; i < short_ch_num; i++) { + ret = cd->hw_ops->read(cd, data_reg, data_buf, size); + if (ret) { + ts_err("Failed read Drv-to-Sen short rawdata"); + err = -EINVAL; + break; + } + + if (checksum_cmp(data_buf, size, CHECKSUM_MODE_U8_LE)) { + ts_err("Drv-to-Sen adc data checksum error"); + err = -EINVAL; + break; + } + + r_threshold = ts_test->r_drv_sen_threshold; + short_die_num = le16_to_cpup((__le16 *)&data_buf[0]); + if (short_die_num >= max_sen_num) { + ts_info("invalid short pad num:%d", short_die_num); + continue; + } + + /* TODO: j start position need recheck */ + self_capdata = le16_to_cpup((__le16 *)&data_buf[2]); + if (self_capdata == 0xffff || self_capdata == 0) { + ts_info("invalid self_capdata:0x%x", self_capdata); + continue; + } + + for (j = 0; j < max_drv_num; j++) { + adc_signal = + le16_to_cpup((__le16 *)&data_buf[4 + j * 2]); + + if (adc_signal < ts_test->short_threshold) + continue; + + short_r = + CAL_CHAN_TO_CHAN_RES(self_capdata, adc_signal); + if (short_r < r_threshold) { + master_pin_num = map_die2pin(short_die_num); + slave_pin_num = map_die2pin(j + max_sen_num); + if (master_pin_num == 0xFF || + slave_pin_num == 0xFF) { + ts_info("WARNNING invalid pin"); + continue; + } + goodix_save_short_res( + master_pin_num, slave_pin_num, short_r); + ts_err("short circut:R=%dK,R_Threshold=%dK", + short_r, r_threshold); + ts_err("%s%d--%s%d shortcircut", + (master_pin_num & DRV_CHANNEL_FLAG) + ? "DRV" + : "SEN", + (master_pin_num & ~DRV_CHANNEL_FLAG), + (slave_pin_num & DRV_CHANNEL_FLAG) + ? "DRV" + : "SEN", + (slave_pin_num & ~DRV_CHANNEL_FLAG)); + err = -EINVAL; + } + } + data_reg += size; + } + + kfree(data_buf); + return err; +} + +static int gdix_check_resistance_to_gnd(u16 adc_signal, u32 pos) +{ + long r = 0; + u16 r_th = 0, avdd_value = 0; + u16 chn_id_tmp = 0; + u8 pin_num = 0; + unsigned short short_type; + int max_drv_num = MAX_DRV_NUM; + int max_sen_num = MAX_SEN_NUM; + + avdd_value = ts_test->avdd_value; + short_type = adc_signal & 0x8000; + adc_signal &= ~0x8000; + if (adc_signal == 0) + adc_signal = 1; + + if (short_type == 0) { + /* short to GND */ + r = CAL_CHAN_TO_GND_RES(adc_signal); + } else { + /* short to VDD */ + r = CAL_CHAN_TO_AVDD_RES(adc_signal, avdd_value); + } + + if (pos < max_drv_num) + r_th = ts_test->r_drv_gnd_threshold; + else + r_th = ts_test->r_sen_gnd_threshold; + + chn_id_tmp = pos; + if (chn_id_tmp < max_drv_num) + chn_id_tmp += max_sen_num; + else + chn_id_tmp -= max_drv_num; + + if (r < r_th) { + pin_num = map_die2pin(chn_id_tmp); + goodix_save_short_res( + pin_num, short_type ? CHN_VDD : CHN_GND, r); + ts_err("%s%d shortcircut to %s,R=%ldK,R_Threshold=%dK", + (pin_num & DRV_CHANNEL_FLAG) ? "DRV" : "SEN", + (pin_num & ~DRV_CHANNEL_FLAG), + short_type ? "VDD" : "GND", r, r_th); + + return -EINVAL; + } + + return 0; +} + +static int gdix_check_gndvdd_shortcircut(void) +{ + int ret = 0, err = 0; + int size = 0, i = 0; + u16 adc_signal = 0; + u32 data_reg = DIFF_CODE_DATA_REG_NOT; + u8 *data_buf = NULL; + int max_drv_num = MAX_DRV_NUM; + int max_sen_num = MAX_SEN_NUM; + + size = (max_drv_num + max_sen_num) * 2 + 2; + data_buf = kzalloc(size, GFP_KERNEL); + if (!data_buf) { + ts_err("Failed to alloc memory"); + return -ENOMEM; + } + /* read diff code, diff code will be used to calculate + * resistance between channel and GND */ + ret = cd->hw_ops->read(cd, data_reg, data_buf, size); + if (ret < 0) { + ts_err("Failed read to-gnd rawdata"); + err = -EINVAL; + goto err_out; + } + + if (checksum_cmp(data_buf, size, CHECKSUM_MODE_U8_LE)) { + ts_err("diff code checksum error"); + err = -EINVAL; + goto err_out; + } + + for (i = 0; i < max_drv_num + max_sen_num; i++) { + adc_signal = le16_to_cpup((__le16 *)&data_buf[i * 2]); + ret = gdix_check_resistance_to_gnd(adc_signal, i); + if (ret != 0) { + ts_err("Resistance to-gnd/vdd short"); + err = ret; + } + } + +err_out: + kfree(data_buf); + return err; +} + +static int goodix_shortcircut_analysis(void) +{ + int ret; + int err = 0; + test_result_t test_result; + + ret = cd->hw_ops->read(cd, SHORT_TEST_RESULT_REG_NOT, + (u8 *)&test_result, sizeof(test_result)); + if (ret < 0) { + ts_err("Read TEST_RESULT_REG failed"); + return ret; + } + + if (checksum_cmp((u8 *)&test_result, sizeof(test_result), + CHECKSUM_MODE_U8_LE)) { + ts_err("shrot result checksum err"); + return -EINVAL; + } + + if (!(test_result.result & 0x0F)) { + ts_info(">>>>> No shortcircut"); + return 0; + } + ts_info("short flag 0x%02x, drv&drv:%d, sen&sen:%d, drv&sen:%d, drv/GNDVDD:%d, sen/GNDVDD:%d", + test_result.result, test_result.drv_drv_num, + test_result.sen_sen_num, test_result.drv_sen_num, + test_result.drv_gnd_avdd_num, test_result.sen_gnd_avdd_num); + + if (test_result.drv_drv_num) + err |= gdix_check_tx_tx_shortcircut(test_result.drv_drv_num); + if (test_result.sen_sen_num) + err |= gdix_check_rx_rx_shortcircut(test_result.sen_sen_num); + if (test_result.drv_sen_num) + err |= gdix_check_tx_rx_shortcircut(test_result.drv_sen_num); + if (test_result.drv_gnd_avdd_num || test_result.sen_gnd_avdd_num) + err |= gdix_check_gndvdd_shortcircut(); + + ts_info(">>>>> short check return 0x%x", err); + + return err; +} + +#define INSPECT_FW_SWITCH_CMD 0x85 +#define SHORT_TEST_RUN_FLAG 0xAA +#define SHORT_TEST_RUN_REG 0x10400 +static int goodix_short_test_prepare(void) +{ + struct goodix_ts_cmd tmp_cmd; + int ret; + int retry; + int resend = 3; + u8 status; + + ts_info("short test prepare IN"); + tmp_cmd.len = 4; + tmp_cmd.cmd = INSPECT_FW_SWITCH_CMD; + +resend_cmd: + ret = cd->hw_ops->send_cmd(cd, &tmp_cmd); + if (ret < 0) { + ts_err("send test mode failed"); + return ret; + } + + retry = 3; + while (retry--) { + msleep(40); + ret = cd->hw_ops->read(cd, SHORT_TEST_RUN_REG, &status, 1); + if (!ret && status == SHORT_TEST_RUN_FLAG) + return 0; + ts_info("short_mode_status=0x%02x ret=%d", status, ret); + } + + if (resend--) { + cd->hw_ops->reset(cd, 100); + goto resend_cmd; + } + + return -EINVAL; +} + +#define MAX_TEST_TIME_MS 15000 +#define DEFAULT_TEST_TIME_MS 7000 +#define SHORT_TEST_FINISH_FLAG 0x88 +static int goodix_shortcircut_test(void) +{ + int ret = 0; + int res; + int retry; + u16 test_time; + u8 status; + + ts_info("---------------------- short_test begin ----------------------"); + ret = goodix_short_test_prepare(); + if (ret < 0) { + ts_err("Failed enter short test mode"); + return ret; + } + + /* get short test time */ + ret = cd->hw_ops->read( + cd, SHORT_TEST_TIME_REG_NOT, (u8 *)&test_time, 2); + if (ret < 0) { + ts_err("Failed to get test_time, default %dms", + DEFAULT_TEST_TIME_MS); + test_time = DEFAULT_TEST_TIME_MS; + } else { + if (test_time > MAX_TEST_TIME_MS) { + ts_info("test time too long %d > %d", test_time, + MAX_TEST_TIME_MS); + test_time = MAX_TEST_TIME_MS; + } + ts_info("get test time %dms", test_time); + } + + /* start short test */ + status = 0; + cd->hw_ops->write(cd, SHORT_TEST_RUN_REG, &status, 1); + + /* wait short test finish */ + msleep(test_time); + retry = 50; + while (retry--) { + ret = cd->hw_ops->read( + cd, SHORT_TEST_STATUS_REG_NOT, &status, 1); + if (!ret && status == SHORT_TEST_FINISH_FLAG) + break; + msleep(50); + } + if (retry < 0) { + ts_err("short test failed, status:0x%02x", status); + return -EINVAL; + } + + /* start analysis short result */ + ts_info("short_test finished, start analysis"); + res = goodix_shortcircut_analysis(); + if (res == 0) { + ts_test->result[GTP_SHORT_TEST] = TEST_OK; + ret = 0; + } + + return ret; +} typedef struct __attribute__((packed)) { uint32_t checksum; @@ -167,6 +864,7 @@ static void seq_stop(struct seq_file *s, void *v) kfree(rbuf); rbuf = NULL; index = 0; + release_test_resource(); } } @@ -186,78 +884,936 @@ static int driver_test_release(struct inode *inode, struct file *file) return seq_release(inode, file); } -static int goodix_noise_test(uint16_t frame, int threshold) +static void goodix_save_header(void) +{ + int i; + bool total_result = true; + + index = sprintf( + &rbuf[index], "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"); + index += sprintf(&rbuf[index], "<TESTLOG>\n"); + index += sprintf(&rbuf[index], "<Header>\n"); + /* sava test result */ + for (i = 0; i < MAX_TEST_ITEMS; i++) { + if (ts_test->item[i] && ts_test->result[i] == TEST_NG) + total_result = false; + } + if (total_result == false) { + index += sprintf(&rbuf[index], "<Result>NG</Result>\n"); + } else { + index += sprintf(&rbuf[index], "<Result>OK</Result>\n"); + } + + index += sprintf(&rbuf[index], "<DeviceType>GT%s</DeviceType>\n", + cd->fw_version.patch_pid); + index += sprintf(&rbuf[index], "<SensorId>%d</SensorId>\n", + cd->fw_version.sensor_id); + index += sprintf(&rbuf[index], "</Header>\n"); + + index += sprintf(&rbuf[index], "<ItemList>\n"); + if (ts_test->item[GTP_CAP_TEST]) { + if (ts_test->result[GTP_CAP_TEST] == TEST_NG) { + index += sprintf(&rbuf[index], + "<Item name=\"Rawdata MAX/MIN Test\" result=\"NG\"/>\n"); + } else { + index += sprintf(&rbuf[index], + "<Item name=\"Rawdata MAX/MIN Test\" result=\"OK\"/>\n"); + } + if (ts_test->result[GTP_DELTA_TEST] == TEST_NG) { + index += sprintf(&rbuf[index], + "<Item name=\"Rawdata Adjcent Deviation Test\" result=\"NG\"/>\n"); + } else { + index += sprintf(&rbuf[index], + "<Item name=\"Rawdata Adjcent Deviation Test\" result=\"OK\"/>\n"); + } + } + + if (ts_test->item[GTP_NOISE_TEST]) { + if (ts_test->result[GTP_NOISE_TEST] == TEST_NG) { + index += sprintf(&rbuf[index], + "<Item name=\"Diffdata Jitter Test\" result=\"NG\"/>\n"); + } else { + index += sprintf(&rbuf[index], + "<Item name=\"Diffdata Jitter Test\" result=\"OK\"/>\n"); + } + } + + if (ts_test->item[GTP_SELFCAP_TEST]) { + if (ts_test->result[GTP_SELFCAP_TEST] == TEST_NG) { + index += sprintf(&rbuf[index], + "<Item name=\"Self Rawdata Upper Limit Test\" result=\"NG\"/>\n"); + } else { + index += sprintf(&rbuf[index], + "<Item name=\"Self Rawdata Upper Limit Test\" result=\"OK\"/>\n"); + } + } + + if (ts_test->item[GTP_SHORT_TEST]) { + if (ts_test->result[GTP_SHORT_TEST] == TEST_NG) { + index += sprintf(&rbuf[index], + "<Item name=\"Short Test\" result=\"NG\"/>\n"); + } else { + index += sprintf(&rbuf[index], + "<Item name=\"Short Test\" result=\"OK\"/>\n"); + } + } + index += sprintf(&rbuf[index], "</ItemList>\n"); +} + +static void goodix_save_limits(void) +{ + int tx = cd->ic_info.parm.drv_num; + int rx = cd->ic_info.parm.sen_num; + int i; + int chn1; + int chn2; + int r; + + index += sprintf(&rbuf[index], "<TestItems>\n"); + + /* save short result */ + if (ts_test->item[GTP_SHORT_TEST]) { + index += sprintf(&rbuf[index], "<Item name=\"Short Test\">\n"); + index += sprintf(&rbuf[index], "<ShortNum>%d</ShortNum>\n", + ts_test->short_res.short_num); + for (i = 0; i < ts_test->short_res.short_num; i++) { + chn1 = ts_test->short_res.short_msg[4 * i]; + chn2 = ts_test->short_res.short_msg[4 * i + 1]; + r = (ts_test->short_res.short_msg[4 * i + 2] << 8) + + ts_test->short_res.short_msg[4 * i + 3]; + if (chn1 == CHN_VDD) + index += sprintf(&rbuf[index], + "<ShortMess Chn1=\"VDD\" "); + else if (chn1 == CHN_GND) + index += sprintf(&rbuf[index], + "<ShortMess Chn1=\"GND\" "); + else if (chn1 & DRV_CHANNEL_FLAG) + index += sprintf(&rbuf[index], + "<ShortMess Chn1=\"Tx%d\" ", + chn1 & 0x7f); + else + index += sprintf(&rbuf[index], + "<ShortMess Chn1=\"Rx%d\" ", + chn1 & 0x7f); + if (chn2 == CHN_VDD) + index += sprintf(&rbuf[index], + "Chn2=\"VDD\" ShortResistor= \"%dKom\"/>\n", + r); + else if (chn2 == CHN_GND) + index += sprintf(&rbuf[index], + "Chn2=\"GND\" ShortResistor= \"%dKom\"/>\n", + r); + else if (chn2 & DRV_CHANNEL_FLAG) + index += sprintf(&rbuf[index], + "Chn2=\"Tx%d\" ShortResistor= \"%dKom\"/>\n", + chn2 & 0x7f, r); + else + index += sprintf(&rbuf[index], + "Chn2=\"Rx%d\" ShortResistor= \"%dKom\"/>\n", + chn2 & 0x7f, r); + } + index += sprintf(&rbuf[index], "</Item>\n"); + } + + /* save open limits */ + if (ts_test->item[GTP_CAP_TEST]) { + index += sprintf( + &rbuf[index], "<Item name=\"Rawdata Test Sets\">\n"); + index += sprintf(&rbuf[index], + "<TotalFrameCnt>%d</TotalFrameCnt>\n", + ts_test->raw_data_cnt); + /* rawdata max limit */ + index += sprintf(&rbuf[index], "<MaxRawLimit>\n"); + for (i = 0; i < tx * rx; i++) { + index += sprintf( + &rbuf[index], "%d,", ts_test->max_limits[i]); + if ((i + 1) % tx == 0) + index += sprintf(&rbuf[index], "\n"); + } + index += sprintf(&rbuf[index], "</MaxRawLimit>\n"); + /* rawdata min limit */ + index += sprintf(&rbuf[index], "<MinRawLimit>\n"); + for (i = 0; i < tx * rx; i++) { + index += sprintf( + &rbuf[index], "%d,", ts_test->min_limits[i]); + if ((i + 1) % tx == 0) + index += sprintf(&rbuf[index], "\n"); + } + index += sprintf(&rbuf[index], "</MinRawLimit>\n"); + /* Max Accord limit */ + index += sprintf(&rbuf[index], "<MaxAccordLimit>\n"); + for (i = 0; i < tx * rx; i++) { + index += sprintf(&rbuf[index], "%d,", + ts_test->deviation_limits[i]); + if ((i + 1) % tx == 0) + index += sprintf(&rbuf[index], "\n"); + } + index += sprintf(&rbuf[index], "</MaxAccordLimit>\n"); + index += sprintf(&rbuf[index], "</Item>\n"); + } + + /* save noise limit */ + if (ts_test->item[GTP_NOISE_TEST]) { + index += sprintf( + &rbuf[index], "<Item name=\"Diffdata Test Sets\">\n"); + index += sprintf(&rbuf[index], + "<TotalFrameCnt>%d</TotalFrameCnt>\n", + ts_test->noise_data_cnt); + index += sprintf(&rbuf[index], + "<MaxJitterLimit>%d</MaxJitterLimit>\n", + ts_test->noise_threshold); + index += sprintf(&rbuf[index], "</Item>\n"); + } + + /* save self rawdata limit */ + if (ts_test->item[GTP_SELFCAP_TEST]) { + index += sprintf(&rbuf[index], + "<Item name=\"Self Rawdata Test Sets\">\n"); + index += sprintf( + &rbuf[index], "<TotalFrameCnt>1</TotalFrameCnt>\n"); + index += sprintf(&rbuf[index], "<MaxRawLimit>\n"); + for (i = 0; i < tx + rx; i++) { + index += sprintf(&rbuf[index], "%d,", + ts_test->self_max_limits[i]); + if ((i + 1) % tx == 0) + index += sprintf(&rbuf[index], "\n"); + } + if ((tx + rx) % tx != 0) + index += sprintf(&rbuf[index], "\n"); + index += sprintf(&rbuf[index], "</MaxRawLimit>\n"); + index += sprintf(&rbuf[index], "<MinRawLimit>\n"); + for (i = 0; i < tx + rx; i++) { + index += sprintf(&rbuf[index], "%d,", + ts_test->self_min_limits[i]); + if ((i + 1) % tx == 0) + index += sprintf(&rbuf[index], "\n"); + } + if ((tx + rx) % tx != 0) + index += sprintf(&rbuf[index], "\n"); + index += sprintf(&rbuf[index], "</MinRawLimit>\n"); + index += sprintf(&rbuf[index], "</Item>\n"); + } + + index += sprintf(&rbuf[index], "</TestItems>\n"); +} + +static void goodix_data_cal(s16 *data, size_t data_size, s16 *stat_result) +{ + int i = 0; + s16 avg = 0; + s16 min = 0; + s16 max = 0; + long long sum = 0; + + min = data[0]; + max = data[0]; + for (i = 0; i < data_size; i++) { + sum += data[i]; + if (max < data[i]) + max = data[i]; + if (min > data[i]) + min = data[i]; + } + avg = div_s64(sum, data_size); + stat_result[0] = avg; + stat_result[1] = max; + stat_result[2] = min; +} + +static void goodix_save_data(void) { + int tx = cd->ic_info.parm.drv_num; + int rx = cd->ic_info.parm.sen_num; + s16 stat_result[3]; + int i, j; + + index += sprintf(&rbuf[index], "<DataRecord>\n"); + + /* save rawdata */ + if (ts_test->item[GTP_CAP_TEST]) { + index += sprintf(&rbuf[index], "<RawDataRecord>\n"); + for (i = 0; i < ts_test->raw_data_cnt; i++) { + goodix_data_cal( + ts_test->rawdata[i].data, tx * rx, stat_result); + index += sprintf(&rbuf[index], + "<DataContent No.=\"%d\" DataCount=\"%d\" Maximum=\"%d\" Minimum=\"%d\" Average=\"%d\">\n", + i, tx * rx, stat_result[1], stat_result[2], + stat_result[0]); + for (j = 0; j < tx * rx; j++) { + index += sprintf(&rbuf[index], "%d,", + ts_test->rawdata[i].data[j]); + if ((j + 1) % tx == 0) + index += sprintf(&rbuf[index], "\n"); + } + index += sprintf(&rbuf[index], "</DataContent>\n"); + goodix_data_cal(ts_test->deltadata[i].data, tx * rx, + stat_result); + index += sprintf(&rbuf[index], + "<RawAccord No.=\"%d\" DataCount=\"%d\" Maximum=\"%d\" Minimum=\"%d\" Average=\"%d\">\n", + i, tx * rx, stat_result[1], stat_result[2], + stat_result[0]); + for (j = 0; j < tx * rx; j++) { + index += sprintf(&rbuf[index], "%d,", + ts_test->deltadata[i].data[j]); + if ((j + 1) % tx == 0) + index += sprintf(&rbuf[index], "\n"); + } + index += sprintf(&rbuf[index], "</RawAccord>\n"); + } + index += sprintf(&rbuf[index], "</RawDataRecord>\n"); + } + + /* save noisedata */ + if (ts_test->item[GTP_NOISE_TEST]) { + index += sprintf(&rbuf[index], "<DiffDataRecord>\n"); + for (i = 0; i < ts_test->noise_data_cnt; i++) { + goodix_data_cal(ts_test->noisedata[i].data, tx * rx, + stat_result); + index += sprintf(&rbuf[index], + "<DataContent No.=\"%d\" DataCount=\"%d\" Maximum=\"%d\" Minimum=\"%d\" Average=\"%d\">\n", + i, tx * rx, stat_result[1], stat_result[2], + stat_result[0]); + for (j = 0; j < tx * rx; j++) { + index += sprintf(&rbuf[index], "%d,", + ts_test->noisedata[i].data[j]); + if ((j + 1) % tx == 0) + index += sprintf(&rbuf[index], "\n"); + } + index += sprintf(&rbuf[index], "</DataContent>\n"); + } + index += sprintf(&rbuf[index], "</DiffDataRecord>\n"); + } + + /* save self rawdata */ + if (ts_test->item[GTP_SELFCAP_TEST]) { + index += sprintf(&rbuf[index], "<selfDataRecord>\n"); + goodix_data_cal( + ts_test->selfrawdata.data, tx + rx, stat_result); + index += sprintf(&rbuf[index], + "<DataContent No.=\"0\" DataCount=\"%d\" Maximum=\"%d\" Minimum=\"%d\" Average=\"%d\">\n", + tx + rx, stat_result[1], stat_result[2], + stat_result[0]); + for (i = 0; i < tx + rx; i++) { + index += sprintf(&rbuf[index], "%d,", + ts_test->selfrawdata.data[i]); + if ((i + 1) % tx == 0) + index += sprintf(&rbuf[index], "\n"); + } + if ((tx + rx) % tx != 0) + index += sprintf(&rbuf[index], "\n"); + index += sprintf(&rbuf[index], "</DataContent>\n"); + index += sprintf(&rbuf[index], "</selfDataRecord>\n"); + } + + index += sprintf(&rbuf[index], "</DataRecord>\n"); +} + +static void goodix_save_tail(void) +{ + index += sprintf(&rbuf[index], "</TESTLOG>\n"); +} + +static void goodix_save_test_result(void) +{ + goodix_save_header(); + goodix_save_limits(); + goodix_save_data(); + goodix_save_tail(); +} + +static void goto_next_line(char **ptr) +{ + do { + *ptr = *ptr + 1; + } while (**ptr != '\n' && **ptr != '\0'); + if (**ptr == '\0') { + return; + } + *ptr = *ptr + 1; +} + +static void copy_this_line(char *dest, char *src) +{ + char *copy_from; + char *copy_to; + + copy_from = src; + copy_to = dest; + do { + *copy_to = *copy_from; + copy_from++; + copy_to++; + } while ((*copy_from != '\n') && (*copy_from != '\r') && + (*copy_from != '\0')); + *copy_to = '\0'; +} + +static int getrid_space(s8 *data, s32 len) +{ + u8 *buf = NULL; + s32 i; + u32 count = 0; + + buf = (char *)kzalloc(len + 5, GFP_KERNEL); + if (buf == NULL) { + ts_err("get space kzalloc error"); + return -ESRCH; + } + + for (i = 0; i < len; i++) { + if (data[i] == ' ' || data[i] == '\r' || data[i] == '\n') { + continue; + } + buf[count++] = data[i]; + } + + buf[count++] = '\0'; + + memcpy(data, buf, count); + kfree(buf); + + return count; +} + +static int parse_valid_data( + char *buf_start, loff_t buf_size, char *ptr, s16 *data, s32 rows) +{ + int i = 0; + int j = 0; + char *token = NULL; + char *tok_ptr = NULL; + char *row_data = NULL; + long temp_val; + + if (!ptr || !data) + return -EINVAL; + + row_data = (char *)kzalloc(MAX_LINE_LEN, GFP_KERNEL); + if (!row_data) { + ts_err("alloc index %d failed.", MAX_LINE_LEN); + return -ENOMEM; + } + + for (i = 0; i < rows; i++) { + memset(row_data, 0, MAX_LINE_LEN); + copy_this_line(row_data, ptr); + getrid_space(row_data, strlen(row_data)); + tok_ptr = row_data; + while ((token = strsep(&tok_ptr, ","))) { + if (strlen(token) == 0) + continue; + if (kstrtol(token, 0, &temp_val)) { + kfree(row_data); + return -EINVAL; + } + data[j++] = (s16)temp_val; + } + if (i == rows - 1) + break; + goto_next_line(&ptr); // next row + if (!ptr || (0 == strlen(ptr)) || + (ptr >= (buf_start + buf_size))) { + ts_info("invalid ptr, return"); + kfree(row_data); + row_data = NULL; + return -EPERM; + } + } + kfree(row_data); + return j; +} + +static int parse_csvfile( + char *buf, size_t size, char *target_name, s16 *data, s32 rows, s32 col) +{ + char *ptr = NULL; + + if (!data || !buf) + return -EIO; + + ptr = buf; + ptr = strstr(ptr, target_name); + if (!ptr) { + ts_info("load %s failed 1, maybe not this item", target_name); + return -EINTR; + } + + goto_next_line(&ptr); + if (!ptr || (0 == strlen(ptr))) { + ts_err("load %s failed 2!", target_name); + return -EIO; + } + + return parse_valid_data(buf, size, ptr, data, rows); +} + +static int goodix_obtain_testlimits(void) +{ + const struct firmware *firmware = NULL; + struct device *dev = &cd->pdev->dev; + int tx = cd->ic_info.parm.drv_num; + int rx = cd->ic_info.parm.sen_num; + char limit_file[100] = { 0 }; + char *temp_buf = NULL; + s16 data_buf[7]; + int ret; + + sprintf(limit_file, "goodix_test_limits_%d.csv", + cd->fw_version.sensor_id); + ts_info("limit_file_name:%s", limit_file); + + ret = request_firmware(&firmware, limit_file, dev); + if (ret < 0) { + ts_err("limits file [%s] not available", limit_file); + return -EINVAL; + } + if (firmware->size <= 0) { + ts_err("request_firmware, limits param length error,len:%zu", + firmware->size); + ret = -EINVAL; + goto exit_free; + } + temp_buf = kzalloc(firmware->size + 1, GFP_KERNEL); + if (!temp_buf) { + ret = -ENOMEM; + goto exit_free; + } + memcpy(temp_buf, firmware->data, firmware->size); + + if (ts_test->item[GTP_CAP_TEST]) { + /* obtain mutual_raw min */ + ret = parse_csvfile(temp_buf, firmware->size, + CSV_TP_SPECIAL_RAW_MIN, ts_test->min_limits, rx, tx); + if (ret < 0) { + ts_err("Failed get min_limits"); + goto exit_free; + } + /* obtain mutual_raw max */ + ret = parse_csvfile(temp_buf, firmware->size, + CSV_TP_SPECIAL_RAW_MAX, ts_test->max_limits, rx, tx); + if (ret < 0) { + ts_err("Failed get max_limits"); + goto exit_free; + } + /* obtain delta limit */ + ret = parse_csvfile(temp_buf, firmware->size, + CSV_TP_SPECIAL_RAW_DELTA, ts_test->deviation_limits, rx, + tx); + if (ret < 0) { + ts_err("Failed get delta limit"); + goto exit_free; + } + } + + if (ts_test->item[GTP_SELFCAP_TEST]) { + /* obtain self_raw min */ + ret = parse_csvfile(temp_buf, firmware->size, + CSV_TP_SPECIAL_SELFRAW_MIN, ts_test->self_min_limits, 1, + tx + rx); + if (ret < 0) { + ts_err("Failed get self_min_limits"); + goto exit_free; + } + /* obtain self_raw max */ + ret = parse_csvfile(temp_buf, firmware->size, + CSV_TP_SPECIAL_SELFRAW_MAX, ts_test->self_max_limits, 1, + tx + rx); + if (ret < 0) { + ts_err("Failed get self_min_limits"); + goto exit_free; + } + } + + if (ts_test->item[GTP_NOISE_TEST]) { + /* obtain noise_threshold */ + ret = parse_csvfile(temp_buf, firmware->size, + CSV_TP_NOISE_LIMIT, &ts_test->noise_threshold, 1, 1); + if (ret < 0) { + ts_err("Failed get noise limits"); + goto exit_free; + } + } + + if (ts_test->item[GTP_SHORT_TEST]) { + /* obtain short_params */ + ret = parse_csvfile(temp_buf, firmware->size, + CSV_TP_SHORT_THRESHOLD, data_buf, 1, 7); + if (ret < 0) { + ts_err("Failed get short circuit limits"); + goto exit_free; + } + ts_test->short_threshold = data_buf[0]; + ts_test->r_drv_drv_threshold = data_buf[1]; + ts_test->r_drv_sen_threshold = data_buf[2]; + ts_test->r_sen_sen_threshold = data_buf[3]; + ts_test->r_drv_gnd_threshold = data_buf[4]; + ts_test->r_sen_gnd_threshold = data_buf[5]; + ts_test->avdd_value = data_buf[6]; + } + +exit_free: + kfree(temp_buf); + if (firmware) + release_firmware(firmware); + return ret; +} + +static int goodix_delta_test(void) +{ + int i, j; + int max_val; + int raw; + int temp; + int tx = cd->ic_info.parm.drv_num; + int rx = cd->ic_info.parm.sen_num; + u32 data_size = tx * rx; + int ret = 0; + + for (i = 0; i < ts_test->raw_data_cnt; i++) { + for (j = 0; j < data_size; j++) { + raw = ts_test->rawdata[i].data[j]; + max_val = 0; + /* calcu delta with above node */ + if (j - tx >= 0) { + temp = ts_test->rawdata[i].data[j - tx]; + temp = ABS(temp - raw); + max_val = MAX(max_val, temp); + } + /* calcu delta with bellow node */ + if (j + tx < data_size) { + temp = ts_test->rawdata[i].data[j + tx]; + temp = ABS(temp - raw); + max_val = MAX(max_val, temp); + } + /* calcu delta with left node */ + if (j % tx) { + temp = ts_test->rawdata[i].data[j - 1]; + temp = ABS(temp - raw); + max_val = MAX(max_val, temp); + } + /* calcu delta with right node */ + if ((j + 1) % tx) { + temp = ts_test->rawdata[i].data[j + 1]; + temp = ABS(temp - raw); + max_val = MAX(max_val, temp); + } + temp = max_val * 1000 / raw; + ts_test->deltadata[i].data[j] = temp; + if (temp > ts_test->deviation_limits[j]) { + ts_err("delta_data[%d] > limits[%d]", temp, + ts_test->deviation_limits[j]); + ret = -EINVAL; + } + } + } + + return ret; +} + +static int goodix_open_test(void) +{ + unsigned char tmp_buf[GOODIX_MAX_FRAMEDATA_LEN]; struct goodix_ts_cmd temp_cmd; int tx = cd->ic_info.parm.drv_num; int rx = cd->ic_info.parm.sen_num; - s16 buf[17 * 35]; + u32 sync_addr = cd->ic_info.misc.frame_data_addr; u32 raw_addr; - int retry = 50; - u8 status; int ret; - int i; int err_cnt = 0; + int i, j; + s16 tmp_val; + u16 tmp_freq; + u8 val; + int retry; raw_addr = cd->ic_info.misc.frame_data_addr + cd->ic_info.misc.frame_data_head_len + cd->ic_info.misc.fw_attr_len + cd->ic_info.misc.fw_log_len + 8; - temp_cmd.len = 0x07; + /* open test prepare */ + temp_cmd.cmd = 0x90; + temp_cmd.data[0] = 0x84; + temp_cmd.len = 5; + ret = cd->hw_ops->send_cmd(cd, &temp_cmd); + if (ret < 0) { + ts_err("send rawdata cmd failed"); + return ret; + } + + /* switch freq */ + if (ts_test->freq > 0) { + ts_info("set freq %d", ts_test->freq); + tmp_freq = ts_test->freq / 61; + temp_cmd.len = 6; + temp_cmd.cmd = 0xB1; + temp_cmd.data[0] = tmp_freq & 0xFF; + temp_cmd.data[1] = (tmp_freq >> 8) & 0xFF; + ret = cd->hw_ops->send_cmd(cd, &temp_cmd); + if (ret < 0) { + ts_err("set freq %d failed", ts_test->freq); + return ret; + } + } + + /* discard the first few frames */ + for (i = 0; i < 3; i++) { + val = 0; + cd->hw_ops->write(cd, sync_addr, &val, 1); + usleep_range(20000, 21000); + } + + /* read rawdata */ + for (i = 0; i < ts_test->raw_data_cnt; i++) { + val = 0; + cd->hw_ops->write(cd, sync_addr, &val, 1); + retry = 20; + while (retry--) { + usleep_range(5000, 5100); + cd->hw_ops->read(cd, sync_addr, &val, 1); + if (val & 0x80) + break; + } + if (retry < 0) { + ts_err("rawdata is not ready val:0x%02x i:%d, exit", + val, i); + ret = -EINVAL; + goto exit; + } + + cd->hw_ops->read(cd, raw_addr, tmp_buf, tx * rx * 2); + goodix_rotate_abcd2cbad(tx, rx, (s16 *)tmp_buf); + memcpy((u8 *)ts_test->rawdata[i].data, tmp_buf, tx * rx * 2); + } + + /* analysis results */ + ts_test->result[GTP_CAP_TEST] = TEST_OK; + for (i = 0; i < ts_test->raw_data_cnt; i++) { + for (j = 0; j < tx * rx; j++) { + tmp_val = ts_test->rawdata[i].data[j]; + if (tmp_val > ts_test->max_limits[j] || + tmp_val < ts_test->min_limits[j]) { + ts_err("rawdata[%d] out of range[%d %d]", + tmp_val, ts_test->min_limits[j], + ts_test->max_limits[j]); + err_cnt++; + } + } + } + + if (err_cnt > 0) { + ret = -EINVAL; + ts_test->result[GTP_CAP_TEST] = TEST_NG; + } + + if (goodix_delta_test() == 0) + ts_test->result[GTP_DELTA_TEST] = TEST_OK; + +exit: + return ret; +} + +static int goodix_self_open_test(void) +{ + unsigned char tmp_buf[GOODIX_MAX_FRAMEDATA_LEN]; + struct goodix_ts_cmd temp_cmd; + int tx = cd->ic_info.parm.drv_num; + int rx = cd->ic_info.parm.sen_num; + u32 sync_addr = cd->ic_info.misc.frame_data_addr; + u32 raw_addr; + int ret; + int j; + s16 tmp_val; + u8 val; + int retry; + + raw_addr = cd->ic_info.misc.frame_data_addr + + cd->ic_info.misc.frame_data_head_len + + cd->ic_info.misc.fw_attr_len + cd->ic_info.misc.fw_log_len + + cd->ic_info.misc.mutual_struct_len + 10; + + /* test prepare */ temp_cmd.cmd = 0x90; - temp_cmd.data[0] = 0x86; - temp_cmd.data[1] = frame & 0xFF; - temp_cmd.data[2] = (frame >> 8) & 0xFF; + temp_cmd.data[0] = 0x84; + temp_cmd.len = 5; ret = cd->hw_ops->send_cmd(cd, &temp_cmd); if (ret < 0) { - ts_err("send noise cmd failed"); - goto fail; + ts_err("send rawdata cmd failed"); + return ret; } - msleep(frame * 10); + /* discard the first few frames */ + for (j = 0; j < 3; j++) { + val = 0; + cd->hw_ops->write(cd, sync_addr, &val, 1); + usleep_range(20000, 21000); + } + + /* read self rawdata */ + val = 0; + cd->hw_ops->write(cd, sync_addr, &val, 1); + retry = 20; while (retry--) { - ret = cd->hw_ops->read( - cd, cd->ic_info.misc.cmd_addr, &status, 1); - if (ret == 0 && status == 0x80) + usleep_range(5000, 5100); + cd->hw_ops->read(cd, sync_addr, &val, 1); + if (val & 0x80) break; - msleep(50); } if (retry < 0) { - ts_err("noise data is not ready"); - goto fail; + ts_err("self rawdata is not ready val:0x%02x, exit", val); + ret = -EINVAL; + goto exit; + } + + cd->hw_ops->read(cd, raw_addr, tmp_buf, (tx + rx) * 2); + memcpy((u8 *)ts_test->selfrawdata.data, tmp_buf, (tx + rx) * 2); + + /* analysis results */ + ts_test->result[GTP_SELFCAP_TEST] = TEST_OK; + for (j = 0; j < tx + rx; j++) { + tmp_val = ts_test->selfrawdata.data[j]; + if (tmp_val > ts_test->self_max_limits[j] || + tmp_val < ts_test->self_min_limits[j]) { + ts_err("self_rawdata[%d] out of range[%d %d]", tmp_val, + ts_test->self_min_limits[j], + ts_test->self_max_limits[j]); + ts_test->result[GTP_SELFCAP_TEST] = TEST_NG; + ret = -EINVAL; + } } - msleep(50); - ret = cd->hw_ops->read(cd, raw_addr, (u8 *)buf, tx * rx * 2); +exit: + return ret; +} + +static int goodix_noise_test(void) +{ + unsigned char tmp_buf[GOODIX_MAX_FRAMEDATA_LEN]; + struct goodix_ts_cmd temp_cmd; + int tx = cd->ic_info.parm.drv_num; + int rx = cd->ic_info.parm.sen_num; + u32 sync_addr = cd->ic_info.misc.frame_data_addr; + u32 raw_addr; + int ret; + int i, j; + s16 tmp_val; + u8 val; + int retry; + + raw_addr = cd->ic_info.misc.frame_data_addr + + cd->ic_info.misc.frame_data_head_len + + cd->ic_info.misc.fw_attr_len + cd->ic_info.misc.fw_log_len + + 8; + + /* open test prepare */ + temp_cmd.cmd = 0x90; + temp_cmd.data[0] = 0x82; + temp_cmd.len = 5; + ret = cd->hw_ops->send_cmd(cd, &temp_cmd); if (ret < 0) { - ts_err("read noise data faield"); - goto fail; + ts_err("send rawdata cmd failed"); + return ret; } - goodix_rotate_abcd2cbad(tx, rx, buf); - for (i = 0; i < tx * rx; i++) { - if (ABS(buf[i]) > threshold) - err_cnt++; - index += sprintf(&rbuf[index], "%3d,", buf[i]); - if ((i + 1) % tx == 0) - index += sprintf(&rbuf[index], "\n"); + /* discard the first few frames */ + for (i = 0; i < 3; i++) { + val = 0; + cd->hw_ops->write(cd, sync_addr, &val, 1); + usleep_range(20000, 21000); } - if (err_cnt > 0) { - ts_err("noise test fail"); - goto fail; + /* read noisedata */ + for (i = 0; i < ts_test->noise_data_cnt; i++) { + val = 0; + cd->hw_ops->write(cd, sync_addr, &val, 1); + retry = 20; + while (retry--) { + usleep_range(5000, 5100); + cd->hw_ops->read(cd, sync_addr, &val, 1); + if (val & 0x80) + break; + } + if (retry < 0) { + ts_err("noisedata is not ready val:0x%02x i:%d, exit", + val, i); + ret = -EINVAL; + goto exit; + } + + cd->hw_ops->read(cd, raw_addr, tmp_buf, tx * rx * 2); + goodix_rotate_abcd2cbad(tx, rx, (s16 *)tmp_buf); + memcpy((u8 *)ts_test->noisedata[i].data, tmp_buf, tx * rx * 2); } - ts_info("noise test pass"); - index += sprintf(&rbuf[index], "noise_test-[PASS]\n"); - return 0; + /* analysis results */ + ts_test->result[GTP_NOISE_TEST] = TEST_OK; + for (i = 0; i < ts_test->noise_data_cnt; i++) { + for (j = 0; j < tx * rx; j++) { + tmp_val = ts_test->noisedata[i].data[j]; + tmp_val = ABS(tmp_val); + if (tmp_val > ts_test->noise_threshold) { + ts_err("noise data[%d] > noise threshold[%d]", + tmp_val, ts_test->noise_threshold); + ts_test->result[GTP_NOISE_TEST] = TEST_NG; + ret = -EINVAL; + } + } + } -fail: - index += sprintf(&rbuf[index], "noise_test-[FAIL]\n"); +exit: return ret; } +static int goodix_auto_test(void) +{ + struct goodix_ts_cmd temp_cmd; + int ret; + + ret = goodix_obtain_testlimits(); + if (ret < 0) { + ts_err("obtain open test limits failed"); + return ret; + } + + cd->hw_ops->irq_enable(cd, false); + goodix_ts_blocking_notify(NOTIFY_ESD_OFF, NULL); + + temp_cmd.len = 5; + temp_cmd.cmd = 0x64; + temp_cmd.data[0] = 1; + + if (ts_test->item[GTP_CAP_TEST]) { + ret = cd->hw_ops->send_cmd(cd, &temp_cmd); + if (ret < 0) + ts_err("enter test mode failed"); + goodix_open_test(); + cd->hw_ops->reset(cd, 100); + } + + if (ts_test->item[GTP_NOISE_TEST]) { + ret = cd->hw_ops->send_cmd(cd, &temp_cmd); + if (ret < 0) + ts_err("enter test mode failed"); + goodix_noise_test(); + cd->hw_ops->reset(cd, 100); + } + + if (ts_test->item[GTP_SELFCAP_TEST]) { + goodix_self_open_test(); + cd->hw_ops->reset(cd, 100); + } + + if (ts_test->item[GTP_SHORT_TEST]) { + goodix_shortcircut_test(); + cd->hw_ops->reset(cd, 100); + } + + cd->hw_ops->irq_enable(cd, true); + goodix_ts_blocking_notify(NOTIFY_ESD_ON, NULL); + goodix_save_test_result(); + return 0; +} + static int get_cap_data(uint8_t *type) { struct goodix_ts_cmd temp_cmd; @@ -409,24 +1965,51 @@ static void goodix_set_scan_mode(u8 val) { struct goodix_ts_cmd temp_cmd; + if (val == 0) { + ts_info("set scan mode to default"); + index = sprintf(rbuf, "set scan mode to default\n"); + } else if (val == 1) { + ts_info("set scan mode to idle"); + index = sprintf(rbuf, "set scan mode to idle\n"); + } else { + ts_info("set scan mode to active"); + index = sprintf(rbuf, "set scan mode to active\n"); + } + temp_cmd.len = 5; temp_cmd.cmd = 0x9F; temp_cmd.data[0] = val; cd->hw_ops->send_cmd(cd, &temp_cmd); } +static void goodix_set_continue_mode(u8 val) +{ + struct goodix_ts_cmd temp_cmd; + + if (val == 0) { + ts_info("enable continue report"); + index = sprintf(rbuf, "enable continue report\n"); + } else { + ts_info("disable continue report"); + index = sprintf(rbuf, "disable continue report\n"); + } + + temp_cmd.len = 5; + temp_cmd.cmd = 0xC3; + temp_cmd.data[0] = val; + cd->hw_ops->send_cmd(cd, &temp_cmd); +} + static ssize_t driver_test_write( struct file *file, const char __user *buf, size_t count, loff_t *pos) { struct goodix_fw_version fw_ver; struct goodix_ic_info ic_info; - struct ts_rawdata_info *info = NULL; char *p = wbuf; char *token; int ret; - int frames; - int limit; int cmd_val; + int cmd_val2; u8 id; if (count > SHORT_SIZE) { @@ -442,10 +2025,11 @@ static ssize_t driver_test_write( kfree(rbuf); rbuf = NULL; index = 0; + release_test_resource(); ts_info("input cmd[%s]", p); - if (strstr(p, CMD_FW_UPDATE)) { + if (!strncmp(p, CMD_FW_UPDATE, strlen(CMD_FW_UPDATE))) { rbuf = kzalloc(SHORT_SIZE, GFP_KERNEL); ret = goodix_do_fw_update( NULL, UPDATE_MODE_BLOCK | UPDATE_MODE_FORCE | @@ -458,7 +2042,7 @@ static ssize_t driver_test_write( goto exit; } - if (strstr(p, CMD_GET_VERSION)) { + if (!strncmp(p, CMD_GET_VERSION, strlen(CMD_GET_VERSION))) { rbuf = kzalloc(SHORT_SIZE, GFP_KERNEL); cd->hw_ops->read_version(cd, &fw_ver); cd->hw_ops->get_ic_info(cd, &ic_info); @@ -469,7 +2053,7 @@ static ssize_t driver_test_write( goto exit; } - if (strstr(p, CMD_GET_RAWDATA)) { + if (!strncmp(p, CMD_GET_RAWDATA, strlen(CMD_GET_RAWDATA))) { rbuf = kzalloc(LARGE_SIZE, GFP_KERNEL); ret = get_cap_data(CMD_GET_RAWDATA); if (ret < 0) { @@ -478,7 +2062,7 @@ static ssize_t driver_test_write( goto exit; } - if (strstr(p, CMD_GET_BASEDATA)) { + if (!strncmp(p, CMD_GET_BASEDATA, strlen(CMD_GET_BASEDATA))) { rbuf = kzalloc(LARGE_SIZE, GFP_KERNEL); ret = get_cap_data(CMD_GET_BASEDATA); if (ret < 0) { @@ -487,7 +2071,7 @@ static ssize_t driver_test_write( goto exit; } - if (strstr(p, CMD_GET_DIFFDATA)) { + if (!strncmp(p, CMD_GET_DIFFDATA, strlen(CMD_GET_DIFFDATA))) { rbuf = kzalloc(LARGE_SIZE, GFP_KERNEL); ret = get_cap_data(CMD_GET_DIFFDATA); if (ret < 0) { @@ -496,7 +2080,7 @@ static ssize_t driver_test_write( goto exit; } - if (strstr(p, CMD_GET_SELF_RAWDATA)) { + if (!strncmp(p, CMD_GET_SELF_RAWDATA, strlen(CMD_GET_SELF_RAWDATA))) { rbuf = kzalloc(LARGE_SIZE, GFP_KERNEL); ret = get_cap_data(CMD_GET_SELF_RAWDATA); if (ret < 0) { @@ -505,7 +2089,7 @@ static ssize_t driver_test_write( goto exit; } - if (strstr(p, CMD_GET_SELF_DIFFDATA)) { + if (!strncmp(p, CMD_GET_SELF_DIFFDATA, strlen(CMD_GET_SELF_DIFFDATA))) { rbuf = kzalloc(LARGE_SIZE, GFP_KERNEL); ret = get_cap_data(CMD_GET_SELF_DIFFDATA); if (ret < 0) { @@ -515,7 +2099,7 @@ static ssize_t driver_test_write( goto exit; } - if (strstr(p, CMD_GET_SELF_BASEDATA)) { + if (!strncmp(p, CMD_GET_SELF_BASEDATA, strlen(CMD_GET_SELF_BASEDATA))) { rbuf = kzalloc(LARGE_SIZE, GFP_KERNEL); ret = get_cap_data(CMD_GET_SELF_BASEDATA); if (ret < 0) { @@ -525,7 +2109,7 @@ static ssize_t driver_test_write( goto exit; } - if (strstr(p, CMD_SET_DOUBLE_TAP)) { + if (!strncmp(p, CMD_SET_DOUBLE_TAP, strlen(CMD_SET_DOUBLE_TAP))) { rbuf = kzalloc(SHORT_SIZE, GFP_KERNEL); token = strsep(&p, ","); if (!token || !p) { @@ -552,7 +2136,7 @@ static ssize_t driver_test_write( goto exit; } - if (strstr(p, CMD_SET_SINGLE_TAP)) { + if (!strncmp(p, CMD_SET_SINGLE_TAP, strlen(CMD_SET_SINGLE_TAP))) { rbuf = kzalloc(SHORT_SIZE, GFP_KERNEL); token = strsep(&p, ","); if (!token || !p) { @@ -579,7 +2163,7 @@ static ssize_t driver_test_write( goto exit; } - if (strstr(p, CMD_SET_IRQ_ENABLE)) { + if (!strncmp(p, CMD_SET_IRQ_ENABLE, strlen(CMD_SET_IRQ_ENABLE))) { rbuf = kzalloc(SHORT_SIZE, GFP_KERNEL); token = strsep(&p, ","); if (!token || !p) { @@ -604,7 +2188,7 @@ static ssize_t driver_test_write( goto exit; } - if (strstr(p, CMD_SET_ESD_ENABLE)) { + if (!strncmp(p, CMD_SET_ESD_ENABLE, strlen(CMD_SET_ESD_ENABLE))) { rbuf = kzalloc(SHORT_SIZE, GFP_KERNEL); token = strsep(&p, ","); if (!token || !p) { @@ -629,7 +2213,7 @@ static ssize_t driver_test_write( goto exit; } - if (strstr(p, CMD_SET_DEBUG_LOG)) { + if (!strncmp(p, CMD_SET_DEBUG_LOG, strlen(CMD_SET_DEBUG_LOG))) { rbuf = kzalloc(SHORT_SIZE, GFP_KERNEL); token = strsep(&p, ","); if (!token || !p) { @@ -654,23 +2238,31 @@ static ssize_t driver_test_write( goto exit; } - if (strstr(p, CMD_AUTO_TEST)) { - rbuf = kzalloc(SHORT_SIZE, GFP_KERNEL); - info = vmalloc(sizeof(*info)); - goodix_do_inspect(cd, info); - index = sprintf(rbuf, "%s", info->result); - vfree(info); + if (!strncmp(p, CMD_AUTO_TEST, strlen(CMD_AUTO_TEST))) { + rbuf = kzalloc(HUGE_SIZE, GFP_KERNEL); + ret = malloc_test_resource(); + if (ret < 0) { + ts_err("malloc test resource failed"); + goto exit; + } + ts_test->item[GTP_CAP_TEST] = true; + ts_test->item[GTP_NOISE_TEST] = true; + ts_test->item[GTP_SELFCAP_TEST] = true; + ts_test->item[GTP_SHORT_TEST] = true; + ts_test->raw_data_cnt = 16; + ts_test->noise_data_cnt = 1; + goodix_auto_test(); goto exit; } - if (strstr(p, CMD_GET_CHANNEL_NUM)) { + if (!strncmp(p, CMD_GET_CHANNEL_NUM, strlen(CMD_GET_CHANNEL_NUM))) { rbuf = kzalloc(SHORT_SIZE, GFP_KERNEL); index = sprintf(rbuf, "TX:%d RX:%d\n", cd->ic_info.parm.drv_num, cd->ic_info.parm.sen_num); goto exit; } - if (strstr(p, CMD_GET_TX_FREQ)) { + if (!strncmp(p, CMD_GET_TX_FREQ, strlen(CMD_GET_TX_FREQ))) { rbuf = kzalloc(SHORT_SIZE, GFP_KERNEL); ret = get_cap_data(CMD_GET_TX_FREQ); if (ret < 0) { @@ -679,14 +2271,14 @@ static ssize_t driver_test_write( goto exit; } - if (strstr(p, CMD_RESET)) { + if (!strncmp(p, CMD_RESET, strlen(CMD_RESET))) { cd->hw_ops->irq_enable(cd, false); cd->hw_ops->reset(cd, 100); cd->hw_ops->irq_enable(cd, true); goto exit; } - if (strstr(p, CMD_SET_SENSE_ENABLE)) { + if (!strncmp(p, CMD_SET_SENSE_ENABLE, strlen(CMD_SET_SENSE_ENABLE))) { rbuf = kzalloc(SHORT_SIZE, GFP_KERNEL); token = strsep(&p, ","); if (!token || !p) { @@ -710,41 +2302,37 @@ static ssize_t driver_test_write( goto exit; } - if (strstr(p, CMD_NOISE_TEST)) { - rbuf = kzalloc(LARGE_SIZE, GFP_KERNEL); + if (!strncmp(p, CMD_NOISE_TEST, strlen(CMD_NOISE_TEST))) { + rbuf = kzalloc(HUGE_SIZE, GFP_KERNEL); token = strsep(&p, ","); if (!token || !p) { index = sprintf(rbuf, "%s: invalid cmd param\n", CMD_NOISE_TEST); goto exit; } - token = strsep(&p, ","); - if (!token || !p) { + if (kstrtos32(p, 10, &cmd_val)) { index = sprintf(rbuf, "%s: invalid cmd param\n", CMD_NOISE_TEST); goto exit; } - if (kstrtos32(token, 10, &frames)) { - index = sprintf(rbuf, "%s: invalid cmd param\n", - CMD_NOISE_TEST); + if (cmd_val > MAX_FRAME_CNT) { + index = sprintf(rbuf, + "%s: frame cnt:%d > MAX_CNT[%d]\n", + CMD_NOISE_TEST, (int)cmd_val, MAX_FRAME_CNT); goto exit; } - if (kstrtos32(p, 10, &limit)) { - index = sprintf(rbuf, "%s: invalid cmd param\n", - CMD_NOISE_TEST); + ret = malloc_test_resource(); + if (ret < 0) { + ts_err("malloc test resource failed"); goto exit; } - - ts_info("noise test frames:%d limit:%d", frames, limit); - cd->hw_ops->irq_enable(cd, false); - goodix_ts_blocking_notify(NOTIFY_ESD_OFF, NULL); - goodix_noise_test(frames, limit); - cd->hw_ops->irq_enable(cd, true); - goodix_ts_blocking_notify(NOTIFY_ESD_ON, NULL); + ts_test->item[GTP_NOISE_TEST] = true; + ts_test->noise_data_cnt = cmd_val; + goodix_auto_test(); goto exit; } - if (strstr(p, CMD_GET_PACKAGE_ID)) { + if (!strncmp(p, CMD_GET_PACKAGE_ID, strlen(CMD_GET_PACKAGE_ID))) { rbuf = kzalloc(SHORT_SIZE, GFP_KERNEL); ret = goodix_flash_read(0x1F301, &id, 1); if (ret < 0) @@ -755,7 +2343,7 @@ static ssize_t driver_test_write( goto exit; } - if (strstr(p, CMD_SET_SCAN_MODE)) { + if (!strncmp(p, CMD_SET_SCAN_MODE, strlen(CMD_SET_SCAN_MODE))) { rbuf = kzalloc(SHORT_SIZE, GFP_KERNEL); token = strsep(&p, ","); if (!token || !p) { @@ -768,15 +2356,95 @@ static ssize_t driver_test_write( CMD_SET_SCAN_MODE); goto exit; } - if (cmd_val == 0) { - goodix_set_scan_mode(0); + if (cmd_val > 2 || cmd_val < 0) { + index = sprintf(rbuf, "%s: invalid cmd param\n", + CMD_SET_SCAN_MODE); + goto exit; + } + goodix_set_scan_mode(cmd_val); + goto exit; + } + + if (!strncmp(p, CMD_SET_CONTINUE_MODE, strlen(CMD_SET_CONTINUE_MODE))) { + rbuf = kzalloc(SHORT_SIZE, GFP_KERNEL); + token = strsep(&p, ","); + if (!token || !p) { + index = sprintf(rbuf, "%s: invalid cmd param\n", + CMD_SET_CONTINUE_MODE); + goto exit; + } + if (kstrtos32(p, 10, &cmd_val)) { + index = sprintf(rbuf, "%s: invalid cmd param\n", + CMD_SET_CONTINUE_MODE); + goto exit; + } + if (cmd_val > 1 || cmd_val < 0) { + index = sprintf(rbuf, "%s: invalid cmd param\n", + CMD_SET_CONTINUE_MODE); + goto exit; + } + goodix_set_continue_mode(cmd_val); + goto exit; + } + + /* open test */ + if (!strncmp(p, CMD_OPEN_TEST, strlen(CMD_OPEN_TEST))) { + rbuf = kzalloc(HUGE_SIZE, GFP_KERNEL); + token = strsep(&p, ","); + if (!token || !p) { index = sprintf( - rbuf, "%s: exit idle\n", CMD_SET_SCAN_MODE); - } else { - goodix_set_scan_mode(1); + rbuf, "%s: invalid cmd param\n", CMD_OPEN_TEST); + goto exit; + } + token = strsep(&p, ","); + if (!token || !p) { index = sprintf( - rbuf, "%s: enter idle\n", CMD_SET_SCAN_MODE); + rbuf, "%s: invalid cmd param\n", CMD_OPEN_TEST); + goto exit; + } + if (kstrtos32(token, 10, &cmd_val)) { + index = sprintf( + rbuf, "%s: invalid cmd param\n", CMD_OPEN_TEST); + goto exit; + } + if (kstrtos32(p, 10, &cmd_val2)) { + index = sprintf( + rbuf, "%s: invalid cmd param\n", CMD_OPEN_TEST); + goto exit; + } + ret = malloc_test_resource(); + if (ret < 0) { + ts_err("malloc test resource failed"); + goto exit; + } + ts_test->item[GTP_CAP_TEST] = true; + ts_test->raw_data_cnt = cmd_val; + ts_test->freq = cmd_val2; + goodix_auto_test(); + goto exit; + } + + if (!strncmp(p, CMD_SELF_OPEN_TEST, strlen(CMD_SELF_OPEN_TEST))) { + rbuf = kzalloc(HUGE_SIZE, GFP_KERNEL); + ret = malloc_test_resource(); + if (ret < 0) { + ts_err("malloc test resource failed"); + goto exit; + } + ts_test->item[GTP_SELFCAP_TEST] = true; + goodix_auto_test(); + goto exit; + } + + if (!strncmp(p, CMD_SHORT_TEST, strlen(CMD_SHORT_TEST))) { + rbuf = kzalloc(HUGE_SIZE, GFP_KERNEL); + ret = malloc_test_resource(); + if (ret < 0) { + ts_err("malloc test resource failed"); + goto exit; } + ts_test->item[GTP_SHORT_TEST] = true; + goodix_auto_test(); goto exit; } |