KernelNanopiR5S/drivers/input/touchscreen/focaltech_touch/focaltech_test/focaltech_test.c
2024-09-10 09:59:09 +02:00

1949 lines
51 KiB
C

/*
*
* FocalTech TouchScreen driver.
*
* Copyright (c) 2012-2018, FocalTech Systems, Ltd., all rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
/************************************************************************
*
* File Name: focaltech_test.c
*
* Author: Focaltech Driver Team
*
* Created: 2016-08-01
*
* Modify:
*
* Abstract: create char device and proc node for the comm between APK and TP
*
************************************************************************/
/*****************************************************************************
* Included header files
*****************************************************************************/
#include "focaltech_test.h"
/*****************************************************************************
* Private constant and macro definitions using #define
*****************************************************************************/
/*****************************************************************************
* Global variable or extern global variabls/functions
*****************************************************************************/
struct fts_test *fts_ftest;
struct test_funcs *test_func_list[] = {
&test_func_ft8201,
};
/*****************************************************************************
* Static function prototypes
*****************************************************************************/
/*****************************************************************************
* functions body
*****************************************************************************/
void sys_delay(int ms)
{
msleep(ms);
}
int focal_abs(int value)
{
if (value < 0)
value = 0 - value;
return value;
}
void *fts_malloc(size_t size)
{
return kzalloc(size, GFP_KERNEL);
}
void fts_free_proc(void *p)
{
return kfree(p);
}
void print_buffer(int *buffer, int length, int line_num)
{
int i = 0;
if (NULL == buffer) {
FTS_TEST_DBG("buffer is null");
return;
}
for (i = 0; i < length; i++) {
printk("%5d ", buffer[i]);
if ((0 == (i + 1) % line_num))
printk("\n");
}
printk("\n");
}
/********************************************************************
* test i2c read/write interface
*******************************************************************/
static int fts_test_i2c_read(u8 *writebuf, int writelen, u8 *readbuf, int readlen)
{
int ret = 0;
#if 1
if (NULL == fts_data) {
FTS_TEST_ERROR("fts_data is null, no test");
return -EINVAL;
}
ret = fts_i2c_read(fts_data->client, writebuf, writelen, readbuf, readlen);
#else
ret = fts_i2c_read(writebuf, writelen, readbuf, readlen);
#endif
if (ret < 0)
return ret;
else
return 0;
}
static int fts_test_i2c_write(u8 *writebuf, int writelen)
{
int ret = 0;
#if 1
if (NULL == fts_data) {
FTS_TEST_ERROR("fts_data is null, no test");
return -EINVAL;
}
ret = fts_i2c_write(fts_data->client, writebuf, writelen);
#else
ret = fts_i2c_write(writebuf, writelen);
#endif
if (ret < 0)
return ret;
else
return 0;
}
int fts_test_read_reg(u8 addr, u8 *val)
{
return fts_test_i2c_read(&addr, 1, val, 1);
}
int fts_test_write_reg(u8 addr, u8 val)
{
int ret;
u8 cmd[2] = {0};
cmd[0] = addr;
cmd[1] = val;
ret = fts_test_i2c_write(cmd, 2);
return ret;
}
int fts_test_read(u8 addr, u8 *readbuf, int readlen)
{
int ret = 0;
int i = 0;
int packet_length = 0;
int packet_num = 0;
int packet_remainder = 0;
int offset = 0;
int byte_num = readlen;
packet_num = byte_num / BYTES_PER_TIME;
packet_remainder = byte_num % BYTES_PER_TIME;
if (packet_remainder)
packet_num++;
if (byte_num < BYTES_PER_TIME) {
packet_length = byte_num;
} else {
packet_length = BYTES_PER_TIME;
}
// FTS_TEST_DBG("packet num:%d, remainder:%d", packet_num, packet_remainder);
ret = fts_test_i2c_read(&addr, 1, &readbuf[offset], packet_length);
if (ret < 0) {
FTS_TEST_ERROR("read buffer fail");
return ret;
}
for (i = 1; i < packet_num; i++) {
offset += packet_length;
if ((i == (packet_num - 1)) && packet_remainder) {
packet_length = packet_remainder;
}
ret = fts_test_i2c_read(NULL, 0, &readbuf[offset], packet_length);
if (ret < 0) {
FTS_TEST_ERROR("read buffer fail");
return ret;
}
}
return 0;
}
int fts_test_write(u8 addr, u8 *writebuf, int writelen)
{
int ret = 0;
int i = 0;
u8 data[BYTES_PER_TIME + 1] = { 0 };
int packet_length = 0;
int packet_num = 0;
int packet_remainder = 0;
int offset = 0;
int byte_num = writelen;
packet_num = byte_num / BYTES_PER_TIME;
packet_remainder = byte_num % BYTES_PER_TIME;
if (packet_remainder)
packet_num++;
if (byte_num < BYTES_PER_TIME) {
packet_length = byte_num;
} else {
packet_length = BYTES_PER_TIME;
}
FTS_TEST_DBG("packet num:%d, remainder:%d", packet_num, packet_remainder);
data[0] = addr;
for (i = 0; i < packet_num; i++) {
if (i != 0) {
data[0] = addr + 1;
}
if ((i == (packet_num - 1)) && packet_remainder) {
packet_length = packet_remainder;
}
memcpy(&data[1], &writebuf[offset], packet_length);
ret = fts_test_i2c_write(data, packet_length + 1);
if (ret < 0) {
FTS_TEST_ERROR("write buffer fail");
return ret;
}
offset += packet_length;
}
return 0;
}
/********************************************************************
* test global function enter work/factory mode
*******************************************************************/
int enter_work_mode(void)
{
int ret = 0;
u8 mode = 0;
int i = 0;
int j = 0;
FTS_TEST_FUNC_ENTER();
ret = fts_test_read_reg(DEVIDE_MODE_ADDR, &mode);
if ((ret >= 0) && (0x00 == mode))
return 0;
for (i = 0; i < ENTER_WORK_FACTORY_RETRIES; i++) {
ret = fts_test_write_reg(DEVIDE_MODE_ADDR, 0x00);
if (ret >= 0) {
sys_delay(FACTORY_TEST_DELAY);
for (j = 0; j < 20; j++) {
ret = fts_test_read_reg(DEVIDE_MODE_ADDR, &mode);
if ((ret >= 0) && (0x00 == mode)) {
FTS_TEST_INFO("enter work mode success");
return 0;
} else
sys_delay(FACTORY_TEST_DELAY);
}
}
sys_delay(50);
}
if (i >= ENTER_WORK_FACTORY_RETRIES) {
FTS_TEST_ERROR("Enter work mode fail");
return -EIO;
}
FTS_TEST_FUNC_EXIT();
return 0;
}
int enter_factory_mode(void)
{
int ret = 0;
u8 mode = 0;
int i = 0;
int j = 0;
ret = fts_test_read_reg(DEVIDE_MODE_ADDR, &mode);
if ((ret >= 0) && (0x40 == mode))
return 0;
for (i = 0; i < ENTER_WORK_FACTORY_RETRIES; i++) {
ret = fts_test_write_reg(DEVIDE_MODE_ADDR, 0x40);
if (ret >= 0) {
sys_delay(FACTORY_TEST_DELAY);
for (j = 0; j < 20; j++) {
ret = fts_test_read_reg(DEVIDE_MODE_ADDR, &mode);
if ((ret >= 0) && (0x40 == mode)) {
FTS_TEST_INFO("enter factory mode success");
sys_delay(200);
return 0;
} else
sys_delay(FACTORY_TEST_DELAY);
}
}
sys_delay(50);
}
if (i >= ENTER_WORK_FACTORY_RETRIES) {
FTS_TEST_ERROR("Enter factory mode fail");
return -EIO;
}
return 0;
}
/*
* read_mass_data - read rawdata/short test data
* addr - register addr which read data from
* byte_num - read data length, unit:byte
* buf - save data
*
* return 0 if read data succuss, otherwise return error code
*/
int read_mass_data(u8 addr, int byte_num, int *buf)
{
int ret = 0;
int i = 0;
u8 *data = NULL;
data = (u8 *)fts_malloc(byte_num * sizeof(u8));
if (NULL == data) {
FTS_TEST_SAVE_ERR("mass data buffer malloc fail\n");
return -ENOMEM;
}
/* read rawdata buffer */
FTS_TEST_INFO("mass data len:%d", byte_num);
ret = fts_test_read(addr, data, byte_num);
if (ret < 0) {
FTS_TEST_SAVE_ERR("read mass data fail\n");
goto read_massdata_err;
}
for (i = 0; i < byte_num; i = i + 2) {
buf[i >> 1] = (int)(((int)(data[i]) << 8) + data[i + 1]);
}
ret = 0;
read_massdata_err:
fts_free(data);
return ret;
}
int short_get_adcdata_incell(u8 retval, u8 ch_num, int byte_num, int *adc_buf)
{
int ret = 0;
int times = 0;
u8 short_state = 0;
FTS_TEST_FUNC_ENTER();
/* Start ADC sample */
ret = fts_test_write_reg(FACTORY_REG_SHORT_TEST_EN, 0x01);
if (ret) {
FTS_TEST_SAVE_ERR("start short test fail\n");
goto adc_err;
}
sys_delay(ch_num * FACTORY_TEST_DELAY);
for (times = 0; times < FACTORY_TEST_RETRY; times++) {
ret = fts_test_read_reg(FACTORY_REG_SHORT_TEST_STATE, &short_state);
if ((ret >= 0) && (retval == short_state))
break;
else
FTS_TEST_DBG("reg%x=%x,retry:%d",
FACTORY_REG_SHORT_TEST_STATE, short_state, times);
sys_delay(FACTORY_TEST_RETRY_DELAY);
}
if (times >= FACTORY_TEST_RETRY) {
FTS_TEST_SAVE_ERR("short test timeout, ADC data not OK\n");
ret = -EIO;
goto adc_err;
}
ret = read_mass_data(FACTORY_REG_SHORT_ADDR, byte_num, adc_buf);
if (ret) {
FTS_TEST_SAVE_ERR("get short(adc) data fail\n");
}
adc_err:
FTS_TEST_FUNC_EXIT();
return ret;
}
/*
* wait_state_update - wait fw status update
*/
int wait_state_update(u8 retval)
{
int ret = 0;
int times = 0;
u8 state = 0xFF;
while (times++ < FACTORY_TEST_RETRY) {
sys_delay(FACTORY_TEST_DELAY);
/* Wait register status update */
state = 0xFF;
ret = fts_test_read_reg(FACTORY_REG_PARAM_UPDATE_STATE, &state);
if ((ret >= 0) && (retval == state))
break;
else
FTS_TEST_DBG("reg%x=%x,retry:%d", \
FACTORY_REG_PARAM_UPDATE_STATE, state, times);
}
if (times >= FACTORY_TEST_RETRY) {
FTS_TEST_SAVE_ERR("Wait State Update fail\n");
return -EIO;
}
return 0;
}
/*
* start_scan - start to scan a frame
*/
int start_scan(void)
{
int ret = 0;
u8 addr = 0;
u8 val = 0;
u8 finish_val = 0;
int times = 0;
struct fts_test *tdata = fts_ftest;
if ((NULL == tdata) || (NULL == tdata->func) ) {
FTS_TEST_ERROR("test/func is null\n");
return -EINVAL;
}
if (SCAN_SC == tdata->func->startscan_mode) {
/* sc ic */
addr = FACTORY_REG_SCAN_ADDR2;
val = 0x01;
finish_val = 0x00;
} else {
addr = DEVIDE_MODE_ADDR;
val = 0xC0;
finish_val = 0x40;
}
/* write register to start scan */
ret = fts_test_write_reg(addr, val);
if (ret < 0) {
FTS_TEST_SAVE_ERR("write start scan mode fail\n");
return ret;
}
/* Wait for the scan to complete */
while (times++ < FACTORY_TEST_RETRY) {
sys_delay(FACTORY_TEST_DELAY);
ret = fts_test_read_reg(addr, &val);
if ((ret >= 0) && (val == finish_val)) {
break;
} else
FTS_TEST_DBG("reg%x=%x,retry:%d", addr, val, times);
}
if (times >= FACTORY_TEST_RETRY) {
FTS_TEST_SAVE_ERR("scan timeout\n");
return -EIO;
}
return 0;
}
static int read_rawdata(
u8 off_addr,
u8 off_val,
u8 rawdata_addr,
int byte_num,
int *data)
{
int ret = 0;
/* set line addr or rawdata start addr */
ret = fts_test_write_reg(off_addr, off_val);
if (ret < 0) {
FTS_TEST_SAVE_ERR("wirte line/start addr fail\n");
return ret;
}
ret = read_mass_data(rawdata_addr, byte_num, data);
if (ret < 0) {
FTS_TEST_SAVE_ERR("read rawdata fail\n");
return ret;
}
return 0;
}
int get_rawdata(int *data)
{
int ret = 0;
u8 val = 0;
u8 addr = 0;
u8 rawdata_addr = 0;
int byte_num = 0;
struct fts_test *tdata = fts_ftest;
if ((NULL == tdata) || (NULL == tdata->func) ) {
FTS_TEST_ERROR("test/func is null\n");
return -EINVAL;
}
/* enter factory mode */
ret = enter_factory_mode();
if (ret < 0) {
FTS_TEST_SAVE_ERR("failed to enter factory mode,ret=%d\n", ret);
return ret;
}
/* start scanning */
ret = start_scan();
if (ret < 0) {
FTS_TEST_SAVE_ERR("scan fail\n");
return ret;
}
/* read rawdata */
if (IC_HW_INCELL == tdata->func->hwtype) {
val = 0xAD;
addr = FACTORY_REG_LINE_ADDR;
rawdata_addr = FACTORY_REG_RAWDATA_ADDR;
} else if (IC_HW_MC_SC == tdata->func->hwtype) {
val = 0xAA;
addr = FACTORY_REG_LINE_ADDR;
rawdata_addr = FACTORY_REG_RAWDATA_ADDR_MC_SC;
} else {
val = 0x0;
addr = FACTORY_REG_RAWDATA_SADDR_SC;
rawdata_addr = FACTORY_REG_RAWDATA_ADDR_SC;
}
byte_num = tdata->node.node_num * 2;
ret = read_rawdata(addr, val, rawdata_addr, byte_num, data);
if (ret < 0) {
FTS_TEST_SAVE_ERR("read rawdata fail\n");
return ret;
}
return 0;
}
/*
* chip_clb - auto clb
*/
int chip_clb(void)
{
int ret = 0;
u8 val = 0;
int times = 0;
/* start clb */
ret = fts_test_write_reg(FACTORY_REG_CLB, 0x04);
if (ret) {
FTS_TEST_SAVE_ERR("write start clb fail\n");
return ret;
}
while (times++ < FACTORY_TEST_RETRY) {
sys_delay(FACTORY_TEST_RETRY_DELAY);
ret = fts_test_read_reg(FACTORY_REG_CLB, &val);
if ((0 == ret) && (0x02 == val)) {
/* clb ok */
break;
} else
FTS_TEST_DBG("reg%x=%x,retry:%d", FACTORY_REG_CLB, val, times);
}
if (times >= FACTORY_TEST_RETRY) {
FTS_TEST_SAVE_ERR("chip clb timeout\n");
return -EIO;
}
return 0;
}
/*
* get_cb_incell - get cb data for incell IC
*/
int get_cb_incell(u16 saddr, int byte_num, int *cb_buf)
{
int ret = 0;
int i = 0;
u8 cb_addr = 0;
u8 addr_h = 0;
u8 addr_l = 0;
int read_num = 0;
int packet_num = 0;
int packet_remainder = 0;
int offset = 0;
int addr = 0;
u8 *data = NULL;
data = (u8 *)fts_malloc(byte_num * sizeof(u8));
if (NULL == data) {
FTS_TEST_SAVE_ERR("cb buffer malloc fail\n");
return -ENOMEM;
}
packet_num = byte_num / BYTES_PER_TIME;
packet_remainder = byte_num % BYTES_PER_TIME;
if (packet_remainder)
packet_num++;
read_num = BYTES_PER_TIME;
FTS_TEST_INFO("cb packet:%d,remainder:%d", packet_num, packet_remainder);
cb_addr = FACTORY_REG_CB_ADDR;
for (i = 0; i < packet_num; i++) {
offset = read_num * i;
addr = saddr + offset;
addr_h = (addr >> 8) & 0xFF;
addr_l = addr & 0xFF;
if ((i == (packet_num - 1)) && packet_remainder) {
read_num = packet_remainder;
}
ret = fts_test_write_reg(FACTORY_REG_CB_ADDR_H, addr_h);
if (ret) {
FTS_TEST_SAVE_ERR("write cb addr high fail\n");
goto TEST_CB_ERR;
}
ret = fts_test_write_reg(FACTORY_REG_CB_ADDR_L, addr_l);
if (ret) {
FTS_TEST_SAVE_ERR("write cb addr low fail\n");
goto TEST_CB_ERR;
}
ret = fts_test_read(cb_addr, data + offset, read_num);
if (ret) {
FTS_TEST_SAVE_ERR("read cb fail\n");
goto TEST_CB_ERR;
}
}
for (i = 0; i < byte_num; i++) {
cb_buf[i] = data[i];
}
TEST_CB_ERR:
fts_free(data);
return ret;
}
int get_cb_sc(int byte_num, int *cb_buf, enum byte_mode mode)
{
int ret = 0;
int i = 0;
int read_num = 0;
int packet_num = 0;
int packet_remainder = 0;
int offset = 0;
u8 cb_addr = 0;
u8 off_addr = 0;
struct fts_test *tdata = fts_ftest;
u8 *cb = NULL;
if ((NULL == tdata) || (NULL == tdata->func) ) {
FTS_TEST_ERROR("test/func is null\n");
return -EINVAL;
}
cb = (u8 *)fts_malloc(byte_num * sizeof(u8));
if (NULL == cb) {
FTS_TEST_SAVE_ERR("malloc memory for cb buffer fail\n");
return -ENOMEM;
}
if (IC_HW_MC_SC == tdata->func->hwtype) {
cb_addr = FACTORY_REG_MC_SC_CB_ADDR;
off_addr = FACTORY_REG_MC_SC_CB_ADDR_OFF;
} else if (IC_HW_SC == tdata->func->hwtype) {
cb_addr = FACTORY_REG_SC_CB_ADDR;
off_addr = FACTORY_REG_SC_CB_ADDR_OFF;
}
packet_num = byte_num / BYTES_PER_TIME;
packet_remainder = byte_num % BYTES_PER_TIME;
if (packet_remainder)
packet_num++;
read_num = BYTES_PER_TIME;
offset = 0;
FTS_TEST_INFO("cb packet:%d,remainder:%d", packet_num, packet_remainder);
for (i = 0; i < packet_num; i++) {
if ((i == (packet_num - 1)) && packet_remainder) {
read_num = packet_remainder;
}
ret = fts_test_write_reg(off_addr, offset);
if (ret < 0) {
FTS_TEST_SAVE_ERR("write cb addr offset fail\n");
goto cb_err;
}
ret = fts_test_read(cb_addr, cb + offset, read_num);
if (ret < 0) {
FTS_TEST_SAVE_ERR("read cb fail\n");
goto cb_err;
}
offset += read_num;
}
if (DATA_ONE_BYTE == mode) {
for (i = 0; i < byte_num; i++) {
cb_buf[i] = cb[i];
}
} else if (DATA_TWO_BYTE == mode) {
for (i = 0; i < byte_num; i = i + 2) {
cb_buf[i >> 1] = (int)(((int)(cb[i]) << 8) + cb[i + 1]);
}
}
ret = 0;
cb_err:
fts_free(cb);
return ret;
}
bool compare_data(int *data, int min, int max, int min_vk, int max_vk, bool key)
{
int i = 0;
bool result = true;
struct fts_test *tdata = fts_ftest;
int rx = tdata->node.rx_num;
int node_va = tdata->node.node_num - tdata->node.key_num;
if (!data || !tdata->node_valid) {
FTS_TEST_SAVE_ERR("data/node_valid is null\n");
return false;
}
for (i = 0; i < node_va; i++) {
if (0 == tdata->node_valid[i])
continue;
if ((data[i] < min) || (data[i] > max)) {
FTS_TEST_SAVE_ERR("test fail,node(%4d,%4d)=%5d,range=(%5d,%5d)\n",
i / rx + 1, i % rx + 1, data[i], min, max);
result = false;
}
}
if (key) {
for (i = node_va; i < tdata->node.node_num; i++) {
if (0 == tdata->node_valid[i])
continue;
if ((data[i] < min_vk) || (data[i] > max_vk)) {
FTS_TEST_SAVE_ERR("test fail,node(%4d,%4d)=%5d,range=(%5d,%5d)\n",
i / rx + 1, i % rx + 1,
data[i], min_vk, max_vk);
result = false;
}
}
}
return result;
}
bool compare_array(int *data, int *min, int *max, bool key)
{
int i = 0;
bool result = true;
struct fts_test *tdata = fts_ftest;
int rx = tdata->node.rx_num;
int node_num = tdata->node.node_num;
if (!data || !min || !max || !tdata->node_valid) {
FTS_TEST_SAVE_ERR("data/min/max/node_valid is null\n");
return false;
}
if (!key) {
node_num -= tdata->node.key_num;
}
for (i = 0; i < node_num; i++) {
if (0 == tdata->node_valid[i])
continue;
if ((data[i] < min[i]) || (data[i] > max[i])) {
FTS_TEST_SAVE_ERR("test fail,node(%4d,%4d)=%5d,range=(%5d,%5d)\n",
i / rx + 1, i % rx + 1, data[i], min[i], max[i]);
result = false;
}
}
return result;
}
/*
* show_data - show and save test data to testresult.txt
*/
void show_data(int *data, bool key)
{
int i = 0;
int j = 0;
struct fts_test *tdata = fts_ftest;
int node_num = tdata->node.node_num;
int tx_num = tdata->node.tx_num;
int rx_num = tdata->node.rx_num;
FTS_TEST_FUNC_ENTER();
for (i = 0; i < tx_num; i++) {
FTS_TEST_SAVE_INFO("Ch/Tx_%02d: ", i + 1);
for (j = 0; j < rx_num; j++) {
FTS_TEST_SAVE_INFO("%5d, ", data[i * rx_num + j]);
}
FTS_TEST_SAVE_INFO("\n");
}
if (key) {
FTS_TEST_SAVE_INFO("Ch/Tx_%02d: ", tx_num + 1);
for (i = tx_num * rx_num; i < node_num; i++) {
FTS_TEST_SAVE_INFO("%5d, ", data[i]);
}
FTS_TEST_SAVE_INFO("\n");
}
FTS_TEST_FUNC_EXIT();
}
/*
* save_testdata_incell - save data to testdata.csv
*/
void save_data_csv(int *data, char *name, u8 code, bool mc_sc, bool key)
{
#if CSV_SUPPORT
int i = 0;
int tx = 0;
int rx = 0;
int csv_node_num = 0;
struct fts_test *tdata = fts_ftest;
struct fts_test_node *node = NULL;
struct csv_format *csv = &tdata->csv;
FTS_TEST_FUNC_ENTER();
if (!csv || !csv->line2_buffer || !csv->data_buffer) {
FTS_TEST_ERROR("csv buffer is null");
return;
}
if (mc_sc) {
node = &tdata->sc_node;
tx = 2;
} else {
node = &tdata->node;
tx = node->tx_num;
}
if (key) {
tx++;
}
rx = node->rx_num;
csv_node_num = tx * rx;
/* line 2 */
csv->line2_len += snprintf(csv->line2_buffer + csv->line2_len, \
CSV_LINE2_BUFFER_LEN - csv->line2_len,
"%s, %d, %d, %d, %d, %d, ", \
name, code, tx, rx,
csv->start_line, csv->item_count);
if (csv->line2_len >= CSV_LINE2_BUFFER_LEN - 1) {
FTS_TEST_ERROR("csv line2 buffer length(%d) fail", csv->line2_len);
}
csv->start_line += tx;
csv->item_count++;
/* test data */
for (i = 0; i < csv_node_num; i++) {
if (((i + 1) % rx) == 0) {
csv->data_len += snprintf(csv->data_buffer + csv->data_len, \
CSV_DATA_BUFFER_LEN - csv->data_len, \
"%d, \n", data[i]);
} else {
csv->data_len += snprintf(csv->data_buffer + csv->data_len, \
CSV_DATA_BUFFER_LEN - csv->data_len, \
"%d, ", data[i]);
}
if (csv->data_len >= CSV_DATA_BUFFER_LEN - 1) {
FTS_TEST_ERROR("csv data buffer length(%d) fail", csv->data_len);
}
}
FTS_TEST_FUNC_EXIT();
#endif
}
/* mc_sc only */
/* Only V3 Pattern has mapping & no-mapping */
int mapping_switch(u8 mapping)
{
int ret = 0;
u8 val = 0xFF;
struct fts_test *tdata = fts_ftest;
if (tdata->v3_pattern) {
ret = fts_test_read_reg(FACTORY_REG_NOMAPPING, &val);
if (ret < 0) {
FTS_TEST_ERROR("read 0x54 register fail");
return ret;
}
if (val != mapping) {
ret = fts_test_write_reg(FACTORY_REG_NOMAPPING, mapping);
if (ret < 0) {
FTS_TEST_ERROR("write 0x54 register fail");
return ret;
}
sys_delay(FACTORY_TEST_DELAY);
}
}
return 0;
}
bool get_fw_wp(u8 wp_ch_sel, enum wp_type water_proof_type)
{
bool fw_wp_state = false;
switch (water_proof_type) {
case WATER_PROOF_ON:
/* bit5: 0-check in wp on, 1-not check */
fw_wp_state = !(wp_ch_sel & 0x20);
break;
case WATER_PROOF_ON_TX:
/* Bit6: 0-check Rx+Tx in wp mode 1-check one channel
Bit2: 0-check Tx in wp mode; 1-check Rx in wp mode
*/
fw_wp_state = (!(wp_ch_sel & 0x40) || !(wp_ch_sel & 0x04));
break;
case WATER_PROOF_ON_RX:
fw_wp_state = (!(wp_ch_sel & 0x40) || (wp_ch_sel & 0x04));
break;
case WATER_PROOF_OFF:
/* bit7: 0-check in wp off, 1-not check */
fw_wp_state = !(wp_ch_sel & 0x80);
break;
case WATER_PROOF_OFF_TX:
/* Bit1-0: 00-check Tx in non-wp mode
01-check Rx in non-wp mode
10:check Rx+Tx in non-wp mode
*/
fw_wp_state = ((0x0 == (wp_ch_sel & 0x03)) || (0x02 == (wp_ch_sel & 0x03)));
break;
case WATER_PROOF_OFF_RX:
fw_wp_state = ((0x01 == (wp_ch_sel & 0x03)) || (0x02 == (wp_ch_sel & 0x03)));
break;
default:
break;
}
return fw_wp_state;
}
int get_cb_mc_sc(u8 wp, int byte_num, int *cb_buf, enum byte_mode mode)
{
int ret = 0;
/* 1:waterproof 0:non-waterproof */
ret = fts_test_write_reg(FACTORY_REG_MC_SC_MODE, wp);
if (ret < 0) {
FTS_TEST_SAVE_ERR("get mc_sc mode fail\n");
return ret;
}
/* read cb */
ret = get_cb_sc(byte_num, cb_buf, mode);
if (ret < 0) {
FTS_TEST_SAVE_ERR("get sc cb fail\n");
return ret;
}
return 0;
}
int get_rawdata_mc_sc(enum wp_type wp, int *data)
{
int ret = 0;
u8 val = 0;
u8 addr = 0;
u8 rawdata_addr = 0;
int byte_num = 0;
struct fts_test *tdata = fts_ftest;
if ((NULL == tdata) || (NULL == tdata->func) ) {
FTS_TEST_ERROR("test/func is null\n");
return -EINVAL;
}
addr = FACTORY_REG_LINE_ADDR;
rawdata_addr = FACTORY_REG_RAWDATA_ADDR_MC_SC;
if (WATER_PROOF_ON == wp) {
val = 0xAC;
} else {
val = 0xAB;
}
byte_num = tdata->sc_node.node_num * 2;
ret = read_rawdata(addr, val, rawdata_addr, byte_num, data);
if (ret < 0) {
FTS_TEST_SAVE_ERR("read rawdata fail\n");
return ret;
}
return 0;
}
int get_rawdata_mc(u8 fre, u8 fir, int *rawdata)
{
int ret = 0;
int i = 0;
if (NULL == rawdata ) {
FTS_TEST_SAVE_ERR("rawdata buffer is null\n");
return -EINVAL;
}
/* set frequecy high/low */
ret = fts_test_write_reg(FACTORY_REG_FRE_LIST, fre);
if (ret < 0) {
FTS_TEST_SAVE_ERR("set frequecy fail,ret=%d\n", ret);
return ret;
}
/* fir enable/disable */
ret = fts_test_write_reg(FACTORY_REG_FIR, 1);
if (ret < 0) {
FTS_TEST_SAVE_ERR("set fir fail,ret=%d\n", fir);
return ret;
}
/* get rawdata */
for (i = 0; i < 3; i++) {
/* lost 3 frames, in order to obtain stable data */
ret = get_rawdata(rawdata);
}
if (ret < 0) {
FTS_TEST_SAVE_ERR("get rawdata fail,ret=%d\n", ret);
return ret;
}
return 0;
}
void short_print_mc(int *r, int num)
{
int i = 0;
for (i = 0; i < num; i++) {
printk("%4d ", r[i]);
}
printk("\n");
}
int short_get_adc_data_mc(u8 retval, int byte_num, int *adc_buf, u8 mode)
{
int ret = 0;
int i = 0;
u8 short_state = 0;
FTS_TEST_FUNC_ENTER();
/* select short test mode & start test */
ret = fts_test_write_reg(FACTROY_REG_SHORT_TEST_EN, mode);
if (ret < 0) {
FTS_TEST_SAVE_ERR("write short test mode fail\n");
goto test_err;
}
for (i = 0; i < FACTORY_TEST_RETRY; i++) {
sys_delay(FACTORY_TEST_RETRY_DELAY);
ret = fts_test_read_reg(FACTROY_REG_SHORT_TEST_EN, &short_state);
if ((ret >= 0) && (retval == short_state))
break;
else
FTS_TEST_DBG("reg%x=%x,retry:%d",
FACTROY_REG_SHORT_TEST_EN, short_state, i);
}
if (i >= FACTORY_TEST_RETRY) {
FTS_TEST_SAVE_ERR("short test timeout, ADC data not OK\n");
ret = -EIO;
goto test_err;
}
ret = read_mass_data(FACTORY_REG_SHORT_ADDR_MC, byte_num, adc_buf);
if (ret < 0) {
FTS_TEST_SAVE_ERR("get short(adc) data fail\n");
}
FTS_TEST_DBG("adc data:\n");
short_print_mc(adc_buf, byte_num / 2);
test_err:
FTS_TEST_FUNC_EXIT();
return ret;
}
bool compare_mc_sc(bool tx_check, bool rx_check, int *data, int *min, int *max)
{
int i = 0;
bool result = true;
struct fts_test *tdata = fts_ftest;
if (rx_check) {
for (i = 0; i < tdata->sc_node.rx_num; i++) {
if (0 == tdata->node_valid_sc[i])
continue;
if ((data[i] < min[i]) || (data[i] > max[i])) {
FTS_TEST_SAVE_ERR("test fail,rx%d=%5d,range=(%5d,%5d)\n",
i + 1, data[i], min[i], max[i]);
result = false;
}
}
}
if (tx_check) {
for (i = tdata->sc_node.rx_num; i < tdata->sc_node.node_num; i++) {
if (0 == tdata->node_valid_sc[i])
continue;
if ((data[i] < min[i]) || (data[i] > max[i])) {
FTS_TEST_SAVE_INFO("test fail,tx%d=%5d,range=(%5d,%5d)\n",
i - tdata->sc_node.rx_num + 1,
data[i], min[i], max[i]);
result = false;
}
}
}
return result;
}
void show_data_mc_sc(int *data)
{
int i = 0;
struct fts_test *tdata = fts_ftest;
FTS_TEST_SAVE_INFO("SCap Rx: ");
for (i = 0; i < tdata->sc_node.rx_num; i++) {
FTS_TEST_SAVE_INFO( "%5d, ", data[i]);
}
FTS_TEST_SAVE_INFO("\n");
FTS_TEST_SAVE_INFO("SCap Tx: ");
for (i = tdata->sc_node.rx_num; i < tdata->sc_node.node_num; i++) {
FTS_TEST_SAVE_INFO( "%5d, ", data[i]);
}
FTS_TEST_SAVE_INFO("\n");
}
/* mc_sc end*/
/*
* fts_test_save_test_data - Save test data to SD card etc.
*/
static int fts_test_save_test_data(char *file_name, char *data_buf, int len)
{
struct file *pfile = NULL;
char filepath[128];
loff_t pos;
mm_segment_t old_fs;
FTS_TEST_FUNC_ENTER();
memset(filepath, 0, sizeof(filepath));
sprintf(filepath, "%s%s", FTS_INI_FILE_PATH, file_name);
if (NULL == pfile) {
pfile = filp_open(filepath, O_TRUNC | O_CREAT | O_RDWR, 0);
}
if (IS_ERR(pfile)) {
FTS_TEST_ERROR("error occured while opening file %s.", filepath);
return -EIO;
}
old_fs = get_fs();
set_fs(KERNEL_DS);
pos = 0;
vfs_write(pfile, data_buf, len, &pos);
filp_close(pfile, NULL);
set_fs(old_fs);
FTS_TEST_FUNC_EXIT();
return 0;
}
static int fts_test_malloc_free_data_csv(struct fts_test *tdata, bool allocate)
{
#if CSV_SUPPORT
struct csv_format *csv = &tdata->csv;
if (true == allocate) {
csv->buffer = vmalloc(CSV_BUFFER_LEN);
if (NULL == csv->buffer) {
FTS_TEST_ERROR("csv->buffer malloc fail\n");
return -ENOMEM;
}
csv->line2_buffer = vmalloc(CSV_LINE2_BUFFER_LEN);
if (NULL == csv->line2_buffer) {
FTS_TEST_ERROR("csv->line2_buffer malloc fail\n");
return -ENOMEM;
}
csv->data_buffer = vmalloc(CSV_DATA_BUFFER_LEN);
if (NULL == csv->data_buffer) {
FTS_TEST_ERROR("csv->data_buffer malloc fail\n");
return -ENOMEM;
}
/* initialize variable */
csv->length = 0;
csv->line2_len = 0;
csv->data_len = 0;
csv->start_line = 11;
csv->item_count = 1;
} else {
if (csv->buffer) {
vfree(csv->buffer);
csv->buffer = NULL;
}
if (csv->line2_buffer) {
vfree(csv->line2_buffer);
csv->line2_buffer = NULL;
}
if (csv->data_buffer) {
vfree(csv->data_buffer);
csv->data_buffer = NULL;
}
}
#endif
return 0;
}
static int fts_test_malloc_free_data_txt(struct fts_test *tdata, bool allocate)
{
if (true == allocate) {
tdata->testresult = vmalloc(TXT_BUFFER_LEN);
if (NULL == tdata->testresult) {
FTS_TEST_ERROR("tdata->testresult malloc fail\n");
return -ENOMEM;
}
tdata->testresult_len = 0;
FTS_TEST_SAVE_INFO("FW version:0x%02x\n", tdata->fw_ver);
FTS_TEST_SAVE_INFO("tx_num:%d, rx_num:%d\n",
tdata->node.tx_num, tdata->node.rx_num);
} else {
if (tdata->testresult) {
vfree(tdata->testresult);
tdata->testresult = NULL;
}
}
return 0;
}
static void fts_test_save_data_csv(struct fts_test *tdata)
{
#if CSV_SUPPORT
struct csv_format *csv = &tdata->csv;
if (!csv || !csv->buffer || !csv->line2_buffer || !csv->data_buffer) {
FTS_TEST_ERROR("csv buffer is null");
return;
}
/* line 1 */
csv->length += snprintf(csv->buffer + csv->length, \
CSV_BUFFER_LEN - csv->length, \
"ECC, 85, 170, IC Name, %s, IC Code, %x\n", \
tdata->ini.ic_name, \
(tdata->ini.ic_code >> IC_CODE_OFFSET));
/* line 2 */
csv->length += snprintf(csv->buffer + csv->length, \
CSV_BUFFER_LEN - csv->length, \
"TestItem Num, %d, ", \
csv->item_count);
if (csv->line2_len > 0) {
memcpy(csv->buffer + csv->length, csv->line2_buffer, csv->line2_len);
csv->length += csv->line2_len;
}
/* line 3 ~ 10 "\n" */
csv->length += snprintf(csv->buffer + csv->length, \
CSV_BUFFER_LEN - csv->length, \
"\n\n\n\n\n\n\n\n\n");
/* line 11 ~ data area */
if (csv->data_len > 0) {
memcpy(csv->buffer + csv->length, csv->data_buffer, csv->data_len);
csv->length += csv->data_len;
}
FTS_TEST_INFO("csv length:%d", csv->length);
fts_test_save_test_data(FTS_CSV_FILE_NAME, csv->buffer, csv->length);
#endif
}
static void fts_test_save_result_txt(struct fts_test *tdata)
{
if (!tdata || !tdata->testresult) {
FTS_TEST_ERROR("test result is null");
return;
}
FTS_TEST_INFO("test result length in txt:%d", tdata->testresult_len);
fts_test_save_test_data(FTS_TXT_FILE_NAME, tdata->testresult, tdata->testresult_len);
}
static int fts_test_malloc_free_incell(struct fts_test *tdata, bool allocate)
{
struct incell_threshold *thr = &tdata->ic.incell.thr;
int buflen = tdata->node.node_num * sizeof(int);
if (true == allocate) {
FTS_TEST_INFO("buflen:%d", buflen);
fts_malloc_r(thr->rawdata_min, buflen);
fts_malloc_r(thr->rawdata_max, buflen);
if (tdata->func->rawdata2_support) {
fts_malloc_r(thr->rawdata2_min, buflen);
fts_malloc_r(thr->rawdata2_max, buflen);
}
fts_malloc_r(thr->cb_min, buflen);
fts_malloc_r(thr->cb_max, buflen);
} else {
fts_free(thr->rawdata_min);
fts_free(thr->rawdata_max);
if (tdata->func->rawdata2_support) {
fts_free(thr->rawdata2_min);
fts_free(thr->rawdata2_max);
}
fts_free(thr->cb_min);
fts_free(thr->cb_max);
}
return 0;
}
static int fts_test_malloc_free_mc_sc(struct fts_test *tdata, bool allocate)
{
struct mc_sc_threshold *thr = &tdata->ic.mc_sc.thr;
int buflen = tdata->node.node_num * sizeof(int);
int buflen_sc = tdata->sc_node.node_num * sizeof(int);
if (true == allocate) {
fts_malloc_r(thr->rawdata_h_min, buflen);
fts_malloc_r(thr->rawdata_h_max, buflen);
if (tdata->func->rawdata2_support) {
fts_malloc_r(thr->rawdata_l_min, buflen);
fts_malloc_r(thr->rawdata_l_max, buflen);
}
fts_malloc_r(thr->tx_linearity_max, buflen);
fts_malloc_r(thr->tx_linearity_min, buflen);
fts_malloc_r(thr->rx_linearity_max, buflen);
fts_malloc_r(thr->rx_linearity_min, buflen);
fts_malloc_r(thr->scap_cb_off_min, buflen_sc);
fts_malloc_r(thr->scap_cb_off_max, buflen_sc);
fts_malloc_r(thr->scap_cb_on_min, buflen_sc);
fts_malloc_r(thr->scap_cb_on_max, buflen_sc);
fts_malloc_r(thr->scap_rawdata_off_min, buflen_sc);
fts_malloc_r(thr->scap_rawdata_off_max, buflen_sc);
fts_malloc_r(thr->scap_rawdata_on_min, buflen_sc);
fts_malloc_r(thr->scap_rawdata_on_max, buflen_sc);
fts_malloc_r(thr->panel_differ_min, buflen);
fts_malloc_r(thr->panel_differ_max, buflen);
} else {
fts_free(thr->rawdata_h_min);
fts_free(thr->rawdata_h_max);
if (tdata->func->rawdata2_support) {
fts_free(thr->rawdata_l_min);
fts_free(thr->rawdata_l_max);
}
fts_free(thr->tx_linearity_max);
fts_free(thr->tx_linearity_min);
fts_free(thr->rx_linearity_max);
fts_free(thr->rx_linearity_min);
fts_free(thr->scap_cb_off_min);
fts_free(thr->scap_cb_off_max);
fts_free(thr->scap_cb_on_min);
fts_free(thr->scap_cb_on_max);
fts_free(thr->scap_rawdata_off_min);
fts_free(thr->scap_rawdata_off_max);
fts_free(thr->scap_rawdata_on_min);
fts_free(thr->scap_rawdata_on_max);
fts_free(thr->panel_differ_min);
fts_free(thr->panel_differ_max);
}
return 0;
}
static int fts_test_malloc_free_sc(struct fts_test *tdata, bool allocate)
{
struct sc_threshold *thr = &tdata->ic.sc.thr;
int buflen = tdata->node.node_num * sizeof(int);
if (true == allocate) {
fts_malloc_r(thr->rawdata_min, buflen);
fts_malloc_r(thr->rawdata_max, buflen);
fts_malloc_r(thr->cb_min, buflen);
fts_malloc_r(thr->cb_max, buflen);
fts_malloc_r(thr->dcb_sort, buflen);
fts_malloc_r(thr->dcb_base, buflen);
} else {
fts_free(thr->rawdata_min);
fts_free(thr->rawdata_max);
fts_free(thr->cb_min);
fts_free(thr->cb_max);
fts_free(thr->dcb_sort);
fts_free(thr->dcb_base);
}
return 0;
}
static int fts_test_malloc_free_thr(struct fts_test *tdata, bool allocate)
{
int ret = 0;
if ((NULL == tdata) || (NULL == tdata->func)) {
FTS_TEST_SAVE_ERR("tdata/func is NULL\n");
return -EINVAL;
}
if (true == allocate) {
fts_malloc_r(tdata->node_valid, tdata->node.node_num * sizeof(int));
fts_malloc_r(tdata->node_valid_sc, tdata->sc_node.node_num * sizeof(int));
} else {
fts_free(tdata->node_valid);
fts_free(tdata->node_valid_sc);
}
switch (tdata->func->hwtype) {
case IC_HW_INCELL:
ret = fts_test_malloc_free_incell(tdata, allocate);
break;
case IC_HW_MC_SC:
ret = fts_test_malloc_free_mc_sc(tdata, allocate);
break;
case IC_HW_SC:
ret = fts_test_malloc_free_sc(tdata, allocate);
break;
default:
FTS_TEST_SAVE_ERR("test ic type(%d) fail\n", tdata->func->hwtype);
ret = -EINVAL;
break;
}
return ret;
}
/* default enable all test item */
static void fts_test_init_item(struct fts_test *tdata)
{
switch (tdata->func->hwtype) {
case IC_HW_INCELL:
tdata->ic.incell.u.tmp = 0xFFFFFFFF;
break;
case IC_HW_MC_SC:
tdata->ic.mc_sc.u.tmp = 0xFFFFFFFF;
break;
case IC_HW_SC:
tdata->ic.sc.u.tmp = 0xFFFFFFFF;
break;
}
}
static int get_tx_rx_num(u8 tx_rx_reg, u8 *ch_num, u8 ch_num_max)
{
int ret = 0;
int i = 0;
for (i = 0; i < 3; i++) {
ret = fts_test_read_reg(tx_rx_reg, ch_num);
if ((ret < 0) || (*ch_num > ch_num_max)) {
sys_delay(50);
} else
break;
}
if (i >= 3) {
FTS_TEST_ERROR("get channel num fail");
return -EIO;
}
return 0;
}
static int get_channel_num(struct fts_test *tdata)
{
int ret = 0;
u8 tx_num = 0;
u8 rx_num = 0;
int key_num = 0;
/* node structure */
if (IC_HW_SC == tdata->func->hwtype) {
ret = get_tx_rx_num(FACTORY_REG_CH_NUM_SC, &tx_num, NUM_MAX_SC);
if (ret < 0) {
FTS_TEST_ERROR("get channel number fail");
return ret;
}
ret = get_tx_rx_num(FACTORY_REG_KEY_NUM_SC, &rx_num, KEY_NUM_MAX);
if (ret < 0) {
FTS_TEST_ERROR("get key number fail");
return ret;
}
tdata->node.tx_num = 2;
tdata->node.rx_num = tx_num / 2;
tdata->node.channel_num = tx_num;
tdata->node.node_num = tx_num;
key_num = rx_num;
} else {
ret = get_tx_rx_num(FACTORY_REG_CHX_NUM, &tx_num, TX_NUM_MAX);
if (ret < 0) {
FTS_TEST_ERROR("get tx_num fail");
return ret;
}
ret = get_tx_rx_num(FACTORY_REG_CHY_NUM, &rx_num, RX_NUM_MAX);
if (ret < 0) {
FTS_TEST_ERROR("get rx_num fail");
return ret;
}
tdata->node.tx_num = tx_num;
tdata->node.rx_num = rx_num;
if (IC_HW_INCELL == tdata->func->hwtype)
tdata->node.channel_num = tx_num * rx_num;
else if (IC_HW_MC_SC == tdata->func->hwtype)
tdata->node.channel_num = tx_num + rx_num;
tdata->node.node_num = tx_num * rx_num;
key_num = tdata->func->key_num_total;
}
/* key */
tdata->node.key_num = key_num;
tdata->node.node_num += tdata->node.key_num;
/* sc node structure */
tdata->sc_node = tdata->node;
if (IC_HW_MC_SC == tdata->func->hwtype) {
if (tdata->v3_pattern) {
ret = get_tx_rx_num(FACTORY_REG_CHX_NUM_NOMAP, &tx_num, TX_NUM_MAX);
if (ret < 0) {
FTS_TEST_ERROR("get no-mappint tx_num fail");
return ret;
}
ret = get_tx_rx_num(FACTORY_REG_CHY_NUM_NOMAP, &rx_num, TX_NUM_MAX);
if (ret < 0) {
FTS_TEST_ERROR("get no-mapping rx_num fail");
return ret;
}
tdata->sc_node.tx_num = tx_num;
tdata->sc_node.rx_num = rx_num;
}
tdata->sc_node.channel_num = tx_num + rx_num;
tdata->sc_node.node_num = tx_num + rx_num;
}
if (tdata->node.tx_num > TX_NUM_MAX) {
FTS_TEST_ERROR("tx num(%d) fail", tdata->node.tx_num);
return -EIO;
}
if (tdata->node.rx_num > RX_NUM_MAX) {
FTS_TEST_ERROR("rx num(%d) fail", tdata->node.rx_num);
return -EIO;
}
FTS_TEST_INFO("node_num:%d, tx:%d, rx:%d", tdata->node.node_num,
tdata->node.tx_num, tdata->node.rx_num);
return 0;
}
static void get_ic_version(struct fts_test *tdata)
{
u8 val[4] = { 0 };
fts_test_read_reg(REG_FW_CHIP_IDH, &val[0]);
fts_test_read_reg(REG_FW_CHIP_IDL, &val[1]);
fts_test_read_reg(REG_FW_IC_TYPE, &val[2]);
fts_test_read_reg(REG_FW_IC_VERSION, &val[3]);
tdata->ic_ver = TEST_IC_VERSION(val[0], val[1], val[2], val[3]);
FTS_TEST_INFO("test ic version:0x%8x", tdata->ic_ver);
}
static int fts_test_init_basicinfo(struct fts_test *tdata)
{
int ret = 0;
u8 val = 0;
if ((NULL == tdata) || (NULL == tdata->func)) {
FTS_TEST_SAVE_ERR("tdata/func is NULL\n");
return -EINVAL;
}
get_ic_version(tdata);
fts_test_read_reg(REG_FW_VERSION, &val);
tdata->fw_ver = val;
if (IC_HW_INCELL == tdata->func->hwtype) {
fts_test_read_reg(REG_VA_TOUCH_THR, &val);
tdata->va_touch_thr = val;
fts_test_read_reg(REG_VKEY_TOUCH_THR, &val);
tdata->vk_touch_thr = val;
}
/* enter factory mode */
ret = enter_factory_mode();
if (ret < 0) {
FTS_TEST_SAVE_ERR("enter factory mode fail\n");
return ret;
}
if (IC_HW_MC_SC == tdata->func->hwtype) {
fts_test_read_reg(FACTORY_REG_PATTERN, &val);
tdata->v3_pattern = (1 == val) ? true : false;
fts_test_read_reg(FACTORY_REG_NOMAPPING, &val);
tdata->mapping = val;
}
/* enter into factory mode and read tx/rx num */
ret = get_channel_num(tdata);
if (ret < 0) {
FTS_TEST_SAVE_ERR("get channel number fail\n");
return ret;
}
return ret;
}
static int fts_test_main_init(void)
{
int ret = 0;
struct fts_test *tdata = fts_ftest;
FTS_TEST_FUNC_ENTER();
/* get basic information: tx/rx num ... */
ret = fts_test_init_basicinfo(tdata);
if (ret < 0) {
FTS_TEST_ERROR("test init basicinfo fail");
return ret;
}
/* allocate memory for test threshold */
ret = fts_test_malloc_free_thr(tdata, true);
if (ret < 0) {
FTS_TEST_ERROR("test malloc for threshold fail");
return ret;
}
/* default enable all test item */
fts_test_init_item(tdata);
/* allocate memory for test data:csv&txt */
ret = fts_test_malloc_free_data_csv(tdata, true);
if (ret < 0) {
FTS_TEST_ERROR("allocate memory for test data(csv) fail");
return ret;
}
ret = fts_test_malloc_free_data_txt(tdata, true);
if (ret < 0) {
FTS_TEST_ERROR("allocate memory for test data(txt) fail");
return ret;
}
/* allocate test data buffer */
tdata->buffer_length = (tdata->node.tx_num + 1) * tdata->node.rx_num;
tdata->buffer_length *= sizeof(int);
FTS_TEST_INFO("test buffer length:%d", tdata->buffer_length);
tdata->buffer = (int *)fts_malloc(tdata->buffer_length);
if (NULL == tdata->buffer) {
FTS_TEST_ERROR("test buffer(%d) malloc fail", tdata->buffer_length);
return -ENOMEM;
}
memset(tdata->buffer, 0, tdata->buffer_length);
FTS_TEST_FUNC_EXIT();
return ret;
}
static int fts_test_main_exit(void)
{
struct fts_test *tdata = fts_ftest;
FTS_TEST_FUNC_ENTER();
fts_test_save_data_csv(tdata);
fts_test_save_result_txt(tdata);
/* free memory */
fts_test_malloc_free_data_txt(tdata, false);
fts_test_malloc_free_data_csv(tdata, false);
fts_test_malloc_free_thr(tdata, false);
/*free test data buffer*/
fts_free(tdata->buffer);
FTS_TEST_FUNC_EXIT();
return 0;
}
/*
* fts_test_get_testparams - get test parameter from ini
*/
static int fts_test_get_testparams(char *config_name)
{
int ret = 0;
ret = fts_test_get_testparam_from_ini(config_name);
return ret;
}
static int fts_test_start(void)
{
int testresult = 0;
struct fts_test *tdata = fts_ftest;
if (tdata && tdata->func && tdata->func->start_test) {
testresult = tdata->func->start_test();
} else {
FTS_TEST_ERROR("test func/start_test func is null");
}
return testresult;
}
/*
* fts_test_entry - test main entry
*
* warning - need disable irq & esdcheck before call this function
*
*/
static int fts_test_entry(char *ini_file_name)
{
int ret = 0;
/* test initialize */
ret = fts_test_main_init();
if (ret < 0) {
FTS_TEST_ERROR("fts_test_main_init fail");
goto test_err;
}
/*Read parse configuration file*/
FTS_TEST_SAVE_INFO("ini_file_name:%s\n", ini_file_name);
ret = fts_test_get_testparams(ini_file_name);
if (ret < 0) {
FTS_TEST_ERROR("get testparam fail");
goto test_err;
}
/* Start testing according to the test configuration */
/* luoguojin ???? */
if (true == fts_test_start()) {
FTS_TEST_SAVE_INFO("\n\n=======Tp test pass.\n");
} else {
FTS_TEST_SAVE_INFO("\n\n=======Tp test failure.\n");
}
ret = 0;
test_err:
fts_test_main_exit();
enter_work_mode();
return ret;
}
/************************************************************************
* Name: fts_test_show
* Brief: no
* Input: device, device attribute, char buf
* Output: no
* Return: EPERM
***********************************************************************/
static ssize_t fts_test_show(struct device *dev, struct device_attribute *attr, char *buf)
{
return -EPERM;
}
/************************************************************************
* Name: fts_test_store
* Brief: upgrade from app.bin
* Input: device, device attribute, char buf, char count
* Output: no
* Return: char count
***********************************************************************/
static ssize_t fts_test_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
char fwname[128] = {0};
struct fts_ts_data *ts_data = fts_data;
struct input_dev *input_dev;
if (ts_data->suspended) {
FTS_INFO("In suspend, no test, return now");
return -EINVAL;
}
input_dev = ts_data->input_dev;
memset(fwname, 0, sizeof(fwname));
sprintf(fwname, "%s", buf);
fwname[count - 1] = '\0';
FTS_TEST_DBG("fwname:%s.", fwname);
mutex_lock(&input_dev->mutex);
disable_irq(ts_data->irq);
#if defined(FTS_ESDCHECK_EN) && (FTS_ESDCHECK_EN)
fts_esdcheck_switch(DISABLE);
#endif
fts_test_entry(fwname);
#if defined(FTS_ESDCHECK_EN) && (FTS_ESDCHECK_EN)
fts_esdcheck_switch(ENABLE);
#endif
enable_irq(ts_data->irq);
mutex_unlock(&input_dev->mutex);
return count;
}
/* test from test.ini
* example:echo "***.ini" > fts_test
*/
static DEVICE_ATTR(fts_test, S_IRUGO | S_IWUSR, fts_test_show, fts_test_store);
/* add your attr in here*/
static struct attribute *fts_test_attributes[] = {
&dev_attr_fts_test.attr,
NULL
};
static struct attribute_group fts_test_attribute_group = {
.attrs = fts_test_attributes
};
static int fts_test_func_init(void)
{
int i = 0;
int j = 0;
int ic_stype = fts_data->ic_info.ids.type;
struct test_funcs *func = NULL;
int func_count = sizeof(test_func_list) / sizeof(test_func_list[0]);
FTS_TEST_INFO("init test function");
if (0 == func_count) {
FTS_TEST_SAVE_ERR("test functions list is NULL, fail\n");
return -ENODATA;
}
fts_ftest = (struct fts_test *)kzalloc(sizeof(*fts_ftest), GFP_KERNEL);
if (NULL == fts_ftest) {
FTS_TEST_ERROR("malloc memory for test fail");
return -ENOMEM;
}
for (i = 0; i < func_count; i++) {
func = test_func_list[i];
for (j = 0; j < FTX_MAX_COMPATIBLE_TYPE; j++) {
if (0 == func->ctype[j])
break;
else if (func->ctype[j] == ic_stype) {
FTS_TEST_INFO("match test function,type:%x", (int)func->ctype[j]);
fts_ftest->func = func;
}
}
}
if (NULL == fts_ftest->func) {
FTS_TEST_ERROR("no test function match, can't test");
return -ENODATA;
}
return 0;
}
int fts_test_init(struct i2c_client *client)
{
int ret = 0;
FTS_TEST_FUNC_ENTER();
/* get test function, must be the first step */
ret = fts_test_func_init();
if (ret < 0) {
FTS_TEST_SAVE_ERR("test functions init fail\n");
return ret;
}
ret = sysfs_create_group(&client->dev.kobj, &fts_test_attribute_group);
if (0 != ret) {
FTS_TEST_ERROR( "[focal] %s() - ERROR: sysfs_create_group() failed.", __func__);
sysfs_remove_group(&client->dev.kobj, &fts_test_attribute_group);
} else {
FTS_TEST_DBG("[focal] %s() - sysfs_create_group() succeeded.", __func__);
}
FTS_TEST_FUNC_EXIT();
return ret;
}
int fts_test_exit(struct i2c_client *client)
{
FTS_TEST_FUNC_ENTER();
sysfs_remove_group(&client->dev.kobj, &fts_test_attribute_group);
fts_free(fts_ftest);
FTS_TEST_FUNC_EXIT();
return 0;
}