blob: 36dab35aebaf26f0d101f976e6ca09c50fcb5426 [file] [log] [blame]
/*
*
* 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_data test_data;
struct test_funcs *test_funcs_list[] = {
&test_func_ft8201,
};
struct test_ic_type ic_types[] = {
{"FT5X22", 6, IC_FT5X46},
{"FT5X46", 6, IC_FT5X46},
{"FT5X46i", 7, IC_FT5X46I},
{"FT5526", 6, IC_FT5526},
{"FT3X17", 6, IC_FT3X17},
{"FT5436", 6, IC_FT5436},
{"FT3X27", 6, IC_FT3X27},
{"FT5526i", 7, IC_FT5526I},
{"FT5416", 6, IC_FT5416},
{"FT5426", 6, IC_FT5426},
{"FT5435", 6, IC_FT5435},
{"FT7681", 6, IC_FT7681},
{"FT7661", 6, IC_FT7661},
{"FT7511", 6, IC_FT7511},
{"FT7421", 6, IC_FT7421},
{"FT7311", 6, IC_FT7311},
{"FT3327DQQ-001", 13, IC_FT3327DQQ_001},
{"FT5446DQS-W01", 13, IC_FT5446DQS_W01},
{"FT5446DQS-W02", 13, IC_FT5446DQS_W02},
{"FT5446DQS-002", 13, IC_FT5446DQS_002},
{"FT5446DQS-Q02", 13, IC_FT5446DQS_Q02},
{"FT6X36", 6, IC_FT6X36},
{"FT3X07", 6, IC_FT3X07},
{"FT6416", 6, IC_FT6416},
{"FT6336G/U", 9, IC_FT6426},
{"FT6236U", 7, IC_FT6236U},
{"FT6436U", 7, IC_FT6436U},
{"FT3267", 6, IC_FT3267},
{"FT3367", 6, IC_FT3367},
{"FT7401", 6, IC_FT7401},
{"FT3407U", 7, IC_FT3407U},
{"FT5822", 6, IC_FT5822},
{"FT5626", 6, IC_FT5626},
{"FT5726", 6, IC_FT5726},
{"FT5826B", 7, IC_FT5826B},
{"FT3617", 6, IC_FT3617},
{"FT3717", 6, IC_FT3717},
{"FT7811", 6, IC_FT7811},
{"FT5826S", 7, IC_FT5826S},
{"FT3517U", 7, IC_FT3517U},
{"FT3518", 6, IC_FT3518},
{"FT3558", 6, IC_FT3558},
{"FT8606", 6, IC_FT8606},
{"FT8716U", 7, IC_FT8716U},
{"FT8716F", 7, IC_FT8716F},
{"FT8716", 6, IC_FT8716},
{"FT8613", 6, IC_FT8613},
{"FT3C47U", 7, IC_FT3C47U},
{"FT8607U", 7, IC_FT8607U},
{"FT8607", 6, IC_FT8607},
{"FT8736", 6, IC_FT8736},
{"FT3D47", 6, IC_FT3D47},
{"FTE716", 6, IC_FTE716},
{"FT8201", 6, IC_FT8201},
{"FT8006M", 7, IC_FT8006M},
{"FT7250", 6, IC_FT7250},
{"FT8006U", 7, IC_FT8006U},
{"FT8719", 6, IC_FT8719},
{"FT8615", 6, IC_FT8615},
{"FT8739", 6, IC_FT8739},
};
/*****************************************************************************
* 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 vmalloc(size);
}
void fts_free_proc(void *p)
{
return vfree(p);
}
/********************************************************************
* test i2c read/write interface
*******************************************************************/
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;
}
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 read_reg(u8 addr, u8 *val)
{
return fts_test_i2c_read(&addr, 1, val, 1);
}
int 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;
}
/********************************************************************
* 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 = read_reg(DEVIDE_MODE_ADDR, &mode);
if ((0 == ret) && (((mode >> 4) & 0x07) == 0x00))
return 0;
for (i = 0; i < ENTER_WORK_FACTORY_RETRIES; i++) {
ret = write_reg(DEVIDE_MODE_ADDR, 0x00);
if (0 == ret) {
for (j = 0; j < 20; j++) {
ret = read_reg(DEVIDE_MODE_ADDR, &mode);
if ((0 == ret) && (((mode >> 4) & 0x07) == 0x00))
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 = read_reg(DEVIDE_MODE_ADDR, &mode);
if ((0 == ret) && (((mode >> 4) & 0x07) == 0x04))
return 0;
for (i = 0; i < ENTER_WORK_FACTORY_RETRIES; i++) {
ret = write_reg(DEVIDE_MODE_ADDR, 0x40);
if (0 == ret) {
for (j = 0; j < 20; j++) {
ret = read_reg(DEVIDE_MODE_ADDR, &mode);
if ((0 == ret) && (((mode >> 4) & 0x07) == 0x04)) {
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;
}
/************************************************************************
* Name: fts_i2c_read_write
* Brief: Write/Read Data by IIC
* Input: writebuf, writelen, readlen
* Output: readbuf
* Return: Comm Code. Code = 0x00 is OK, else fail.
***********************************************************************/
u8 fts_i2c_read_write(unsigned char *writebuf, int writelen, unsigned char *readbuf, int readlen)
{
int ret;
if (readlen > 0) {
ret = fts_test_i2c_read(writebuf, writelen, readbuf, readlen);
} else {
ret = fts_test_i2c_write(writebuf, writelen);
}
if (ret >= 0)
return (ERROR_CODE_OK);
else
return (ERROR_CODE_COMM_ERROR);
}
/*
* 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 reg_addr = 0;
u8 *data = NULL;
int read_num = 0;
int packet_num = 0;
int packet_remainder = 0;
int offset = 0;
data = (u8 *)fts_malloc(byte_num * sizeof(u8));
if (NULL == data) {
FTS_TEST_SAVE_ERR("rawdata buffer malloc fail\n");
return -ENOMEM;
}
/* read rawdata buffer */
FTS_TEST_INFO("mass data len:%d", byte_num);
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) {
read_num = byte_num;
} else {
read_num = BYTES_PER_TIME;
}
FTS_TEST_INFO("packet num:%d, remainder:%d", packet_num, packet_remainder);
reg_addr = addr;
ret = fts_test_i2c_read(&reg_addr, 1, data, read_num);
if (ret) {
FTS_TEST_SAVE_ERR("read rawdata fail\n");
goto READ_MASSDATA_ERR;
}
for (i = 1; i < packet_num; i++) {
offset = read_num * i;
if ((i == (packet_num - 1)) && packet_remainder) {
read_num = packet_remainder;
}
ret = fts_test_i2c_read(NULL, 0, data + offset, read_num);
if (ret) {
FTS_TEST_SAVE_ERR("read much rawdata 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]);
}
READ_MASSDATA_ERR:
if (data) {
fts_free(data);
}
return ret;
}
/*
* chip_clb_incell - auto clb
*/
int chip_clb_incell(void)
{
int ret = 0;
u8 val = 0;
int times = 0;
/* start clb */
ret = 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 = 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;
}
/*
* start_scan_incell - start to scan a frame for incell ic
*/
int start_scan_incell(void)
{
int ret = 0;
u8 val = 0x00;
int times = 0;
ret = read_reg(DEVIDE_MODE_ADDR, &val);
if (ret) {
FTS_TEST_SAVE_ERR("read device mode fail\n");
return ret;
}
/* Top bit position 1, start scan */
val |= 0x80;
ret = write_reg(DEVIDE_MODE_ADDR, val);
if (ret) {
FTS_TEST_SAVE_ERR("write device mode fail\n");
return ret;
}
while (times++ < FACTORY_TEST_RETRY) {
/* Wait for the scan to complete */
sys_delay(FACTORY_TEST_DELAY);
ret = read_reg(DEVIDE_MODE_ADDR, &val);
if ((0 == ret) && (0 == (val >> 7))) {
break;
} else
FTS_TEST_DBG("reg%x=%x,retry:%d", DEVIDE_MODE_ADDR, val, times);
}
if (times >= FACTORY_TEST_RETRY) {
FTS_TEST_SAVE_ERR("start scan timeout\n");
return -EIO;
}
return 0;
}
/*
* wait_state_update - wait fw status update
*/
int wait_state_update(void)
{
int ret = 0;
int times = 0;
u8 state = 0xFF;
while (times++ < FACTORY_TEST_RETRY) {
sys_delay(FACTORY_TEST_RETRY_DELAY);
/* Wait register status update */
state = 0xFF;
ret = read_reg(FACTORY_REG_PARAM_UPDATE_STATE, &state);
if ((0 == ret) && (0x00 == 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;
}
/*
* get_rawdata_incell - read rawdata/diff for incell ic
*/
int get_rawdata_incell(int *data)
{
int ret = 0;
u8 tx_num = 0;
u8 rx_num = 0;
u8 key_num = 0;
int va_num = 0;
FTS_TEST_FUNC_ENTER();
/* enter into factory mode */
ret = enter_factory_mode();
if (ret) {
FTS_TEST_SAVE_ERR("Failed to Enter Factory Mode\n");
return ret;
}
/* get tx/rx num */
tx_num = test_data.screen_param.tx_num;
rx_num = test_data.screen_param.rx_num;
va_num = tx_num * rx_num;
key_num = test_data.screen_param.key_num_total;
/* start to scan a frame */
ret = start_scan_incell();
if (ret) {
FTS_TEST_SAVE_ERR("Failed to Scan ...\n");
return ret;
}
/* Read RawData for va Area */
ret = write_reg(FACTORY_REG_LINE_ADDR, 0xAD);
if (ret) {
FTS_TEST_SAVE_ERR("wirte AD to reg01 fail\n");
return ret;
}
ret = read_mass_data(FACTORY_REG_RAWDATA_ADDR, va_num * 2, data);
if (ret) {
FTS_TEST_SAVE_ERR("Failed to Get RawData of channel.\n");
return ret;
}
/* Read RawData for key Area */
ret = write_reg(FACTORY_REG_LINE_ADDR, 0xAE);
if (ret) {
FTS_TEST_SAVE_ERR("wirte AE to reg01 fail\n");
return ret;
}
ret = read_mass_data(FACTORY_REG_RAWDATA_ADDR, key_num * 2, data + va_num);
if (ret) {
FTS_TEST_SAVE_ERR("Failed to Get RawData of keys.\n");
return ret;
}
FTS_TEST_FUNC_EXIT();
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 = 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 = 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_i2c_read(&cb_addr, 1, 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;
}
/*
* weakshort_get_adc_data_incell - get short(adc) data for incell IC
*/
int weakshort_get_adc_data_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 = write_reg(FACTORY_REG_SHORT_TEST_EN, 0x01);
if (ret) {
FTS_TEST_SAVE_ERR("start short test fail\n");
goto ADC_ERROR;
}
sys_delay(ch_num * FACTORY_TEST_DELAY);
for (times = 0; times < FACTORY_TEST_RETRY; times++) {
ret = read_reg(FACTORY_REG_SHORT_TEST_STATE, &short_state);
if ((0 == ret) && (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_ERROR;
}
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_ERROR:
FTS_TEST_FUNC_EXIT();
return ret;
}
/*
* show_data_incell - show and save test data to testresult.txt
*/
void show_data_incell(int *data, bool include_key)
{
int row = 0;
int col = 0;
int tx_num = test_data.screen_param.tx_num;
int rx_num = test_data.screen_param.rx_num;
int key_num = test_data.screen_param.key_num_total;
FTS_TEST_SAVE_INFO("\nVA Channels: ");
for (row = 0; row < tx_num; row++) {
FTS_TEST_SAVE_INFO("\nCh_%02d: ", row + 1);
for (col = 0; col < rx_num; col++) {
FTS_TEST_SAVE_INFO("%5d, ", data[row * rx_num + col]);
}
}
if (include_key) {
FTS_TEST_SAVE_INFO("\nKeys: ");
for (col = 0; col < key_num; col++) {
FTS_TEST_SAVE_INFO("%5d, ", data[rx_num * tx_num + col]);
}
}
FTS_TEST_SAVE_INFO("\n");
}
/*
* compare_data_incell - check data in range or not
*
* return true if check pass, or return false
*/
bool compare_data_incell(int *data, int min, int max, int vk_min, int vk_max, bool include_key)
{
int row = 0;
int col = 0;
int value = 0;
bool tmp_result = true;
int tx_num = test_data.screen_param.tx_num;
int rx_num = test_data.screen_param.rx_num;
int key_num = test_data.screen_param.key_num_total;
/* VA area */
for (row = 0; row < tx_num; row++) {
for (col = 0; col < rx_num; col++) {
if (0 == test_data.incell_detail_thr.invalid_node[row * rx_num + col])
continue; /* Invalid Node */
value = data[row * rx_num + col];
if (value < min || value > max) {
tmp_result = false;
FTS_TEST_SAVE_INFO("test failure. Node=(%d, %d), \
Get_value=%d, Set_Range=(%d, %d)\n", \
row + 1, col + 1, value, min, max);
}
}
}
/* Key area */
if (include_key) {
if (test_data.screen_param.key_flag) {
key_num = test_data.screen_param.key_num;
}
row = test_data.screen_param.tx_num;
for (col = 0; col < key_num; col++) {
if (0 == test_data.incell_detail_thr.invalid_node[tx_num * rx_num + col])
continue; /* Invalid Node */
value = data[rx_num * tx_num + col];
if (value < vk_min || value > vk_max) {
tmp_result = false;
FTS_TEST_SAVE_INFO("test failure. Node=(%d, %d), \
Get_value=%d, Set_Range=(%d, %d)\n", \
row + 1, col + 1, value, vk_min, vk_max);
}
}
}
return tmp_result;
}
/************************************************************************
* Name: compare_detailthreshold_data_incell
* Brief: compare_detailthreshold_data_incell
* Input: none
* Output: none
* Return: none.
***********************************************************************/
bool compare_detailthreshold_data_incell(int *data, int *data_min, int *data_max, bool include_key)
{
int row, col;
int value;
bool tmp_result = true;
int tmp_min, tmp_max;
int rx_num = test_data.screen_param.rx_num;
int tx_num = test_data.screen_param.tx_num;
int key_num = test_data.screen_param.key_num_total;
// VA
for (row = 0; row < tx_num; row++) {
for (col = 0; col < rx_num; col++) {
if (test_data.incell_detail_thr.invalid_node[row * rx_num + col] == 0)continue; //Invalid Node
tmp_min = data_min[row * rx_num + col];
tmp_max = data_max[row * rx_num + col];
value = data[row * rx_num + col];
if (value < tmp_min || value > tmp_max) {
tmp_result = false;
FTS_TEST_SAVE_INFO(" \n test failure. Node=(%d, %d), Get_value=%d, Set_Range=(%d, %d)", \
row + 1, col + 1, value, tmp_min, tmp_max);
}
}
}
// Key
if (include_key) {
if (test_data.screen_param.key_flag) {
key_num = test_data.screen_param.key_num;
}
row = test_data.screen_param.tx_num;
for ( col = 0; col < key_num; col++ ) {
if (test_data.incell_detail_thr.invalid_node[rx_num * tx_num + col] == 0)continue; //Invalid Node
tmp_min = data_min[rx_num * tx_num + col];
tmp_max = data_max[rx_num * tx_num + col];
value = data[rx_num * tx_num + col];
if (value < tmp_min || value > tmp_max) {
tmp_result = false;
FTS_TEST_SAVE_INFO(" \n test failure. Node=(%d, %d), Get_value=%d, Set_Range=(%d, %d)", \
row + 1, col + 1, value, tmp_min, tmp_max);
}
}
}
return tmp_result;
}
/*
* save_testdata_incell - save data to testdata.csv
*/
void save_testdata_incell(int *data, char *test_num, int index, u8 row, u8 col, u8 item_count)
{
int len = 0;
int i = 0, j = 0;
FTS_TEST_FUNC_ENTER();
/* Save Msg */
len = snprintf(test_data.tmp_buffer, BUFF_LEN_TMP_BUFFER, \
"%s, %d, %d, %d, %d, %d, ", \
test_num, test_data.test_item_code, row, col, \
test_data.start_line, item_count);
memcpy(test_data.msg_area_line2 + test_data.len_msg_area_line2, test_data.tmp_buffer, len);
test_data.len_msg_area_line2 += len;
test_data.start_line += row;
test_data.test_data_count++;
/* Save Data */
for (i = 0 + index; (i < row + index) && (i < TX_NUM_MAX); i++) {
for (j = 0; (j < col) && (j < RX_NUM_MAX); j++) {
if (j == (col - 1)) {
/* The Last Data of the row, add "\n" */
len = snprintf(test_data.tmp_buffer, BUFF_LEN_TMP_BUFFER, \
"%d, \n", data[col * (i + index) + j]);
} else {
len = snprintf(test_data.tmp_buffer, BUFF_LEN_TMP_BUFFER, \
"%d, ", data[col * (i + index) + j]);
}
memcpy(test_data.store_data_area + test_data.len_store_data_area, test_data.tmp_buffer, len);
test_data.len_store_data_area += len;
}
}
FTS_TEST_FUNC_EXIT();
}
/*
* fts_ic_table_get_ic_code_from_ic_name - get ic code from ic name
*/
u32 fts_ic_table_get_ic_code_from_ic_name(char *ic_name)
{
int i = 0;
int type_size = 0;
type_size = sizeof(ic_types) / sizeof(ic_types[0]);
for (i = 0; i < type_size; i++) {
if (0 == strncmp(ic_name, ic_types[i].ic_name, ic_types[i].len))
return ic_types[i].ic_type;
}
FTS_TEST_ERROR("no IC type match");
return 0;
}
/*
* init_test_funcs - get test function based on ic_type
*/
int init_test_funcs(u32 ic_type)
{
int i = 0;
struct test_funcs *funcs = test_funcs_list[0];
int funcs_len = sizeof(test_funcs_list) / sizeof(test_funcs_list[0]);
u32 ic_series = 0;
ic_series = TEST_ICSERIES(ic_type);
FTS_TEST_INFO("ic_type:%x, test functions len:%x", ic_type, funcs_len);
for (i = 0; i < funcs_len; i++) {
funcs = test_funcs_list[i];
if (ic_series == funcs->ic_series) {
test_data.func = funcs;
break;
}
}
if (i >= funcs_len) {
FTS_TEST_ERROR("no ic serial function match");
return -ENODATA;
}
return 0;
}
/*
* 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;
}
/************************************************************************
* Name: fts_set_testitem
* Brief: set test item code and name
* Input: null
* Output: null
* Return:
**********************************************************************/
void fts_set_testitem(u8 itemcode)
{
test_data.test_item[test_data.test_num].itemcode = itemcode;
test_data.test_item[test_data.test_num].testnum = test_data.test_num;
test_data.test_item[test_data.test_num].testresult = RESULT_NULL;
test_data.test_num++;
}
/************************************************************************
* Name: merge_all_testdata
* Brief: Merge All Data of test result
* Input: none
* Output: none
* Return: none
***********************************************************************/
void merge_all_testdata(void)
{
int len = 0;
//Msg Area, Add Line1
test_data.len_store_msg_area += sprintf(test_data.store_msg_area, "ECC, 85, 170, IC Name, %s, IC Code, %x\n", test_data.ini_ic_name, test_data.screen_param.selected_ic);
/* Add the head part of Line2 */
len = sprintf(test_data.tmp_buffer, "TestItem Num, %d, ", test_data.test_data_count);
memcpy(test_data.store_msg_area + test_data.len_store_msg_area, test_data.tmp_buffer, len);
test_data.len_store_msg_area += len;
/* Add other part of Line2, except for "\n" */
memcpy(test_data.store_msg_area + test_data.len_store_msg_area, test_data.msg_area_line2, test_data.len_msg_area_line2);
test_data.len_store_msg_area += test_data.len_msg_area_line2;
/* Add Line3 ~ Line10 */
len = sprintf(test_data.tmp_buffer, "\n\n\n\n\n\n\n\n\n");
memcpy(test_data.store_msg_area + test_data.len_store_msg_area, test_data.tmp_buffer, len);
test_data.len_store_msg_area += len;
/* 1.Add Msg Area */
memcpy(test_data.store_all_data, test_data.store_msg_area, test_data.len_store_msg_area);
/* 2.Add Data Area */
if (0 != test_data.len_store_data_area) {
memcpy(test_data.store_all_data + test_data.len_store_msg_area, test_data.store_data_area, test_data.len_store_data_area);
}
FTS_TEST_DBG("lenStoreMsgArea=%d, lenStoreDataArea = %d", test_data.len_store_msg_area, test_data.len_store_data_area);
}
void init_storeparam_testdata(void)
{
test_data.testresult_len = 0;
test_data.len_store_msg_area = 0;
test_data.len_msg_area_line2 = 0;
test_data.len_store_data_area = 0;
/* The Start Line of Data Area is 11 */
test_data.start_line = 11;
test_data.test_data_count = 0;
}
int allocate_init_testdata_memory(void)
{
test_data.testresult = fts_malloc(BUFF_LEN_TESTRESULT_BUFFER);
if (NULL == test_data.testresult)
goto ERR;
test_data.store_all_data = fts_malloc(FTS_TEST_STORE_DATA_SIZE);
if (NULL == test_data.store_all_data)
goto ERR;
test_data.store_msg_area = fts_malloc(BUFF_LEN_STORE_MSG_AREA);
if (NULL == test_data.store_msg_area)
goto ERR;
test_data.msg_area_line2 = fts_malloc(BUFF_LEN_MSG_AREA_LINE2);
if (NULL == test_data.msg_area_line2)
goto ERR;
test_data.store_data_area = fts_malloc(BUFF_LEN_STORE_DATA_AREA);
if (NULL == test_data.store_data_area)
goto ERR;
test_data.tmp_buffer = fts_malloc(BUFF_LEN_TMP_BUFFER);
if (NULL == test_data.tmp_buffer)
goto ERR;
init_storeparam_testdata();
return 0;
ERR:
FTS_TEST_ERROR("fts_malloc memory failed in function.");
return -ENOMEM;
}
/************************************************************************
* Name: free_testdata_memory
* Brief: Release pointer memory
* Input: none
* Output: none
* Return: none
***********************************************************************/
void free_testdata_memory(void)
{
/* free buff */
if (NULL != test_data.testresult)
fts_free(test_data.testresult);
if (NULL != test_data.store_all_data)
fts_free(test_data.store_all_data);
if (NULL != test_data.store_msg_area)
fts_free(test_data.store_msg_area);
if (NULL != test_data.msg_area_line2)
fts_free(test_data.msg_area_line2);
if (NULL != test_data.store_data_area)
fts_free(test_data.store_data_area);
if (NULL != test_data.tmp_buffer)
fts_free(test_data.tmp_buffer);
}
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 = 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;
}
int get_channel_num(void)
{
int ret = 0;
u8 tx_num = 0;
u8 rx_num = 0;
FTS_TEST_FUNC_ENTER();
ret = enter_factory_mode();
if (ret < 0) {
FTS_TEST_ERROR("enter factory mode fail, can't get tx/rx num");
return ret;
}
test_data.screen_param.used_max_tx_num = TX_NUM_MAX;
test_data.screen_param.used_max_rx_num = RX_NUM_MAX;
test_data.screen_param.key_num_total = KEY_NUM_MAX;
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;
}
test_data.screen_param.tx_num = (int)tx_num;
test_data.screen_param.rx_num = (int)rx_num;
FTS_TEST_INFO("TxNum=%d, RxNum=%d, MaxTxNum=%d, MaxRxNum=%d",
test_data.screen_param.tx_num,
test_data.screen_param.rx_num,
test_data.screen_param.used_max_tx_num,
test_data.screen_param.used_max_rx_num);
FTS_TEST_FUNC_EXIT();
return 0;
}
static int fts_test_init_basicinfo(void)
{
int ret = 0;
u8 val = 0;
ret = read_reg(REG_FW_VERSION, &val);
FTS_TEST_SAVE_INFO("FW version:0x%02x\n", val);
ret = read_reg(REG_VA_TOUCH_THR, &val);
test_data.va_touch_thr = val;
ret = read_reg(REG_VKEY_TOUCH_THR, &val);
test_data.key_touch_thr = val;
/* enter into factory mode and read tx/rx num */
ret = get_channel_num();
FTS_TEST_SAVE_INFO("tx_num:%d, rx_num:%d\n",
test_data.screen_param.tx_num,
test_data.screen_param.rx_num);
return ret;
}
static int fts_test_main_init(void)
{
int ret = 0;
int len = 0;
FTS_TEST_FUNC_ENTER();
/* allocate memory for test data:csv&txt */
ret = allocate_init_testdata_memory();
if (ret < 0) {
FTS_TEST_ERROR("allocate memory for test data fail");
return ret;
}
/* get basic information: tx/rx num */
ret = fts_test_init_basicinfo();
if (ret < 0) {
FTS_TEST_ERROR("test init basicinfo fail");
return ret;
}
/* Allocate memory for detail threshold structure */
ret = malloc_struct_DetailThreshold();
if (ret < 0) {
FTS_TEST_ERROR("Failed to malloc memory for detaithreshold");
return ret;
}
/*Allocate test data buffer*/
len = (test_data.screen_param.tx_num + 1) * test_data.screen_param.rx_num;
test_data.buffer = (int *)fts_malloc(len * sizeof(int));
if (NULL == test_data.buffer) {
FTS_TEST_ERROR("test_data.buffer malloc fail");
return -ENOMEM;
}
memset(test_data.buffer, 0, len * sizeof(int));
FTS_TEST_FUNC_EXIT();
return ret;
}
/*
* 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 bool fts_test_start(void)
{
bool testresult = false;
FTS_TEST_FUNC_ENTER();
FTS_TEST_DBG("IC_%s Test", test_data.ini_ic_name);
if (test_data.func && test_data.func->start_test) {
testresult = test_data.func->start_test();
} else {
FTS_TEST_ERROR("test func/start_test func is null");
testresult = false;
}
FTS_TEST_FUNC_EXIT();
return testresult;
}
static int fts_test_main_exit(void)
{
int data_len = 0;
FTS_TEST_FUNC_ENTER();
/* Merge test data */
merge_all_testdata();
/*Gets the number of tests in the test library and saves it*/
data_len = test_data.len_store_msg_area + test_data.len_store_data_area;
fts_test_save_test_data(FTS_TESTDATA_FILE_NAME, test_data.store_all_data, data_len);
fts_test_save_test_data(FTS_TESTRESULT_FILE_NAME, test_data.testresult, test_data.testresult_len);
/* free memory */
free_struct_DetailThreshold();
free_testdata_memory();
/*free test data buffer*/
if (test_data.buffer)
fts_free(test_data.buffer);
FTS_TEST_FUNC_EXIT();
return 0;
}
/*
* 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;
FTS_TEST_FUNC_ENTER();
/* test initialize */
ret = fts_test_main_init();
if (ret < 0) {
FTS_TEST_ERROR("fts_test_main_init() error.");
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 failed");
goto TEST_ERR;
}
/* Start testing according to the test configuration */
if (true == fts_test_start()) {
FTS_TEST_SAVE_INFO("\n=======Tp test pass. \n\n");
} else {
FTS_TEST_SAVE_INFO("\n=======Tp test failure. \n\n");
}
ret = 0;
TEST_ERR:
enter_work_mode();
fts_test_main_exit();
FTS_TEST_FUNC_EXIT();
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;
FTS_TEST_FUNC_ENTER();
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);
FTS_TEST_FUNC_EXIT();
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
};
int fts_test_init(struct i2c_client *client)
{
int ret = 0;
FTS_TEST_FUNC_ENTER();
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_TEST_FUNC_EXIT();
return 0;
}