blob: c3540cdcb0e6fff24ddfdf89f1c84f9df27f630f [file] [log] [blame]
/*
*
**************************************************************************
** STMicroelectronics **
**************************************************************************
* *
* FTS API for MP test *
* *
**************************************************************************
**************************************************************************
*
*/
/*!
* \file ftsTest.c
* \brief Contains all the functions related to the Mass Production Test
*/
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <stdarg.h>
#include <linux/serio.h>
#include <linux/time.h>
#include <linux/delay.h>
#include <linux/ctype.h>
#include <linux/firmware.h>
#include "fts_test.h"
#include "fts_error.h"
#ifdef LIMITS_H_FILE
#include "../fts_limits.h"
#endif
extern struct sys_info system_info;
struct test_to_do tests;/* /< global variable that specify the tests to
* perform during the Mass Production Test */
static struct limit_file limit_file;/* /< variable which contains the limit file
* during test */
/**
* Initialize the testToDo variable with the default tests to perform during
* the Mass Production Test
* @return OK
*/
int init_test_to_do(void)
{
/*** Initialize Limit File ***/
limit_file.size = 0;
limit_file.data = NULL;
strlcpy(limit_file.name, " ", MAX_LIMIT_FILE_NAME);
tests.mutual_ito_raw = 1;
tests.mutual_ito_raw_adj = 1;
tests.mutual_raw = 1;
tests.mutual_raw_lp = 1;
tests.self_force_raw = 1;
tests.self_force_raw_lp = 0;
tests.self_sense_raw = 1;
tests.self_sense_raw_lp = 1;
tests.mutual_cx_lp = 1;
tests.mutual_cx_lp_adj = 1;
tests.self_force_ix = 1;
tests.self_force_ix_lp = 0;
tests.self_sense_ix = 1;
tests.self_sense_ix_lp = 1;
return OK;
}
/**
* Compute the Horizontal adjacent matrix of short values doing the abs of
* the difference between the column i with the i-1 one.
* Both the original data matrix and the adj matrix are disposed as 1 dimension
* array one row after the other \n
* The resulting matrix has one column less than the starting original one \n
* @param data pointer to the array of signed bytes containing the original
* data
* @param row number of rows of the original data
* @param column number of columns of the original data
* @param result pointer of a pointer to an array of unsigned bytes which
* will contain the adj matrix
* @return OK if success or an error code which specify the type of error
*/
int compute_adj_horiz_total(short *data, int row, int column, u16 **result)
{
int i, j;
int size = row * (column - 1);
if (column < 2) {
pr_err("%s: ERROR %08X\n", __func__, ERROR_OP_NOT_ALLOW);
return ERROR_OP_NOT_ALLOW;
}
*result = (u16 *)kmalloc(size * sizeof(u16), GFP_KERNEL);
if (*result == NULL) {
pr_err("%s: ERROR %08X\n", __func__, ERROR_ALLOC);
return ERROR_ALLOC;
}
for (i = 0; i < row; i++)
for (j = 1; j < column; j++)
*(*result + (i * (column - 1) + (j - 1))) =
abs(data[i * column + j] - data[i * column + (j - 1)]);
return OK;
}
/**
* Compute the Vertical adjacent matrix of short values doing the abs of
* the difference between the row i with the i-1 one.
* Both the original data matrix and the adj matrix are disposed as 1 dimension
* array one row after the other. \n
* The resulting matrix has one column less than the starting original one \n
* @param data pointer to the array of signed bytes containing the original
* data
* @param row number of rows of the original data
* @param column number of columns of the original data
* @param result pointer of a pointer to an array of unsigned bytes which will
* contain the adj matrix
* @return OK if success or an error code which specify the type of error
*/
int compute_adj_vert_total(short *data, int row, int column, u16 **result)
{
int i, j;
int size = (row - 1) * (column);
if (row < 2) {
pr_err("%s: ERROR %08X\n", __func__, ERROR_OP_NOT_ALLOW);
return ERROR_OP_NOT_ALLOW;
}
*result = (u16 *)kmalloc(size * sizeof(u16), GFP_KERNEL);
if (*result == NULL) {
pr_err("%s: ERROR %08X\n", __func__, ERROR_ALLOC);
return ERROR_ALLOC;
}
for (i = 1; i < row; i++)
for (j = 0; j < column; j++)
*(*result + ((i - 1) * column + j)) =
abs(data[i * column + j] - data[(i - 1) * column + j]);
return OK;
}
/**
* Check that each value of a matrix of u16 doesn't exceed a specific Max value
* set for each node (max value is included in the interval).
* The matrixes of data and max values are stored as 1 dimension arrays one row
* after the other.
* @param data pointer to the array of short containing the data to check
* @param row number of rows of data
* @param column number of columns of data
* @param max pointer to a matrix which specify the Maximum value allowed for
* each node
* @return the number of elements that overcome the specified interval (0 = OK)
*/
int check_limits_map_adj_total(u16 *data, int row, int column, int *max)
{
int i, j;
int count = 0;
for (i = 0; i < row; i++) {
for (j = 0; j < column; j++) {
if (data[i * column + j] > max[i * column + j]) {
pr_err("%s: Node[%d,%d] = %d exceed limit > %d\n",
__func__, i, j, data[i * column + j], max[i *
column + j]);
count++;
}
}
}
return count;
}
/**
* Check that each value of a matrix of short doesn't exceed a specific min and
* Max value set for each node (these values are included in the interval).
* The matrixes of data, min and max values are stored as 1 dimension arrays
* one row after the other.
* @param data pointer to the array of short containing the data to check
* @param row number of rows of data
* @param column number of columns of data
* @param min pointer to a matrix which specify the minimum value allowed for
* each node
* @param max pointer to a matrix which specify the Maximum value allowed for
* each node
* @return the number of elements that overcome the specified interval (0 = OK)
*/
int check_limits_map_total(short *data, int row, int column,
int *min, int *max)
{
int i, j;
int count = 0;
for (i = 0; i < row; i++) {
for (j = 0; j < column; j++) {
if (data[i * column + j] < min[i * column + j] ||
data[i * column + j] > max[i * column + j]) {
pr_info("%s: Node[%d,%d] = %d exceed limit [%d, %d]\n",
__func__, i, j, data[i * column + j],
min[i *
column
+ j], max[i * column + j]);
count++;
}
}
}
return count; /* if count is 0 = OK, test completed successfully */
}
/**
* Print in the kernel log a label followed by a matrix of i8 row x columns and
* free its memory
* @param label pointer to the string to print before the actual matrix
* @param matrix reference to the matrix of u8 which contain the actual data
* @param row number of rows on which the matrix should be print
* @param column number of columns for each row
*/
void print_frame_i8(char *label, i8 **matrix, int row, int column)
{
int i, j;
int buff_len, index;
char *buff;
pr_info("%s\n", label);
if (matrix == NULL)
return;
buff_len = (4 + 1) * column + 1; /* -128 str len: 4 */
buff = kzalloc(buff_len, GFP_KERNEL);
if (buff == NULL) {
pr_err("%s: fail to allocate buffer\n", __func__);
return;
}
for (i = 0; i < row; i++) {
if (!matrix[i])
break;
index = 0;
for (j = 0; j < column; j++)
index += scnprintf(buff + index, buff_len - index,
"%d ", matrix[i][j]);
pr_info("%s\n", buff);
kfree(matrix[i]);
}
kfree(matrix);
kfree(buff);
}
/**
* Print in the kernel log a label followed by a matrix of short row x columns
*and free its memory
* @param label pointer to the string to print before the actual matrix
* @param matrix reference to the matrix of short which contain the actual data
* @param row number of rows on which the matrix should be print
* @param column number of columns for each row
*/
void print_frame_short(char *label, short **matrix, int row, int column)
{
int i, j;
int buff_len, index;
char *buff;
pr_info("%s\n", label);
if (matrix == NULL)
return;
buff_len = (6 + 1) * column + 1; /* -32768 str len: 6 */
buff = kzalloc(buff_len, GFP_KERNEL);
if (buff == NULL) {
pr_err("%s: fail to allocate buffer\n", __func__);
return;
}
for (i = 0; i < row; i++) {
if (!matrix[i])
break;
index = 0;
for (j = 0; j < column; j++)
index += scnprintf(buff + index, buff_len - index,
"%d ", matrix[i][j]);
pr_info("%s\n", buff);
kfree(matrix[i]);
}
kfree(matrix);
kfree(buff);
}
/**
* Print in the kernel log a label followed by a matrix of u16 row x columns
* and free its memory
* @param label pointer to the string to print before the actual matrix
* @param matrix reference to the matrix of u16 which contain the actual data
* @param row number of rows on which the matrix should be print
* @param column number of columns for each row
*/
void print_frame_u16(char *label, u16 **matrix, int row, int column)
{
int i, j;
int buff_len, index;
char *buff;
pr_info("%s\n", label);
if (matrix == NULL)
return;
buff_len = (5 + 1) * column + 1; /* 65535 str len: 5 */
buff = kzalloc(buff_len, GFP_KERNEL);
if (buff == NULL) {
pr_err("%s: fail to allocate buffer\n", __func__);
return;
}
for (i = 0; i < row; i++) {
if (!matrix[i])
break;
index = 0;
for (j = 0; j < column; j++)
index += scnprintf(buff + index, buff_len - index,
"%d ", matrix[i][j]);
pr_info("%s\n", buff);
kfree(matrix[i]);
}
kfree(matrix);
kfree(buff);
}
/**
* Transform an array of i8 in a matrix of i8 with a defined number of
* columns and the resulting number of rows
* @param data array of bytes to convert
* @param size size of data
* @param columns number of columns that the resulting matrix should have.
* @return a reference to a matrix of short where for each row there are
* columns elements
* @warning If size = 0 it will be allocated a matrix 1*1 wich still should
* be free
*/
i8 **array_1d_to_2d_i8(i8 *data, int size, int columns)
{
int i;
i8 **matrix = NULL;
if (size == 0) {
matrix = (i8 **)kmalloc(1 *
sizeof(i8 *), GFP_KERNEL);
matrix[0] = (i8 *)kmalloc(0 *
sizeof(i8), GFP_KERNEL);
} else {
matrix = (i8 **)kmalloc(((int)(size / columns)) * sizeof(i8 *),
GFP_KERNEL);
if (matrix != NULL) {
for (i = 0; i < (int)(size / columns); i++)
matrix[i] = (i8 *)kmalloc(columns * sizeof(i8),
GFP_KERNEL);
for (i = 0; i < size; i++)
matrix[i / columns][i % columns] = data[i];
}
}
return matrix;
}
/**
* Transform an array of short in a matrix of short with a defined number of
* columns and the resulting number of rows
* @param data array of bytes to convert
* @param size size of data
* @param columns number of columns that the resulting matrix should have.
* @return a reference to a matrix of short where for each row there are
* columns elements
* @warning If size = 0 it will be allocated a matrix 1*1 wich still should
* be free
*/
short **array_1d_to_2d_short(short *data, int size, int columns)
{
int i;
short **matrix = NULL;
if (size == 0) {
matrix = (short **)kmalloc(1 *
sizeof(short *), GFP_KERNEL);
matrix[0] = (short *)kmalloc(0 *
sizeof(short), GFP_KERNEL);
} else {
matrix = (short **)kmalloc(((int)(size / columns)) *
sizeof(short *), GFP_KERNEL);
if (matrix != NULL) {
for (i = 0; i < (int)(size / columns); i++)
matrix[i] = (short *)kmalloc(columns *
sizeof(short), GFP_KERNEL);
for (i = 0; i < size; i++)
matrix[i / columns][i % columns] = data[i];
}
}
return matrix;
}
/**
* Transform an array of u16 in a matrix of u16 with a defined number of
* columns and the resulting number of rows
* @param data array of bytes to convert
* @param size size of data
* @param columns number of columns that the resulting matrix should have.
* @return a reference to a matrix of short where for each row there are
* columns elements
* @warning If size = 0 it will be allocated a matrix 1*1 wich still should
* be free
*/
u16 **array_1d_to_2d_u16(u16 *data, int size, int columns)
{
int i;
u16 **matrix = NULL;
if (size == 0) {
matrix = (u16 **)kmalloc(1 *
sizeof(u16 *), GFP_KERNEL);
matrix[0] = (u16 *)kmalloc(0 *
sizeof(u16), GFP_KERNEL);
} else {
matrix = (u16 **)kmalloc(((int)(size / columns)) *
sizeof(u16 *), GFP_KERNEL);
if (matrix != NULL) {
for (i = 0; i < (int)(size / columns); i++)
matrix[i] = (u16 *)kmalloc(columns *
sizeof(u16), GFP_KERNEL);
for (i = 0; i < size; i++)
matrix[i / columns][i % columns] = data[i];
}
}
return matrix;
}
/**
* Retrieve the actual Test Limit data from the system (bin file or header
*file)
* @param path name of Production Test Limit file to load or "NULL" if the
*limits data should be loaded by a .h file
* @param file pointer to the LimitFile struct which will contains the limits
*data
* @return OK if success or an error code which specify the type of error
*encountered
*/
int get_limits_file(char *path, struct limit_file *file)
{
const struct firmware *fw = NULL;
struct device *dev = NULL;
int fd = -1;
pr_info("%s: Get Limits File starting... %s\n", __func__, path);
if (file->data != NULL) {/* to avoid memory leak on consecutive call of
* the function with the same pointer */
pr_debug("%s: Pointer to Limits Data already contains something..."
"freeing its content!\n", __func__);
kfree(file->data);
file->data = NULL;
file->size = 0;
}
strlcpy(file->name, path, MAX_LIMIT_FILE_NAME);
if (strncmp(path, "NULL", 4) == 0) {
#ifdef LIMITS_H_FILE
pr_info("%s: Loading Limits File from .h!\n", __func__);
file->size = LIMITS_SIZE_NAME;
file->data = (char *)kmalloc((file->size) * sizeof(char),
GFP_KERNEL);
if (file->data != NULL) {
memcpy(file->data, (char *)(LIMITS_ARRAY_NAME),
file->size);
return OK;
} else {
pr_err("%s: Error while allocating data... ERROR %08X\n",
__func__, path, ERROR_ALLOC);
return ERROR_ALLOC;
}
#else
pr_err("%s: limit file path NULL... ERROR %08X\n",
__func__, ERROR_FILE_NOT_FOUND);
return ERROR_FILE_NOT_FOUND;
#endif
} else {
dev = get_dev();
if (dev != NULL) {
pr_info("%s: Loading Limits File from .csv!\n", __func__);
fd = request_firmware(&fw, path, dev);
if (fd == 0) {
pr_info("%s: Start to copy %s...\n",
__func__, path);
file->size = fw->size;
file->data = (char *)kmalloc((file->size) *
sizeof(char),
GFP_KERNEL);
if (file->data != NULL) {
memcpy(file->data, (char *)fw->data,
file->size);
pr_debug("%s: Limit file Size = %d\n",
__func__, file->size);
release_firmware(fw);
return OK;
}
pr_err("%s: Error while allocating data... ERROR %08X\n",
__func__, ERROR_ALLOC);
release_firmware(fw);
return ERROR_ALLOC;
}
pr_err("%s: Request the file %s failed... ERROR %08X\n",
__func__, path, ERROR_FILE_NOT_FOUND);
return ERROR_FILE_NOT_FOUND;
}
pr_err("%s: Error while getting the device ERROR %08X\n",
__func__, ERROR_FILE_READ);
return ERROR_FILE_READ;
}
}
/**
* Reset and release the memory which store a Production Limit File previously
*loaded
* @param file pointer to the LimitFile struct to free
* @return OK if success or an error code which specify the type of error
*encountered
*/
int free_limits_file(struct limit_file *file)
{
pr_debug("%s: Freeing Limit File ...\n", __func__);
if (file != NULL) {
if (file->data != NULL) {
kfree(file->data);
file->data = NULL;
} else
pr_debug("%s: Limit File was already freed!\n",
__func__);
file->size = 0;
strlcpy(file->name, " ", MAX_LIMIT_FILE_NAME);
return OK;
}
pr_err("%s: Passed a NULL argument! ERROR %08X\n",
__func__, ERROR_OP_NOT_ALLOW);
return ERROR_OP_NOT_ALLOW;
}
/**
* Reset and release the memory which store the current Limit File previously
*loaded
* @return OK if success or an error code which specify the type of error
*encountered
*/
int free_current_limits_file(void)
{
return free_limits_file(&limit_file);
}
/**
* Parse the raw data read from a Production test limit file in order to find
*the specified information
* If no limits file data are passed, the function loads and stores the limit
*file from the system
* @param path name of Production Test Limit file to load or "NULL" if the
*limits data should be loaded by a .h file
* @param file pointer to LimitFile struct that should be parsed or NULL if the
*limit file in the system should be loaded and then parsed
* @param label string which identify a particular set of data in the file that
*want to be loaded
* @param data pointer to the pointer which will contains the specified limits
*data as 1 dimension matrix with data arranged row after row
* @param row pointer to a int variable which will contain the number of row of
*data
* @param column pointer to a int variable which will contain the number of
*column of data
* @return OK if success or an error code which specify the type of error
*/
int parse_production_test_limits(char *path, struct limit_file *file,
char *label, int **data, int *row, int *column)
{
int find = 0;
char *token = NULL;
int i = 0;
int j = 0;
int z = 0;
char *line2 = NULL;
char line[800];
char *buf = NULL;
int n, size, pointer = 0, ret = OK;
char *data_file = NULL;
if (file == NULL || strcmp(path, file->name) != 0 || file->size == 0) {
pr_info("%s: No limit File data passed...try to get them from the system!\n",
__func__);
ret = get_limits_file(LIMITS_FILE, &limit_file);
if (ret < OK) {
pr_err("%s: ERROR %08X\n",
__func__, ERROR_FILE_NOT_FOUND);
return ERROR_FILE_NOT_FOUND;
}
size = limit_file.size;
data_file = limit_file.data;
} else {
pr_info("%s: Limit File data passed as arguments!\n", __func__);
size = file->size;
data_file = file->data;
}
pr_info("%s: The size of the limits file is %d bytes...\n",
__func__, size);
while (find == 0) {
if (read_line(&data_file[pointer], line, size - pointer, &n) <
0) {
find = -1;
break;
}
pointer += n;
if (line[0] == '*') {
line2 = kstrdup(line, GFP_KERNEL);
if (line2 == NULL) {
pr_err("%s: kstrdup ERROR %08X\n",
__func__, ERROR_ALLOC);
ret = ERROR_ALLOC;
goto END;
}
buf = line2;
line2 += 1;
token = strsep(&line2, ",");
if (strcmp(token, label) == 0) {
find = 1;
token = strsep(&line2, ",");
if (token != NULL) {
if (sscanf(token, "%d", row) == 1)
pr_debug("%s: Row = %d\n",
__func__, *row);
else {
pr_debug("%s: ERROR while reading "
"the row value!ERROR %08X\n",
__func__, ERROR_FILE_PARSE);
ret = ERROR_FILE_PARSE;
goto END;
}
} else {
pr_err("%s: Row ERROR %08X\n",
__func__, ERROR_FILE_PARSE);
ret = ERROR_FILE_PARSE;
goto END;
}
token = strsep(&line2, ",");
if (token != NULL) {
if (sscanf(token, "%d", column) == 1)
pr_debug("%s: Column = %d\n",
__func__, *column);
else {
pr_debug("%s: ERROR while reading "
"the column value!ERROR %08X\n",
__func__, ERROR_FILE_PARSE);
ret = ERROR_FILE_PARSE;
goto END;
}
} else {
pr_err("%s: Column ERROR %08X\n",
__func__, ERROR_FILE_PARSE);
ret = ERROR_FILE_PARSE;
goto END;
}
kfree(buf);
buf = NULL;
*data = (int *)kmalloc(((*row) * (*column)) *
sizeof(int), GFP_KERNEL);
j = 0;
if (*data == NULL) {
pr_err("%s: ERROR %08X\n",
__func__, ERROR_ALLOC);
ret = ERROR_ALLOC;
goto END;
}
for (i = 0; i < *row; i++) {
if (read_line(&data_file[pointer], line,
size - pointer, &n) < 0) {
pr_err("%s: read_line ERROR %08X\n",
__func__,
ERROR_FILE_READ);
ret = ERROR_FILE_READ;
goto END;
}
pointer += n;
line2 = kstrdup(line, GFP_KERNEL);
if (line2 == NULL) {
pr_err("%s: kstrdup ERROR %08X\n",
__func__, ERROR_ALLOC);
ret = ERROR_ALLOC;
goto END;
}
buf = line2;
token = strsep(&line2, ",");
for (z = 0; (z < *column) &&
(token != NULL); z++) {
if (sscanf(token, "%d",
((*data) + j)) == 1) {
j++;
token =
strsep(&line2, ",");
}
}
kfree(buf);
buf = NULL;
}
if (j == ((*row) * (*column))) {
pr_info("%s: READ DONE!\n", __func__);
ret = OK;
goto END;
}
pr_err("%s: ERROR %08X, j=%d is not equal to %d!\n",
__func__, ERROR_FILE_PARSE, j, ((*row) * (*column)));
ret = ERROR_FILE_PARSE;
goto END;
}
kfree(buf);
buf = NULL;
}
}
pr_err("%s: Test Label not found ERROR: %08X\n", __func__,
ERROR_LABEL_NOT_FOUND);
ret = ERROR_LABEL_NOT_FOUND;
END:
if (buf != NULL)
kfree(buf);
return ret;
}
/**
* Read one line of a text file passed as array of byte and terminate it with a
*termination character '\0'
* @param data text file as array of bytes
* @param line pointer to an array of char that will contain the line read
* @param size size of data
* @param n pointer to a int variable which will contain the number of
*characters of the line
* @return OK if success or an error code which specify the type of error
*/
int read_line(char *data, char *line, int size, int *n)
{
int i = 0;
if (size < 1)
return ERROR_OP_NOT_ALLOW;
while (data[i] != '\n' && i < size) {
line[i] = data[i];
i++;
}
*n = i + 1;
line[i] = '\0';
return OK;
}
/**
* Perform an ITO test setting all the possible options
* @param info pointer to fts_ts_info which contains info about the device and
* its hw setup
* @param path_limits name of Production Limit file to load or
* "NULL" if the limits data should be loaded by a .h file
* @param tests pointer to a test_to_do variable which select the test to do
* @return OK if success or an error code which specify the type of error
*/
int fts_production_test_ito(struct fts_ts_info *info,
char *path_limits, struct test_to_do *tests)
{
int res = OK;
u8 sett[2] = { 0xFF, 0x07 };
int i = 0;
u8 data[8] = { 0 };
int event_to_search = 0x00;
struct mutual_sense_frame ms_raw_frame;
int trows, tcolumns;
int *thresholds = NULL;
u16 *adj = NULL;
int *thresholds_min = NULL;
int *thresholds_max = NULL;
ms_raw_frame.node_data = NULL;
pr_info("%s: ITO Production test is starting...\n", __func__);
if (tests->mutual_ito_raw || tests->mutual_ito_raw_adj) {
res = fts_system_reset(info, 1);
if (res < OK) {
res |= ERROR_PROD_TEST_ITO;
pr_err("%s: ERROR %08X\n", __func__, res);
goto goto_error;
}
res = fts_write_fw_reg(ITO_TRIGGER_ADDR, sett, 2);
if (res < OK) {
res |= ERROR_PROD_TEST_ITO;
pr_err("%s: ERROR %08X\n", __func__, res);
goto goto_error;
}
for (i = 0; i < TIMEOUT_FW_REG_STATUS; i++) {
res = fts_read_fw_reg(ITO_TRIGGER_ADDR, data, 2);
if (res < OK) {
res |= ERROR_PROD_TEST_ITO;
pr_err("%s: ERROR %08X\n", __func__, res);
goto goto_error;
}
res = (data[0] & 0xFF) || (data[1] & 0x07);
pr_info("%s: Status = %d\n", __func__, res);
if (!res) {
pr_info("%s: ITO Command finished..\n", __func__);
break;
}
msleep(TIMEOUT_RESOLUTION);
}
res = poll_for_event(&event_to_search, 1, data, 8);
if (res < OK) {
res |= ERROR_PROD_TEST_ITO;
pr_err("%s: ITO failed... ERROR %08X\n",
__func__, res);
goto goto_error;
}
pr_info("%s: ITO Command = OK!\n", __func__);
pr_info("%s: Collecting MS Raw data...\n", __func__);
res = get_ms_frame(MS_RAW, &ms_raw_frame);
if (res < OK) {
res |= ERROR_PROD_TEST_ITO;
pr_err("%s: failed... ERROR %08X\n", __func__, res);
goto goto_error;
}
print_frame_short("MS Raw ITO frame =",
array_1d_to_2d_short(
ms_raw_frame.node_data,
ms_raw_frame.
node_data_size,
ms_raw_frame.header.
sense_node),
ms_raw_frame.header.force_node,
ms_raw_frame.header.sense_node);
if (tests->mutual_ito_raw_adj) {
pr_info("%s: MS RAW ITO ADJ TEST:\n", __func__);
pr_info("%s: MS RAW ITO ADJ HORIZONTAL TEST:\n",
__func__);
res = compute_adj_horiz_total(ms_raw_frame.node_data,
ms_raw_frame.header.force_node,
ms_raw_frame.header.sense_node,
&adj);
if (res < OK) {
res |= ERROR_PROD_TEST_ITO;
pr_err("%s: compute adj Horizontal failed... ERROR %08X\n",
__func__, res);
goto goto_error;
}
res = parse_production_test_limits(path_limits,
&limit_file,
MS_RAW_ITO_ADJH, &thresholds,
&trows, &tcolumns);
if (res < OK ||
(trows != ms_raw_frame.header.force_node ||
tcolumns != ms_raw_frame.header.sense_node - 1)) {
res |= ERROR_PROD_TEST_ITO;
pr_err("%s: MS_RAW_ITO_ADJH limit parse failed... ERROR %08X\n",
__func__, res);
goto goto_error;
}
res = check_limits_map_adj_total(adj,
ms_raw_frame.header.force_node,
ms_raw_frame.header.sense_node - 1,
thresholds);
if (res != OK) {
pr_err("%s: check limit adj horiz MS RAW ITO ADJH "
"failed...ERROR COUNT = %d\n",
__func__, res);
pr_err("%s: MS RAW ITO ADJ HORIZONTAL TEST:.................FAIL\n\n",
__func__);
res = (ERROR_PROD_TEST_ITO |
ERROR_PROD_TEST_CHECK_FAIL);
goto goto_error;
} else
pr_info("%s: MS RAW ITO ADJ HORIZONTAL TEST:.................OK\n",
__func__);
kfree(thresholds);
thresholds = NULL;
kfree(adj);
adj = NULL;
pr_info("%s: MS RAW ITO ADJ VERTICAL TEST:\n", __func__);
res = compute_adj_vert_total(ms_raw_frame.node_data,
ms_raw_frame.header.force_node,
ms_raw_frame.header.sense_node,
&adj);
if (res < OK) {
res |= ERROR_PROD_TEST_ITO;
pr_err("%s: compute adj vert failed... ERROR %08X\n",
__func__, res);
goto goto_error;
}
res = parse_production_test_limits(path_limits,
&limit_file, MS_RAW_ITO_ADJV, &thresholds,
&trows, &tcolumns);
if (res < OK ||
(trows != ms_raw_frame.header.force_node - 1 ||
tcolumns != ms_raw_frame.header.sense_node)) {
res |= ERROR_PROD_TEST_ITO;
pr_err("%s: MS_RAW_ITO_ADJV limit parse failed... ERROR %08X\n",
__func__, res);
goto goto_error;
}
res = check_limits_map_adj_total(adj,
ms_raw_frame.header.force_node -
1, ms_raw_frame.header.sense_node,
thresholds);
if (res != OK) {
pr_err("%s: check limits adj MS RAW ITO ADJV "
"failed...ERROR COUNT = %d\n",
__func__, res);
pr_err("%s: MS RAW ITO ADJ VERTICAL TEST:.................FAIL\n\n",
__func__);
res = (ERROR_PROD_TEST_ITO |
ERROR_PROD_TEST_CHECK_FAIL);
goto goto_error;
} else
pr_info("%s: MS RAW ITO ADJ VERTICAL TEST:.................OK\n",
__func__);
kfree(thresholds);
thresholds = NULL;
kfree(adj);
adj = NULL;
} else
pr_info("%s: MS RAW ITO ADJ TEST SKIPPED:\n", __func__);
if (tests->mutual_ito_raw) {
pr_info("%s: MS RAW ITO MIN MAX TEST:\n", __func__);
res = parse_production_test_limits(path_limits,
&limit_file, MS_RAW_ITO_EACH_NODE_MIN,
&thresholds_min, &trows, &tcolumns);
if (res < OK || (trows !=
ms_raw_frame.header.force_node ||
tcolumns != ms_raw_frame.header.sense_node)) {
res |= ERROR_PROD_TEST_ITO;
pr_err("%s: MS_RAW_ITO_EACH_NODE_MIN limit parse failed... "
"ERROR %08X\n",
__func__, res);
goto goto_error;
}
res = parse_production_test_limits(path_limits,
&limit_file, MS_RAW_ITO_EACH_NODE_MAX,
&thresholds_max, &trows, &tcolumns);
if (res < OK || (trows !=
ms_raw_frame.header.force_node ||
tcolumns != ms_raw_frame.header.sense_node)) {
res |= ERROR_PROD_TEST_ITO;
pr_err("%s: MS_RAW__ITO_EACH_NODE_MAX limit parse"
" failed... ERROR %08X\n",
__func__, res);
goto goto_error;
}
res = check_limits_map_total(ms_raw_frame.node_data,
ms_raw_frame.header.force_node,
ms_raw_frame.header.sense_node, thresholds_min,
thresholds_max);
if (res != OK) {
pr_err("%s: check limits min max each node data "
"failed...ERROR COUNT = %d\n",
__func__, res);
pr_err("%s: MS RAW ITO MAP MIN MAX TEST:.................FAIL\n\n",
__func__);
res = (ERROR_PROD_TEST_ITO |
ERROR_PROD_TEST_CHECK_FAIL);
} else {
pr_info("%s: MS RAW ITO MAP MIN MAX TEST:.................OK\n",
__func__);
}
if (thresholds_min != NULL) {
kfree(thresholds_min);
thresholds_min = NULL;
}
if (thresholds_max != NULL) {
kfree(thresholds_max);
thresholds_max = NULL;
}
} else
pr_info("%s: MS RAW ITO MIN MAX TEST SKIPPED..\n",
__func__);
} else
pr_info("%s: MS RAW ITO TEST SKIPPED..\n", __func__);
goto_error:
if (thresholds != NULL)
kfree(thresholds);
if (adj != NULL)
kfree(adj);
if (ms_raw_frame.node_data != NULL)
kfree(ms_raw_frame.node_data);
if (thresholds_min != NULL) {
kfree(thresholds_min);
thresholds_min = NULL;
}
if (thresholds_max != NULL) {
kfree(thresholds_max);
thresholds_max = NULL;
}
free_limits_file(&limit_file);
res |= fts_system_reset(info, 1);
if (res < OK) {
pr_err("%s: ERROR %08X\n", __func__, ERROR_PROD_TEST_ITO);
res = (res | ERROR_PROD_TEST_ITO);
}
return res;
}
/**
* Perform all the test selected in a TestTodo variable related to MS raw data
* (touch, keys etc..)
* @param path_limits name of Production Limit file to load or
* "NULL" if the limits data should be loaded by a .h file
* @param tests pointer to a test_to_do variable which select the test to do
* @return OK if success or an error code which specify the type of error
*/
int fts_production_test_ms_raw(char *path_limits, struct test_to_do *tests)
{
int res = OK;
struct mutual_sense_frame ms_raw_frame;
int trows, tcolumns;
int *thresholds_min = NULL;
int *thresholds_max = NULL;
uint8_t data = SCAN_MODE_LOCK_ACTIVE;
ms_raw_frame.node_data = NULL;
pr_info("%s: MS RAW DATA TEST STARTING...\n", __func__);
if (tests->mutual_raw) {
data = SCAN_MODE_LOCK_ACTIVE;
res = fts_write_fw_reg(SCAN_MODE_ADDR, &data, 1);
msleep(WAIT_FOR_FRESH_FRAMES);
data = SCAN_MODE_HIBERNATE;
res |= fts_write_fw_reg(SCAN_MODE_ADDR, &data, 1);
msleep(WAIT_FOR_FRESH_FRAMES);
pr_info("%s: Collecting MS Raw data...\n", __func__);
res |= get_ms_frame(MS_RAW, &ms_raw_frame);
if (res < OK) {
res |= ERROR_PROD_TEST_RAW;
pr_err("%s: failed... ERROR %08X\n", __func__, res);
goto goto_error;
}
print_frame_short("MS Raw frame =",
array_1d_to_2d_short(
ms_raw_frame.node_data,
ms_raw_frame.
node_data_size,
ms_raw_frame.header.
sense_node),
ms_raw_frame.header.force_node,
ms_raw_frame.header.sense_node);
pr_info("%s: MS RAW MIN MAX TEST:\n", __func__);
res = parse_production_test_limits(path_limits,
&limit_file, MS_RAW_EACH_NODE_MIN,
&thresholds_min, &trows, &tcolumns);
if (res < OK || (trows !=
ms_raw_frame.header.force_node ||
tcolumns != ms_raw_frame.header.sense_node)) {
res |= ERROR_PROD_TEST_RAW;
pr_err("%s: MS_RAW_EACH_NODE_MIN limit parse failed... ERROR %08X\n",
__func__, res);
goto goto_error;
}
res = parse_production_test_limits(path_limits,
&limit_file, MS_RAW_EACH_NODE_MAX,
&thresholds_max, &trows, &tcolumns);
if (res < OK || (trows !=
ms_raw_frame.header.force_node ||
tcolumns != ms_raw_frame.header.sense_node)) {
res |= ERROR_PROD_TEST_RAW;
pr_err("%s: MS_RAW_EACH_NODE_MAX limit parse failed... ERROR %08X\n",
__func__, res);
goto goto_error;
}
res = check_limits_map_total(ms_raw_frame.node_data,
ms_raw_frame.header.force_node,
ms_raw_frame.header.sense_node, thresholds_min,
thresholds_max);
if (res != OK) {
pr_err("%s: check_limits_map_total failed... ERROR COUNT = %d\n",
__func__, res);
pr_err("%s: MS RAW MIN MAX TEST:.................FAIL\n\n",
__func__);
res = (ERROR_PROD_TEST_RAW |
ERROR_PROD_TEST_CHECK_FAIL);
} else {
pr_info("%s: MS RAW MIN MAX TEST:.................OK\n",
__func__);
}
if (thresholds_min != NULL) {
kfree(thresholds_min);
thresholds_min = NULL;
}
if (thresholds_max != NULL) {
kfree(thresholds_max);
thresholds_max = NULL;
}
} else
pr_info("%s: MS RAW DATA TEST SKIPPED...\n", __func__);
goto_error:
if (ms_raw_frame.node_data != NULL)
kfree(ms_raw_frame.node_data);
if (thresholds_min != NULL) {
kfree(thresholds_min);
thresholds_min = NULL;
}
if (thresholds_max != NULL) {
kfree(thresholds_max);
thresholds_max = NULL;
}
free_limits_file(&limit_file);
return res;
}
/**
* Perform all the test selected in a TestTodo variable related to MS low power
* raw data
* @param path_limits name of Production Limit file to load or
* "NULL" if the limits data should be loaded by a .h file
* @param tests pointer to a test_to_do variable which select the test to do
* @return OK if success or an error code which specify the type of error
*/
int fts_production_test_ms_raw_lp(char *path_limits, struct test_to_do *tests)
{
int res = OK;
struct mutual_sense_frame ms_raw_frame;
uint8_t data = SCAN_MODE_LOCK_LP_ACTIVE;
int trows, tcolumns;
int *thresholds_min = NULL;
int *thresholds_max = NULL;
ms_raw_frame.node_data = NULL;
pr_info("%s: MS LP RAW TEST STARTING..\n", __func__);
if (tests->mutual_raw_lp) {
res = fts_write_fw_reg(SCAN_MODE_ADDR, &data, 1);
msleep(WAIT_FOR_FRESH_FRAMES);
data = SCAN_MODE_HIBERNATE;
res |= fts_write_fw_reg(SCAN_MODE_ADDR, &data, 1);
msleep(WAIT_FOR_FRESH_FRAMES);
pr_info("%s: Collecting MS LP Raw data...\n", __func__);
res |= get_ms_frame(MS_RAW, &ms_raw_frame);
if (res < OK) {
res |= ERROR_PROD_TEST_RAW;
pr_err("%s: failed... ERROR %08X\n",
__func__, res);
goto goto_error;
}
print_frame_short("MS LP Raw frame =",
array_1d_to_2d_short(
ms_raw_frame.node_data,
ms_raw_frame.
node_data_size,
ms_raw_frame.header.
sense_node),
ms_raw_frame.header.force_node,
ms_raw_frame.header.sense_node);
pr_info("%s: MS LP RAW MIN MAX TEST:\n", __func__);
res = parse_production_test_limits(path_limits,
&limit_file, MS_RAW_LP_EACH_NODE_MIN,
&thresholds_min, &trows, &tcolumns);
if (res < OK || (trows !=
ms_raw_frame.header.force_node ||
tcolumns != ms_raw_frame.header.sense_node)) {
res |= ERROR_PROD_TEST_RAW;
pr_err("%s: MS_RAW_LP_EACH_NODE_MIN limit parse failed... ERROR %08X\n",
__func__, res);
goto goto_error;
}
res = parse_production_test_limits(path_limits,
&limit_file, MS_RAW_LP_EACH_NODE_MAX,
&thresholds_max, &trows, &tcolumns);
if (res < OK || (trows !=
ms_raw_frame.header.force_node ||
tcolumns != ms_raw_frame.header.sense_node)) {
res |= ERROR_PROD_TEST_RAW;
pr_err("%s: MS_RAW_LP_EACH_NODE_MAX limit parse failed... ERROR %08X\n",
__func__, res);
goto goto_error;
}
res = check_limits_map_total(ms_raw_frame.node_data,
ms_raw_frame.header.force_node,
ms_raw_frame.header.sense_node, thresholds_min,
thresholds_max);
if (res != OK) {
pr_err("%s: check_limits_map_total failed... ERROR COUNT = %d\n",
__func__, res);
pr_err("%s: MS LP RAW MIN MAX TEST:.................FAIL\n\n",
__func__);
res = (ERROR_PROD_TEST_RAW |
ERROR_PROD_TEST_CHECK_FAIL);
} else {
pr_info("%s: MS LP RAW MIN MAX TEST:.................OK\n",
__func__);
}
if (thresholds_min != NULL) {
kfree(thresholds_min);
thresholds_min = NULL;
}
if (thresholds_max != NULL) {
kfree(thresholds_max);
thresholds_max = NULL;
}
} else {
pr_info("%s: MS LP RAW MIN MAX TEST SKIPPED...\n",
__func__);
}
goto_error:
if (ms_raw_frame.node_data != NULL)
kfree(ms_raw_frame.node_data);
if (thresholds_min != NULL) {
kfree(thresholds_min);
thresholds_min = NULL;
}
if (thresholds_max != NULL) {
kfree(thresholds_max);
thresholds_max = NULL;
}
free_limits_file(&limit_file);
return res;
}
/**
* Perform all the test selected in a TestTodo variable related to SS raw data
* (touch, keys etc..)
* @param path_limits name of Production Limit file to load or
* "NULL" if the limits data should be loaded by a .h file
* @param tests pointer to a test_to_do variable which select the test to do
* @return OK if success or an error code which specify the type of error
*/
int fts_production_test_ss_raw(char *path_limits, struct test_to_do *tests)
{
int res = OK;
struct self_sense_frame ss_raw_frame;
uint8_t data = SCAN_MODE_LOCK_ACTIVE;
int trows, tcolumns;
int *thresholds_min = NULL;
int *thresholds_max = NULL;
ss_raw_frame.force_data = NULL;
ss_raw_frame.sense_data = NULL;
pr_info("%s: SS RAW DATA TEST STARTING...\n", __func__);
if (tests->self_force_raw || tests->self_sense_raw) {
res = fts_write_fw_reg(SCAN_MODE_ADDR, &data, 1);
msleep(WAIT_FOR_FRESH_FRAMES);
data = SCAN_MODE_HIBERNATE;
res |= fts_write_fw_reg(SCAN_MODE_ADDR, &data, 1);
msleep(WAIT_FOR_FRESH_FRAMES);
pr_info("%s: Collecting SS Raw data...\n", __func__);
res |= get_ss_frame(SS_RAW, &ss_raw_frame);
if (res < OK) {
res |= ERROR_PROD_TEST_RAW;
pr_err("%s: failed... ERROR %08X\n",
__func__, res);
goto goto_error;
}
if (tests->self_force_raw) {
print_frame_short("SS Raw Force frame =",
array_1d_to_2d_short(
ss_raw_frame.force_data,
ss_raw_frame.header.force_node,
1),
ss_raw_frame.header.force_node,
1);
pr_info("%s: SS RAW FORCE MIN MAX TEST:\n",
__func__);
res = parse_production_test_limits(path_limits,
&limit_file, SS_RAW_FORCE_EACH_NODE_MIN,
&thresholds_min, &trows, &tcolumns);
if (res < OK || (trows !=
ss_raw_frame.header.force_node ||
tcolumns != 1)) {
res |= ERROR_PROD_TEST_RAW;
pr_err("%s: SS_RAW_FORCE_EACH_NODE_MIN limit parse failed... "
"ERROR %08X\n",
__func__, res);
goto goto_error;
}
res = parse_production_test_limits(path_limits,
&limit_file, SS_RAW_FORCE_EACH_NODE_MAX,
&thresholds_max, &trows, &tcolumns);
if (res < OK || (trows !=
ss_raw_frame.header.force_node ||
tcolumns != 1)) {
res |= ERROR_PROD_TEST_RAW;
pr_err("%s: SS_RAW_FORCE_EACH_NODE_MAX limit parse failed... "
"ERROR %08X\n",
__func__, res);
goto goto_error;
}
res = check_limits_map_total(ss_raw_frame.force_data,
ss_raw_frame.header.force_node, 1,
thresholds_min,
thresholds_max);
if (res != OK) {
pr_err("%s: check_limits_map_total failed... ERROR COUNT = %d\n",
__func__, res);
pr_err("%s: SS RAW FORCE MIN MAX TEST:.................FAIL\n\n",
__func__);
res = (ERROR_PROD_TEST_RAW |
ERROR_PROD_TEST_CHECK_FAIL);
} else {
pr_info("%s: SS RAW FORCE MIN MAX TEST:.................OK\n",
__func__);
}
if (thresholds_min != NULL) {
kfree(thresholds_min);
thresholds_min = NULL;
}
if (thresholds_max != NULL) {
kfree(thresholds_max);
thresholds_max = NULL;
}
} else
pr_info("%s: SS RAW FORCE TEST SKIPPED..\n",
__func__);
if (tests->self_sense_raw) {
print_frame_short("SS Raw Sense frame =",
array_1d_to_2d_short(
ss_raw_frame.sense_data,
ss_raw_frame.header.sense_node,
ss_raw_frame.header.sense_node),
1,
ss_raw_frame.header.sense_node);
pr_info("%s: SS RAW SENSE MIN MAX TEST:\n",
__func__);
res = parse_production_test_limits(path_limits,
&limit_file, SS_RAW_SENSE_EACH_NODE_MIN,
&thresholds_min, &trows, &tcolumns);
if (res < OK || (trows != 1 ||
tcolumns != ss_raw_frame.header.sense_node)) {
res |= ERROR_PROD_TEST_RAW;
pr_err("%s: SS_RAW_SENSE_EACH_NODE_MIN limit parse failed... "
"ERROR %08X\n",
__func__, res);
goto goto_error;
}
res = parse_production_test_limits(path_limits,
&limit_file, SS_RAW_SENSE_EACH_NODE_MAX,
&thresholds_max, &trows, &tcolumns);
if (res < OK || (trows != 1 ||
tcolumns != ss_raw_frame.header.sense_node)) {
res |= ERROR_PROD_TEST_RAW;
pr_err("%s: SS_RAW_SENSE_EACH_NODE_MAX limit parse failed... "
"ERROR %08X\n",
__func__, res);
goto goto_error;
}
res = check_limits_map_total(ss_raw_frame.sense_data,
1,
ss_raw_frame.header.sense_node,
thresholds_min, thresholds_max);
if (res != OK) {
pr_err("%s: check_limits_map_total failed... ERROR COUNT = %d\n",
__func__, res);
pr_err("%s: SS RAW SENSE MIN MAX TEST:.................FAIL\n\n",
__func__);
res = (ERROR_PROD_TEST_RAW |
ERROR_PROD_TEST_CHECK_FAIL);
} else
pr_info("%s: SS RAW SENSE MIN MAX TEST:.................OK\n",
__func__);
} else
pr_info("%s: SS RAW SENSE TEST SKIPPED..\n",
__func__);
} else
pr_info("%s: SS RAW TEST SKIPPED...\n", __func__);
goto_error:
if (ss_raw_frame.force_data != NULL)
kfree(ss_raw_frame.force_data);
if (ss_raw_frame.sense_data != NULL)
kfree(ss_raw_frame.sense_data);
if (thresholds_min != NULL) {
kfree(thresholds_min);
thresholds_min = NULL;
}
if (thresholds_max != NULL) {
kfree(thresholds_max);
thresholds_max = NULL;
}
free_limits_file(&limit_file);
return res;
}
/**
* Perform all the test selected in a TestTodo variable related to SS raw data
* low power
* @param path_limits name of Production Limit file to load or
* "NULL" if the limits data should be loaded by a .h file
* @param tests pointer to a test_to_do variable which select the test to do
* @return OK if success or an error code which specify the type of error
*/
int fts_production_test_ss_raw_lp(char *path_limits, struct test_to_do *tests)
{
int res = OK;
struct self_sense_frame ss_raw_frame;
uint8_t data = SCAN_MODE_LOCK_LP_DETECT;
int trows, tcolumns;
int *thresholds_min = NULL;
int *thresholds_max = NULL;
ss_raw_frame.force_data = NULL;
ss_raw_frame.sense_data = NULL;
pr_info("%s: SS RAW LP DATA TEST STARTING...\n", __func__);
if (tests->self_force_raw_lp || tests->self_sense_raw_lp) {
res = fts_write_fw_reg(SCAN_MODE_ADDR, &data, 1);
msleep(WAIT_FOR_FRESH_FRAMES);
data = SCAN_MODE_HIBERNATE;
res |= fts_write_fw_reg(SCAN_MODE_ADDR, &data, 1);
msleep(WAIT_FOR_FRESH_FRAMES);
pr_info("%s: Collecting SS LP Raw data...\n", __func__);
res |= get_ss_frame(SS_DETECT_RAW, &ss_raw_frame);
if (res < OK) {
res |= ERROR_PROD_TEST_RAW;
pr_err("%s: failed... ERROR %08X\n",
__func__, res);
goto goto_error;
}
if (tests->self_force_raw_lp) {
if (ss_raw_frame.header.force_node > 0) {
print_frame_short("SS LP Raw Force frame =",
array_1d_to_2d_short(
ss_raw_frame.force_data,
ss_raw_frame.header.force_node,
1),
ss_raw_frame.header.force_node,
1);
pr_info("%s: SS LP RAW FORCE MIN MAX TEST:\n",
__func__);
res = parse_production_test_limits(path_limits,
&limit_file,
SS_RAW_LP_FORCE_EACH_NODE_MIN,
&thresholds_min, &trows, &tcolumns);
if (res < OK || (trows !=
ss_raw_frame.header.force_node ||
tcolumns != 1)) {
res |= ERROR_PROD_TEST_RAW;
pr_err("%s: SS_RAW_LP_FORCE_EACH_NODE_MIN limit "
"parse failed... ERROR %08X\n",
__func__,
res);
goto goto_error;
}
res = parse_production_test_limits(path_limits,
&limit_file,
SS_RAW_LP_FORCE_EACH_NODE_MAX,
&thresholds_max, &trows, &tcolumns);
if (res < OK || (trows !=
ss_raw_frame.header.force_node ||
tcolumns != 1)) {
res |= ERROR_PROD_TEST_RAW;
pr_err("%s: SS_RAW_LP_FORCE_EACH_NODE_MAX limit "
"parse failed... ERROR %08X\n",
__func__,
res);
goto goto_error;
}
res = check_limits_map_total(ss_raw_frame.
force_data,
ss_raw_frame.header.force_node, 1,
thresholds_min,
thresholds_max);
if (res != OK) {
pr_err("%s: check_limits_map_total failed... "
"ERROR COUNT = %d\n",
__func__, res);
pr_err("%s: SS LP RAW FORCE MIN MAX TEST:"
".................FAIL\n\n",
__func__);
res = (ERROR_PROD_TEST_RAW | ERROR_PROD_TEST_CHECK_FAIL);
} else {
pr_info("%s: SS LP RAW FORCE MIN MAX TEST:"
".................OK\n",
__func__);
}
if (thresholds_min != NULL) {
kfree(thresholds_min);
thresholds_min = NULL;
}
if (thresholds_max != NULL) {
kfree(thresholds_max);
thresholds_max = NULL;
}
} else
pr_err("%s: SS LP RAW FORCE MIN MAX TEST:SS LP FORCE "
"NOT AVAILABLE\n",
__func__);
} else
pr_info("%s: SS LP RAW FORCE TEST SKIPPED\n", __func__);
if (tests->self_sense_raw_lp) {
if (ss_raw_frame.header.sense_node > 0) {
print_frame_short("SS LP Raw Sense frame =",
array_1d_to_2d_short(
ss_raw_frame.sense_data,
ss_raw_frame.header.sense_node,
ss_raw_frame.header.sense_node),
1,
ss_raw_frame.header.sense_node);
pr_info("%s: SS LP RAW SENSE MIN MAX TEST:\n",
__func__);
res = parse_production_test_limits(path_limits,
&limit_file,
SS_RAW_LP_SENSE_EACH_NODE_MIN,
&thresholds_min, &trows, &tcolumns);
if (res < OK || (trows != 1 ||
tcolumns != ss_raw_frame.header.sense_node)) {
res |= ERROR_PROD_TEST_RAW;
pr_err("%s: SS_RAW_LP_SENSE_EACH_NODE_MIN limit "
"parse failed...ERROR %08X\n",
__func__, res);
goto goto_error;
}
res = parse_production_test_limits(path_limits,
&limit_file,
SS_RAW_LP_SENSE_EACH_NODE_MAX,
&thresholds_max, &trows, &tcolumns);
if (res < OK || (trows != 1 ||
tcolumns != ss_raw_frame.header.sense_node)) {
res |= ERROR_PROD_TEST_RAW;
pr_err("%s: SS_RAW_LP_SENSE_EACH_NODE_MAX limit "
"parse failed...ERROR %08X\n",
__func__, res);
goto goto_error;
}
res = check_limits_map_total(ss_raw_frame.
sense_data, 1,
ss_raw_frame.header.sense_node,
thresholds_min, thresholds_max);
if (res != OK) {
pr_err("%s: check_limits_map_total failed"
"...ERROR COUNT = %d\n",
__func__, res);
pr_err("%s: SS LP RAW SENSE MIN MAX TEST:"
".................FAIL\n\n",
__func__);
res = (ERROR_PROD_TEST_RAW |
ERROR_PROD_TEST_CHECK_FAIL);
} else {
pr_info("%s: SS LP RAW SENSE MIN MAX TEST:"
".................OK\n",
__func__);
}
} else
pr_err("%s: SS LP RAW SENSE MIN MAX TEST: SS LP SENSE "
"NOT AVAILABLE\n",
__func__);
} else
pr_info("%s: SS LP RAW SENSE TEST SKIPPED\n",
__func__);
} else
pr_info("%s: SS LP RAW TEST SKIPPED...\n", __func__);
goto_error:
if (ss_raw_frame.force_data != NULL)
kfree(ss_raw_frame.force_data);
if (ss_raw_frame.sense_data != NULL)
kfree(ss_raw_frame.sense_data);
if (thresholds_min != NULL) {
kfree(thresholds_min);
thresholds_min = NULL;
}
if (thresholds_max != NULL) {
kfree(thresholds_max);
thresholds_max = NULL;
}
free_limits_file(&limit_file);
return res;
}
/**
* Perform all the tests selected in a TestTodo variable related to MS Total CX LowPower
* Init data (touch, keys etc..)
* @param path_limits name of Production Limit file to load or
* "NULL" if the limits data should be loaded by a .h file
* @param stop_on_fail if 1, the test flow stops at the first data check
* failure
* @param tests pointer to a test_to_do variable which select the test to do
* @return OK if success or an error code which specify the type of error
*/
int fts_production_test_ms_cx_lp(char *path_limits, int stop_on_fail,
struct test_to_do *tests)
{
int res = OK;
struct mutual_total_cx_data ms_cx_data;
int trows, tcolumns;
int *thresholds_min = NULL;
int *thresholds_max = NULL;
u16 *adj = NULL;
int *thresholds = NULL;
ms_cx_data.node_data = NULL;
pr_info("%s: MS TOTAL CX LP DATA TEST STARTING...\n", __func__);
if (tests->mutual_cx_lp || tests->mutual_cx_lp_adj) {
pr_info("%s: Collecting MS CX LP data...\n", __func__);
res = get_mutual_total_cx_data(HDM_REQ_TOT_CX_MS_LOW_POWER,
&ms_cx_data);
if (res < OK) {
res |= ERROR_PROD_TEST_CX;
pr_err("%s: failed... ERROR %08X\n", __func__, res);
goto goto_error;
}
print_frame_short("MS TOTAL CX data =",
array_1d_to_2d_short(
ms_cx_data.node_data,
ms_cx_data.
node_data_size,
ms_cx_data.header.
sense_node),
ms_cx_data.header.force_node,
ms_cx_data.header.sense_node);
if (tests->mutual_cx_lp) {
pr_info("%s: MS TOTAL CX LP DATA MIN MAX TEST:\n",
__func__);
res = parse_production_test_limits(path_limits,
&limit_file, MS_TOTAL_CX_LP_MIN,
&thresholds_min, &trows, &tcolumns);
if (res < OK || (trows !=
ms_cx_data.header.force_node ||
tcolumns != ms_cx_data.header.sense_node)) {
res |= ERROR_PROD_TEST_CX;
pr_err("%s: MS_TOTAL_CX_LP_MIN limit parse failed... ERROR %08X\n",
__func__, res);
goto goto_error;
}
res = parse_production_test_limits(path_limits,
&limit_file, MS_TOTAL_CX_LP_MAX,
&thresholds_max, &trows, &tcolumns);
if (res < OK || (trows !=
ms_cx_data.header.force_node ||
tcolumns != ms_cx_data.header.sense_node)) {
res |= ERROR_PROD_TEST_CX;
pr_err("%s: MS_TOTAL_CX_LP_MAX limit parse failed... ERROR %08X\n",
__func__, res);
goto goto_error;
}
res = check_limits_map_total(ms_cx_data.node_data,
ms_cx_data.header.force_node,
ms_cx_data.header.sense_node, thresholds_min,
thresholds_max);
if (res != OK) {
pr_err("%s: check_limits_map_total failed... ERROR COUNT = %d\n",
__func__, res);
pr_err("%s: MS TOTAL CX LP MIN MAX TEST:.................FAIL\n\n",
__func__);
res = (ERROR_PROD_TEST_CX |
ERROR_PROD_TEST_CHECK_FAIL);
if (stop_on_fail == 1)
goto goto_error;
} else {
pr_info("%s: MS TOTAL CX LP MIN MAX TEST:.................OK\n",
__func__);
}
if (thresholds_min != NULL) {
kfree(thresholds_min);
thresholds_min = NULL;
}
if (thresholds_max != NULL) {
kfree(thresholds_max);
thresholds_max = NULL;
}
} else
pr_info("%s: MS TOTAL CX LP DATA MIN MAX TEST SKIPPED...\n",
__func__);
if (tests->mutual_cx_lp_adj) {
pr_info("%s: MS TOTAL CX LP DATA ADJACENT HORIZONTAL TEST:\n",
__func__);
res = compute_adj_horiz_total(ms_cx_data.node_data,
ms_cx_data.header.force_node,
ms_cx_data.header.sense_node,
&adj);
if (res < OK) {
pr_err("%s: compute adj Horizontal failed... ERROR %08X\n",
__func__, res);
goto goto_error;
}
res = parse_production_test_limits(path_limits,
&limit_file,
MS_TOTAL_CX_LP_ADJH, &thresholds,
&trows, &tcolumns);
if (res < OK ||
(trows != ms_cx_data.header.force_node ||
tcolumns != ms_cx_data.header.sense_node - 1)) {
res |= ERROR_PROD_TEST_CX;
pr_err("%s: MS_TOTAL_CX_LP_ADJH limit parse failed... ERROR %08X\n",
__func__, res);
goto goto_error;
}
res = check_limits_map_adj_total(adj,
ms_cx_data.header.force_node,
ms_cx_data.header.sense_node - 1,
thresholds);
if (res != OK) {
pr_err("%s: check limit adj horiz MS_TOTAL_CX_LP_ADJH failed... "
"ERROR COUNT = %d\n",
__func__, res);
pr_err("%s: MS TOTAL CX LP ADJ HORIZONTAL TEST:"
".................FAIL\n\n",
__func__);
res = (ERROR_PROD_TEST_CX |
ERROR_PROD_TEST_CHECK_FAIL);
if (stop_on_fail == 1)
goto goto_error;
} else
pr_info("%s: MS TOTAL CX LP ADJ HORIZONTAL TEST:"
".................OK\n",
__func__);
kfree(thresholds);
thresholds = NULL;
kfree(adj);
adj = NULL;
pr_info("%s: MS TOTAL CX LP ADJ VERTICAL TEST:\n",
__func__);
res = compute_adj_vert_total(ms_cx_data.node_data,
ms_cx_data.header.force_node,
ms_cx_data.header.sense_node,
&adj);
if (res < OK) {
res |= ERROR_PROD_TEST_CX;
pr_err("%s: compute adj vert failed... ERROR %08X\n",
__func__, res);
goto goto_error;
}
res = parse_production_test_limits(path_limits,
&limit_file, MS_TOTAL_CX_LP_ADJV, &thresholds,
&trows, &tcolumns);
if (res < OK ||
(trows != ms_cx_data.header.force_node - 1 ||
tcolumns != ms_cx_data.header.sense_node)) {
res |= ERROR_PROD_TEST_CX;
pr_err("%s: MS_TOTAL_CX_LP_ADJV limit parse failed... ERROR %08X\n",
__func__, res);
goto goto_error;
}
res = check_limits_map_adj_total(adj,
ms_cx_data.header.force_node -
1, ms_cx_data.header.sense_node,
thresholds);
if (res != OK) {
pr_err("%s: check limits adj MS_TOTAL_CX_LP_ADJV failed..."
"ERROR COUNT = %d\n",
__func__, res);
pr_err("%s: MS TOTAL CX LP ADJ VERTICAL TEST:"
".................FAIL\n\n",
__func__);
res = (ERROR_PROD_TEST_CX |
ERROR_PROD_TEST_CHECK_FAIL);
if (stop_on_fail == 1)
goto goto_error;
} else
pr_info("%s: MS TOTAL CX LP ADJ VERTICAL TEST:"
".................OK\n",
__func__);
kfree(thresholds);
thresholds = NULL;
kfree(adj);
adj = NULL;
}
} else
pr_info("%s: MS TOTAL CX LP TEST SKIPPED...\n", __func__);
goto_error:
if (ms_cx_data.node_data != NULL)
kfree(ms_cx_data.node_data);
if (thresholds_min != NULL) {
kfree(thresholds_min);
thresholds_min = NULL;
}
if (thresholds_max != NULL) {
kfree(thresholds_max);
thresholds_max = NULL;
}
if (thresholds != NULL) {
kfree(thresholds);
thresholds = NULL;
}
if (adj != NULL) {
kfree(adj);
adj = NULL;
}
free_limits_file(&limit_file);
return res;
}
/**
* Perform all the tests selected in a TestTodo variable related to SS Init
* data (touch, keys etc..)
* @param path_limits name of Production Limit file to load or
* "NULL" if the limits data should be loaded by a .h file
* @param tests pointer to a test_to_do variable which select the test to do
* @return OK if success or an error code which specify the type of error
*/
int fts_production_test_ss_ix(char *path_limits, struct test_to_do *tests)
{
int res = OK;
struct self_total_cx_data ss_cx_data;
int trows, tcolumns;
int *thresholds_min = NULL;
int *thresholds_max = NULL;
ss_cx_data.ix_tx = NULL;
ss_cx_data.ix_rx = NULL;
pr_info("%s: SS TOTAL IX DATA TEST STARTING...\n", __func__);
if (tests->self_force_ix || tests->self_sense_ix) {
pr_info("%s: Collecting SS IX data...\n", __func__);
res |= get_self_total_cx_data(HDM_REQ_TOT_IX_SS_TOUCH,
&ss_cx_data);
if (res < OK) {
res |= ERROR_PROD_TEST_CX;
pr_err("%s: failed... ERROR %08X\n",
__func__, res);
goto goto_error;
}
print_frame_u16("SS TOTAL FORCE DATA =",
array_1d_to_2d_u16(ss_cx_data.ix_tx,
ss_cx_data.header.force_node,
1),
ss_cx_data.header.force_node,
1);
print_frame_u16("SS TOTAL SENSE DATA =",
array_1d_to_2d_u16(ss_cx_data.ix_rx,
ss_cx_data.header.sense_node,
ss_cx_data.header.sense_node),
1,
ss_cx_data.header.sense_node);
pr_info("%s: SS TOTAL IX DATA MIN MAX TEST:\n", __func__);
if (tests->self_force_ix) {
pr_info("%s: SS TOTAL FORCE IX DATA MIN MAX TEST:\n",
__func__);
res = parse_production_test_limits(path_limits,
&limit_file, SS_FORCE_TOTAL_IX_MIN,
&thresholds_min, &trows, &tcolumns);
if (res < OK || (trows !=
ss_cx_data.header.force_node ||
tcolumns != 1)) {
res |= ERROR_PROD_TEST_CX;
pr_err("%s: SS_FORCE_TOTAL_IX_MIN limit parse failed... "
"ERROR %08X\n",
__func__, res);
goto goto_error;
}
res = parse_production_test_limits(path_limits,
&limit_file, SS_FORCE_TOTAL_IX_MAX,
&thresholds_max, &trows, &tcolumns);
if (res < OK || (trows != ss_cx_data.header.force_node ||
tcolumns != 1)) {
res |= ERROR_PROD_TEST_CX;
pr_err("%s: SS_FORCE_TOTAL_IX_MAX limit parse failed... "
"ERROR %08X\n",
__func__, res);
goto goto_error;
}
res = check_limits_map_total(ss_cx_data.ix_tx,
ss_cx_data.header.force_node,
1, thresholds_min,
thresholds_max);
if (res != OK) {
pr_err("%s: check_limits_map_total failed... ERROR COUNT = %d\n",
__func__, res);
pr_err("%s: SS TOTAL FORCE IX DATA MAP MIN MAX TEST:"
".................FAIL\n\n",
__func__);
res = (ERROR_PROD_TEST_CX |
ERROR_PROD_TEST_CHECK_FAIL);
} else {
pr_info("%s: SS TOTAL FORCE IX DATA MAP MIN MAX TEST:"
".................OK\n",
__func__);
}
} else
pr_info("%s: SS TOTAL FORCE IX DATA MIN MAX TEST SKIPPED\n", __func__);
if (tests->self_sense_ix) {
pr_info("%s: SS TOTAL SENSE IX DATA MIN MAX TEST:\n", __func__);
res = parse_production_test_limits(path_limits,
&limit_file, SS_SENSE_TOTAL_IX_MIN,
&thresholds_min, &trows, &tcolumns);
if (res < OK || (trows != 1 || tcolumns != ss_cx_data.header.sense_node)) {
res |= ERROR_PROD_TEST_CX;
pr_err("%s: SS_SENSE_TOTAL_IX_MIN limit parse failed... ERROR %08X\n",
__func__, res);
goto goto_error;
}
res = parse_production_test_limits(path_limits,
&limit_file, SS_SENSE_TOTAL_IX_MAX,
&thresholds_max, &trows, &tcolumns);
if (res < OK || (trows != 1 || tcolumns != ss_cx_data.header.sense_node)) {
res |= ERROR_PROD_TEST_CX;
pr_err("%s: SS_SENSE_TOTAL_IX_MIN limit parse failed... "
"ERROR %08X\n",
__func__, res);
goto goto_error;
}
res = check_limits_map_total(ss_cx_data.ix_rx,
1,
ss_cx_data.header.sense_node, thresholds_min,
thresholds_max);
if (res != OK) {
pr_err("%s: check_limits_map_total failed... ERROR COUNT = %d\n",
__func__, res);
pr_err("%s: SS TOTAL SENSE IX DATA MAP MIN MAX TEST:"
".................FAIL\n\n",
__func__);
res = (ERROR_PROD_TEST_CX | ERROR_PROD_TEST_CHECK_FAIL);
} else
pr_info("%s: SS TOTAL SENSE IX DATA MAP MIN MAX TEST:"
".................OK\n",
__func__);
} else
pr_info("%s: SS TOTAL SENSE IX DATA MAP MIN MAX TEST SKIPPED\n", __func__);
if (thresholds_min != NULL) {
kfree(thresholds_min);
thresholds_min = NULL;
}
if (thresholds_max != NULL) {
kfree(thresholds_max);
thresholds_max = NULL;
}
} else
pr_info("%s: MS TOTAL CX TEST SKIPPED...\n",
__func__);
goto_error:
if (ss_cx_data.ix_rx != NULL) {
kfree(ss_cx_data.ix_rx);
ss_cx_data.ix_rx = NULL;
}
if (ss_cx_data.ix_tx != NULL) {
kfree(ss_cx_data.ix_tx);
ss_cx_data.ix_tx = NULL;
}
if (thresholds_min != NULL) {
kfree(thresholds_min);
thresholds_min = NULL;
}
if (thresholds_max != NULL) {
kfree(thresholds_max);
thresholds_max = NULL;
}
free_limits_file(&limit_file);
return res;
}
/**
* Perform all the tests selected in a TestTodo variable related to SS Init
* data for LP mode (touch, keys etc..)
* @param path_limits name of Production Limit file to load or
* "NULL" if the limits data should be loaded by a .h file
* @param tests pointer to a test_to_do variable which select the test to do
* @return OK if success or an error code which specify the type of error
*/
int fts_production_test_ss_ix_lp(char *path_limits, struct test_to_do *tests)
{
int res = OK;
struct self_total_cx_data ss_cx_data;
int trows, tcolumns;
int *thresholds_min = NULL;
int *thresholds_max = NULL;
ss_cx_data.ix_tx = NULL;
ss_cx_data.ix_rx = NULL;
pr_info("%s: SS TOTAL IX LP DATA TEST STARTING...\n", __func__);
if (tests->self_force_ix_lp || tests->self_sense_ix_lp) {
pr_info("%s: Collecting SS IX LP data...\n", __func__);
res |= get_self_total_cx_data(HDM_REQ_TOT_IX_SS_TOUCH_IDLE,
&ss_cx_data);
if (res < OK) {
res |= ERROR_PROD_TEST_CX;
pr_err("%s: failed... ERROR %08X\n", __func__, res);
goto goto_error;
}
print_frame_u16("SS TOTAL FORCE LP DATA =",
array_1d_to_2d_u16(ss_cx_data.ix_tx,
ss_cx_data.header.force_node,
1),
ss_cx_data.header.force_node,
1);
print_frame_u16("SS TOTAL SENSE LP DATA =",
array_1d_to_2d_u16(ss_cx_data.ix_rx,
ss_cx_data.header.sense_node,
ss_cx_data.header.sense_node),
1,
ss_cx_data.header.sense_node);
pr_info("%s: SS TOTAL IX LP DATA MIN MAX TEST:\n", __func__);
if (tests->self_force_ix_lp) {
pr_info("%s: SS TOTAL FORCE IX LP DATA MIN MAX TEST:\n", __func__);
res = parse_production_test_limits(path_limits,
&limit_file, SS_FORCE_TOTAL_IX_LP_MIN,
&thresholds_min, &trows, &tcolumns);
if (res < OK || (trows !=
ss_cx_data.header.force_node ||
tcolumns != 1)) {
res |= ERROR_PROD_TEST_CX;
pr_err("%s: SS_FORCE_TOTAL_IX_MIN limit parse failed... ERROR %08X\n",
__func__, res);
goto goto_error;
}
res = parse_production_test_limits(path_limits,
&limit_file, SS_FORCE_TOTAL_IX_LP_MAX,
&thresholds_max, &trows, &tcolumns);
if (res < OK || (trows !=
ss_cx_data.header.force_node ||
tcolumns != 1)) {
res |= ERROR_PROD_TEST_CX;
pr_err("%s: SS_FORCE_TOTAL_IX_MAX limit parse failed... ERROR %08X\n",
__func__, res);
goto goto_error;
}
res = check_limits_map_total(ss_cx_data.ix_tx,
ss_cx_data.header.force_node,
1, thresholds_min,
thresholds_max);
if (res != OK) {
pr_err("%s: check_limits_map_total failed... ERROR COUNT = %d\n",
__func__, res);
pr_err("%s: SS TOTAL FORCE IX LP DATA MAP MIN MAX TEST:"
".................FAIL\n\n",
__func__);
res = (ERROR_PROD_TEST_CX | ERROR_PROD_TEST_CHECK_FAIL);
} else
pr_info("%s: SS TOTAL FORCE IX LP DATA MAP MIN MAX TEST:"
".................OK\n",
__func__);
} else
pr_info("%s: SS TOTAL FORCE IX LP DATA MIN MAX TEST SKIPPED\n", __func__);
if (tests->self_sense_ix_lp) {
pr_info("%s: SS TOTAL SENSE IX LP DATA MIN MAX TEST:\n", __func__);
res = parse_production_test_limits(path_limits,
&limit_file, SS_SENSE_TOTAL_IX_LP_MIN,
&thresholds_min, &trows, &tcolumns);
if (res < OK || (trows !=
1 ||
tcolumns != ss_cx_data.header.sense_node)) {
res |= ERROR_PROD_TEST_CX;
pr_err("%s: SS_SENSE_TOTAL_IX_MIN limit parse failed... ERROR %08X\n",
__func__, res);
goto goto_error;
}
res = parse_production_test_limits(path_limits,
&limit_file, SS_SENSE_TOTAL_IX_LP_MAX,
&thresholds_max, &trows, &tcolumns);
if (res < OK || (trows !=
1 ||
tcolumns != ss_cx_data.header.sense_node)) {
res |= ERROR_PROD_TEST_CX;
pr_err("%s: SS_SENSE_TOTAL_IX_MIN limit parse failed... ERROR %08X\n",
__func__, res);
goto goto_error;
}
res = check_limits_map_total(ss_cx_data.ix_rx,
1,
ss_cx_data.header.sense_node, thresholds_min,
thresholds_max);
if (res != OK) {
pr_err("%s: check_limits_map_total failed... ERROR COUNT = %d\n",
__func__, res);
pr_err("%s: SS TOTAL SENSE IX LP DATA MAP MIN MAX TEST:"
".................FAIL\n\n",
__func__);
res = (ERROR_PROD_TEST_CX | ERROR_PROD_TEST_CHECK_FAIL);
} else
pr_info("%s: SS TOTAL SENSE IX LP DATA MAP MIN MAX TEST:"
".................OK\n",
__func__);
} else
pr_info("%s: SS TOTAL SENSE IX LP DATA MIN MAX TEST SKIPPED\n", __func__);
if (thresholds_min != NULL) {
kfree(thresholds_min);
thresholds_min = NULL;
}
if (thresholds_max != NULL) {
kfree(thresholds_max);
thresholds_max = NULL;
}
} else
pr_info("%s: SS TOTAL IX LP TEST SKIPPED...\n", __func__);
goto_error:
if (ss_cx_data.ix_rx != NULL) {
kfree(ss_cx_data.ix_rx);
ss_cx_data.ix_rx = NULL;
}
if (ss_cx_data.ix_tx != NULL) {
kfree(ss_cx_data.ix_tx);
ss_cx_data.ix_tx = NULL;
}
if (thresholds_min != NULL) {
kfree(thresholds_min);
thresholds_min = NULL;
}
if (thresholds_max != NULL) {
kfree(thresholds_max);
thresholds_max = NULL;
}
free_limits_file(&limit_file);
return res;
}
/**
* Perform a FULL (ITO + INIT + DATA CHECK) Mass Production Test of the IC
* @param info pointer to fts_ts_info which contains info about the device and
* its hw setup
* @param path_limits name of Production Limit file to load or
* "NULL" if the limits data should be loaded by a .h file
* @param stop_on_fail if 1, the test flow stops at the first data check
* failure, except ITO test which will always stop for error
* @param do_init flag variable to decide on full panel initialisation
* the Initialization of the IC is executed otherwise it is skipped
* @param tests pointer to a test_to_do variable which select the test to do
* @return OK if success or an error code which specify the type of error
*/
int fts_production_test_main(struct fts_ts_info *info, char *path_limits,
int stop_on_fail, struct test_to_do *tests, int do_init)
{
int res = OK;
pr_info("%s: MAIN production test is starting...\n", __func__);
pr_info("%s: [1]ITO TEST...\n", __func__);
res = fts_production_test_ito(info, path_limits, tests);
if (res != OK) {
pr_err("%s: ITO TEST FAIL\n", __func__);
goto goto_error;
}
if (do_init) {
pr_info("%s: Do Initialization...\n", __func__);
res = fts_fw_request(PI_ADDR, 1, 1, TIMEOUT_FPI);
if (res < OK) {
pr_err("%s: Error performing autotune.. %08X\n",
__func__, res);
res |= ERROR_INIT;
if (stop_on_fail)
goto goto_error;
}
pr_info("%s: Initialization done...\n", __func__);
}
pr_info("%s: [2]MUTUAL RAW TEST...\n", __func__);
res = fts_production_test_ms_raw(path_limits, tests);
if (res != OK) {
pr_err("%s: MUTUAL RAW TEST FAIL\n", __func__);
if (stop_on_fail)
goto goto_error;
}
pr_info("%s: [3]LOW POWER MUTUAL RAW Test......\n", __func__);
res = fts_production_test_ms_raw_lp(path_limits, tests);
if (res != OK) {
pr_err("%s: LOW POWER MUTUAL RAW TEST FAIL\n", __func__);
if (stop_on_fail)
goto goto_error;
}
pr_info("%s: [4]SELF RAW TEST...\n", __func__);
res = fts_production_test_ss_raw(path_limits, tests);
if (res != OK) {
pr_err("%s: SELF RAW TEST FAIL\n", __func__);
if (stop_on_fail)
goto goto_error;
}
pr_info("%s: [5]LOW POWER SELF RAW TEST......\n", __func__);
res = fts_production_test_ss_raw_lp(path_limits, tests);
if (res != OK) {
pr_err("%s: LOW POWER SELF RAW TEST FAIL\n", __func__);
if (stop_on_fail)
goto goto_error;
}
pr_info("%s: [6]MUTUAL CX LOW POWER TEST......\n", __func__);
res = fts_production_test_ms_cx_lp(path_limits, stop_on_fail, tests);
if (res != OK) {
pr_err("%s: MUTUAL CX LOW POWER TEST FAIL\n", __func__);
if (stop_on_fail)
goto goto_error;
}
pr_info("%s: [7]SELF IX TEST......\n", __func__);
res = fts_production_test_ss_ix(path_limits, tests);
if (res != OK) {
pr_err("%s: SELF IX TEST FAIL\n", __func__);
if (stop_on_fail)
goto goto_error;
}
pr_info("%s: [8]SELF IX DETECT TEST......\n", __func__);
res = fts_production_test_ss_ix_lp(path_limits, tests);
if (res != OK) {
pr_err("%s: SELF IX DETECT TEST FAIL\n", __func__);
if (stop_on_fail)
goto goto_error;
}
goto_error:
if (res != OK) {
pr_err("%s: MAIN production test FAIL\n\n", __func__);
return res;
}
pr_info("%s: MAIN production test OK\n\n", __func__);
return res;
}