diff options
Diffstat (limited to 'drivers/input/touchscreen/stm/fts_lib/ftsTest.c')
-rw-r--r-- | drivers/input/touchscreen/stm/fts_lib/ftsTest.c | 5268 |
1 files changed, 5268 insertions, 0 deletions
diff --git a/drivers/input/touchscreen/stm/fts_lib/ftsTest.c b/drivers/input/touchscreen/stm/fts_lib/ftsTest.c new file mode 100644 index 000000000000..f0dedb852bc5 --- /dev/null +++ b/drivers/input/touchscreen/stm/fts_lib/ftsTest.c @@ -0,0 +1,5268 @@ +/* + * + ************************************************************************** + ** STMicroelectronics ** + ************************************************************************** + ** marco.cali@st.com ** + ************************************************************************** + * * + * FTS API for MP test * + * * + ************************************************************************** + ************************************************************************** + * + */ + +/*! + * \file ftsTest.c + * \brief Contains all the functions related to the Mass Production Test + */ + +#include "ftsCompensation.h" +#include "ftsCore.h" +#include "ftsError.h" +#include "ftsFrame.h" +#include "ftsHardware.h" +#include "ftsIO.h" +#include "ftsSoftware.h" +#include "ftsTest.h" +#include "ftsTime.h" +#include "ftsTool.h" +#include "../fts.h" + + +#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> + + +#ifdef LIMITS_H_FILE +#include "../fts_limits.h" +#endif + + +TestToDo tests; /* /< global variable that specify the tests to perform during + * the Mass Production Test */ +static LimitFile 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 initTestToDo(void) +{ + /*** Initialize Limit File ***/ + limit_file.size = 0; + limit_file.data = NULL; + strlcpy(limit_file.name, " ", MAX_LIMIT_FILE_NAME); + + + tests.MutualRawAdjITO = 1; + + tests.MutualRaw = 1; + tests.MutualRawGap = 0; + tests.MutualRawAdj = 0; + + tests.MutualRawLP = 1; + tests.MutualRawGapLP = 0; + tests.MutualRawAdjLP = 0; + + tests.MutualCx1 = 0; + tests.MutualCx2 = 0; + tests.MutualCx2Adj = 0; + tests.MutualCxTotal = 0; + tests.MutualCxTotalAdj = 0; + +#ifdef PHONE_KEY + tests.MutualKeyRaw = 1; +#else + tests.MutualKeyRaw = 0; +#endif + tests.MutualKeyCx1 = 0; + tests.MutualKeyCx2 = 0; +#ifdef PHONE_KEY + tests.MutualKeyCxTotal = 0; +#else + tests.MutualKeyCxTotal = 0; +#endif + + tests.SelfForceRaw = 1; + tests.SelfForceRawGap = 0; + + tests.SelfForceRawLP = 1; + tests.SelfForceRawGapLP = 0; + + tests.SelfForceIx1 = 0; + tests.SelfForceIx2 = 0; + tests.SelfForceIx2Adj = 0; + tests.SelfForceIxTotal = 0; + tests.SelfForceIxTotalAdj = 0; + tests.SelfForceCx1 = 0; + tests.SelfForceCx2 = 0; + tests.SelfForceCx2Adj = 0; + tests.SelfForceCxTotal = 0; + tests.SelfForceCxTotalAdj = 0; + + tests.SelfSenseRaw = 1; + tests.SelfSenseRawGap = 0; + + tests.SelfSenseRawLP = 1; + tests.SelfSenseRawGapLP = 0; + + tests.SelfSenseIx1 = 0; + tests.SelfSenseIx2 = 0; + tests.SelfSenseIx2Adj = 0; + tests.SelfSenseIxTotal = 0; + tests.SelfSenseIxTotalAdj = 0; + tests.SelfSenseCx1 = 0; + tests.SelfSenseCx2 = 0; + tests.SelfSenseCx2Adj = 0; + tests.SelfSenseCxTotal = 0; + tests.SelfSenseCxTotalAdj = 0; + + return OK; +} + +/** + * Compute the Horizontal adjacent matrix doing the abs of the difference + * between the column i with the i-1 one. \n + * 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 computeAdjHoriz(i8 *data, int row, int column, u8 **result) +{ + int i, j; + int size = row * (column - 1); + + if (column < 2) { + pr_err("computeAdjHoriz: ERROR %08X\n", ERROR_OP_NOT_ALLOW); + return ERROR_OP_NOT_ALLOW; + } + + *result = (u8 *)kmalloc(size * sizeof(u8), GFP_KERNEL); + if (*result == NULL) { + pr_err("computeAdjHoriz: ERROR %08X\n", 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 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 computeAdjHorizTotal(short *data, int row, int column, u16 **result) +{ + int i, j; + int size = row * (column - 1); + + if (column < 2) { + pr_err("computeAdjHorizTotal: ERROR %08X\n", + ERROR_OP_NOT_ALLOW); + return ERROR_OP_NOT_ALLOW; + } + + *result = (u16 *)kmalloc(size * sizeof(u16), GFP_KERNEL); + if (*result == NULL) { + pr_err("computeAdjHorizTotal: ERROR %08X\n", 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 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 computeAdjVert(i8 *data, int row, int column, u8 **result) +{ + int i, j; + int size = (row - 1) * (column); + + if (row < 2) { + pr_err("computeAdjVert: ERROR %08X\n", ERROR_OP_NOT_ALLOW); + return ERROR_OP_NOT_ALLOW; + } + + *result = (u8 *)kmalloc(size * sizeof(u8), GFP_KERNEL); + if (*result == NULL) { + pr_err("computeAdjVert: ERROR %08X\n", 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; +} + +/** + * 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 computeAdjVertTotal(short *data, int row, int column, u16 **result) +{ + int i, j; + int size = (row - 1) * (column); + + if (row < 2) { + pr_err("computeAdjVertTotal: ERROR %08X\n", ERROR_OP_NOT_ALLOW); + return ERROR_OP_NOT_ALLOW; + } + + *result = (u16 *)kmalloc(size * sizeof(u16), GFP_KERNEL); + if (*result == NULL) { + pr_err("computeAdjVertTotal: ERROR %08X\n", 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; +} + +/** + * Compute the Horizontal adjacent matrix doing the abs of the difference + * between the column i with the i-1 one. \n + * 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 unsigned 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 computeAdjHorizFromU(u8 *data, int row, int column, u8 **result) +{ + int i, j; + int size = row * (column - 1); + + if (column < 2) { + pr_err("computeAdjHoriz: ERROR %08X\n", ERROR_OP_NOT_ALLOW); + return ERROR_OP_NOT_ALLOW; + } + + *result = (u8 *)kmalloc(size * sizeof(u8), GFP_KERNEL); + if (*result == NULL) { + pr_err("computeAdjHoriz: ERROR %08X\n", 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 Horizontal adjacent matrix of u16 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 unsigned 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 computeAdjHorizTotalFromU(u16 *data, int row, int column, u16 **result) +{ + int i, j; + int size = row * (column - 1); + + if (column < 2) { + pr_err("computeAdjHorizTotal: ERROR %08X\n", + ERROR_OP_NOT_ALLOW); + return ERROR_OP_NOT_ALLOW; + } + + *result = (u16 *)kmalloc(size * sizeof(u16), GFP_KERNEL); + if (*result == NULL) { + pr_err("computeAdjHorizTotal: ERROR %08X\n", 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 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 unsigned 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 computeAdjVertFromU(u8 *data, int row, int column, u8 **result) +{ + int i, j; + int size = (row - 1) * (column); + + if (row < 2) { + pr_err("computeAdjVert: ERROR %08X\n", ERROR_OP_NOT_ALLOW); + return ERROR_OP_NOT_ALLOW; + } + + *result = (u8 *)kmalloc(size * sizeof(u8), GFP_KERNEL); + if (*result == NULL) { + pr_err("computeAdjVert: ERROR %08X\n", 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; +} + +/** + * Compute the Vertical adjacent matrix of u16 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 unsigned 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 computeAdjVertTotalFromU(u16 *data, int row, int column, u16 **result) +{ + int i, j; + int size = (row - 1) * (column); + + if (row < 2) { + pr_err("computeAdjVertTotal: ERROR %08X\n", ERROR_OP_NOT_ALLOW); + return ERROR_OP_NOT_ALLOW; + } + + *result = (u16 *)kmalloc(size * sizeof(u16), GFP_KERNEL); + if (*result == NULL) { + pr_err("computeAdjVertTotal: ERROR %08X\n", 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 short doesn't exceed a min and a Max + * value + * (these values are included in the interval). \n + * The matrix is stored as 1 dimension array one row after the other. \n + * @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 minimum value allowed + * @param max Maximum value allowed + * @return the number of elements that overcome the specified interval (0 = OK) + */ +int checkLimitsMinMax(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 || data[i * column + j] > + max) { + pr_err("checkLimitsMinMax: Node[%d,%d] = %d exceed limit [%d, %d]\n", + i, j, data[i * column + j], min, max); + count++; + } + } + } + + return count; /* if count is 0 = OK, test completed successfully */ +} + +/** + * Check that the difference between the max and min of a matrix of short + * is less or equal to a threshold.\n + * The matrix is stored as 1 dimension array 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 threshold threshold value allowed + * @return OK if the difference is <= to threshold otherwise + * ERROR_TEST_CHECK_FAIL + */ +int checkLimitsGap(short *data, int row, int column, int threshold) +{ + int i, j; + int min_node; + int max_node; + + if (row == 0 || column == 0) { + pr_err("checkLimitsGap: invalid number of rows = %d or columns = %d ERROR %08X\n", + row, column, ERROR_OP_NOT_ALLOW); + return ERROR_OP_NOT_ALLOW; + } + + min_node = data[0]; + max_node = data[0]; + + for (i = 0; i < row; i++) { + for (j = 0; j < column; j++) { + if (data[i * column + j] < min_node) + min_node = data[i * column + j]; + else if (data[i * column + j] > max_node) + max_node = data[i * column + j]; + } + } + + if (max_node - min_node > threshold) { + pr_err("checkLimitsGap: GAP = %d exceed limit %d\n", + max_node - min_node, threshold); + return ERROR_TEST_CHECK_FAIL; + } else + return OK; +} + +/** + * Check that each value of a matrix of i8 doesn't exceed a specific min and + * Max value set for each node (these values are included in the interval). \n + * 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 checkLimitsMap(i8 *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_err("checkLimitsMap: Node[%d,%d] = %d exceed limit [%d, %d]\n", + 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 */ +} + +/** + * 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 checkLimitsMapTotal(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_err("checkLimitsMapTotal: Node[%d,%d] = %d exceed limit [%d, %d]\n", + 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 */ +} + +/** + * Check that each value of a matrix of u8 doesn't exceed a specific min and + * Max value set for each node (these values are included in the interval). \n + * 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 checkLimitsMapFromU(u8 *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_err("checkLimitsMap: Node[%d,%d] = %d exceed limit [%d, %d]\n", + 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 */ +} + +/** + * Check that each value of a matrix of u16 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 checkLimitsMapTotalFromU(u16 *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_err("checkLimitsMapTotal: Node[%d,%d] = %d exceed limit [%d, %d]\n", + 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 */ +} + +/** + * Check that each value of a matrix of u8 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 checkLimitsMapAdj(u8 *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("checkLimitsMapAdj: Node[%d,%d] = %d exceed limit > %d\n", + i, j, + data[i * column + j], + max[i * column + j]); + count++; + } + } + } + + return count; /* if count is 0 = OK, test completed successfully */ +} + +/** + * 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 checkLimitsMapAdjTotal(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("checkLimitsMapAdjTotal: Node[%d,%d] = %d exceed limit > %d\n", + i, j, + data[i * column + j], + max[i * column + j]); + count++; + } + } + } + + return count; /* if count is 0 = OK, test completed successfully */ +} + +/** + * Perform an ITO test setting all the possible options + * (see @link ito_opt ITO Options @endlink) and checking MS Raw ADJ if enabled + * @param path_limits name of Production Limit file to load or + * "NULL" if the limits data should be loaded by a .h file + * @param todo pointer to a TestToDo variable which select the test to do + * @return OK if success or an error code which specify the type of error + */ +int production_test_ito(char *path_limits, TestToDo *todo) +{ + int res = OK; + u8 sett[2] = { 0x00, 0x00 }; + MutualSenseFrame msRawFrame; + int *thresholds = NULL; + u16 *adj = NULL; + int trows, tcolumns; + + pr_info("ITO Production test is starting...\n"); + + res = fts_system_reset(); + if (res < 0) { + pr_err("%s: ERROR %08X\n", __func__, ERROR_PROD_TEST_ITO); + return res | ERROR_PROD_TEST_ITO; + } + + sett[0] = SPECIAL_TUNING_IOFF; + pr_info("Trimming Ioff...\n"); + res = writeSysCmd(SYS_CMD_SPECIAL_TUNING, sett, 2); + if (res < OK) { + pr_err("production_test_ito: Trimm Ioff ERROR %08X\n", + (res | ERROR_PROD_TEST_ITO)); + return res | ERROR_PROD_TEST_ITO; + } + + sett[0] = 0xFF; + sett[1] = 0xFF; + pr_info("ITO Check command sent...\n"); + res = writeSysCmd(SYS_CMD_ITO, sett, 2); + if (res < OK) { + pr_err("production_test_ito: ERROR %08X\n", + (res | ERROR_PROD_TEST_ITO)); + return res | ERROR_PROD_TEST_ITO; + } + + pr_info("ITO Command = OK!\n"); + + pr_info("MS RAW ITO ADJ TEST:\n"); + if (todo->MutualRawAdjITO == 1) { + pr_info("Collecting MS Raw data...\n"); + res |= getMSFrame3(MS_RAW, &msRawFrame); + if (res < OK) { + pr_err("%s: getMSFrame failed... ERROR %08X\n", + __func__, ERROR_PROD_TEST_ITO); + goto ERROR; + } + + print_frame_short("MS Raw ITO frame =", + array1dTo2d_short( + msRawFrame.node_data, + msRawFrame.node_data_size, + msRawFrame.header.sense_node), + msRawFrame.header.force_node, + msRawFrame.header.sense_node); + + pr_info("MS RAW ITO ADJ HORIZONTAL TEST:\n"); + res = computeAdjHorizTotal(msRawFrame.node_data, + msRawFrame.header.force_node, + msRawFrame.header.sense_node, + &adj); + if (res < OK) { + pr_err("%s: computeAdjHoriz failed... ERROR %08X\n", + __func__, ERROR_PROD_TEST_ITO); + goto ERROR; + } + + res = parseProductionTestLimits(path_limits, &limit_file, + MS_RAW_ITO_ADJH, &thresholds, + &trows, &tcolumns); + if (res < OK || (trows != msRawFrame.header.force_node || + tcolumns != msRawFrame.header.sense_node - + 1)) { + pr_err("%s: parseProductionTestLimits MS_RAW_ITO_ADJH failed... ERROR %08X\n", + __func__, ERROR_PROD_TEST_DATA); + goto ERROR; + } + + + res = checkLimitsMapAdjTotal(adj, msRawFrame.header.force_node, + msRawFrame.header.sense_node - 1, + thresholds); + if (res != OK) { + pr_err("production_test_data: checkLimitsAdj MS RAW ITO ADJH failed... ERROR COUNT = %d\n", + res); + pr_err("MS RAW ITO ADJ HORIZONTAL TEST:.................FAIL\n\n"); + res = ERROR_PROD_TEST_ITO; + goto ERROR; + } else + pr_info("MS RAW ITO ADJ HORIZONTAL TEST:.................OK\n"); + + kfree(thresholds); + thresholds = NULL; + + kfree(adj); + adj = NULL; + + pr_info("MS RAW ITO ADJ VERTICAL TEST:\n"); + res = computeAdjVertTotal(msRawFrame.node_data, + msRawFrame.header.force_node, + msRawFrame.header.sense_node, + &adj); + if (res < OK) { + pr_err("%s: computeAdjVert failed... ERROR %08X\n", + __func__, ERROR_PROD_TEST_ITO); + goto ERROR; + } + + res = parseProductionTestLimits(path_limits, &limit_file, + MS_RAW_ITO_ADJV, &thresholds, + &trows, &tcolumns); + if (res < OK || (trows != msRawFrame.header.force_node - 1 || + tcolumns != msRawFrame.header.sense_node)) { + pr_err("%s: parseProductionTestLimits MS_RAW_ITO_ADJV failed... ERROR %08X\n", + __func__, ERROR_PROD_TEST_ITO); + goto ERROR; + } + + + res = checkLimitsMapAdjTotal(adj, msRawFrame.header.force_node - + 1, msRawFrame.header.sense_node, + thresholds); + if (res != OK) { + pr_err("%s: checkLimitsAdj MS RAW ITO ADJV failed... ERROR COUNT = %d\n", + __func__, res); + pr_err("MS RAW ITO ADJ VERTICAL TEST:.................FAIL\n\n"); + res = ERROR_PROD_TEST_ITO; + goto ERROR; + } else + pr_info("MS RAW ITO ADJ VERTICAL TEST:.................OK\n"); + + kfree(thresholds); + thresholds = NULL; + + kfree(adj); + adj = NULL; + } else + pr_info("MS RAW ITO ADJ TEST:.................SKIPPED\n"); + +ERROR: + if (thresholds != NULL) + kfree(thresholds); + if (adj != NULL) + kfree(adj); + if (msRawFrame.node_data != NULL) + kfree(msRawFrame.node_data); + freeLimitsFile(&limit_file); + res |= fts_system_reset(); + if (res < OK) { + pr_err("production_test_ito: ERROR %08X\n", + ERROR_PROD_TEST_ITO); + res = (res | ERROR_PROD_TEST_ITO); + } + return res; +} + +/** + * Perform the Initialization of the IC + * @param type type of initialization to do + * (see @link sys_special_opt Initialization Options (Full or Panel) @endlink) + * @return OK if success or an error code which specify the type of error + */ +int production_test_initialization(u8 type) +{ + int res; + + pr_info("INITIALIZATION Production test is starting...\n"); + if (type != SPECIAL_PANEL_INIT && type != SPECIAL_FULL_PANEL_INIT) { + pr_err("production_test_initialization: Type incompatible! Type = %02X ERROR %08X\n", + type, ERROR_OP_NOT_ALLOW | + ERROR_PROD_TEST_INITIALIZATION); + return ERROR_OP_NOT_ALLOW | ERROR_PROD_TEST_INITIALIZATION; + } + + res = fts_system_reset(); + if (res < 0) { + pr_err("production_test_initialization: ERROR %08X\n", + ERROR_PROD_TEST_INITIALIZATION); + return res | ERROR_PROD_TEST_INITIALIZATION; + } + + pr_info("INITIALIZATION command sent... %02X\n", type); + res = writeSysCmd(SYS_CMD_SPECIAL, &type, 1); + if (res < OK) { + pr_err("production_test_initialization: ERROR %08X\n", + (res | ERROR_PROD_TEST_INITIALIZATION)); + return res | ERROR_PROD_TEST_INITIALIZATION; + } + + + pr_info("Refresh Sys Info...\n"); + res |= readSysInfo(1); /* need to update the chipInfo in order + * to refresh several versions */ + + if (res < 0) { + pr_err("production_test_initialization: read sys info ERROR %08X\n", + ERROR_PROD_TEST_INITIALIZATION); + res = (res | ERROR_PROD_TEST_INITIALIZATION); + } + + return res; +} + + +// @param signature value of the MP flag to save if the Mass Production Test succeed +/** + * Perform a FULL (ITO + INIT + DATA CHECK) Mass Production Test of the IC + * @param pathThresholds 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 + * otherwise it keeps going performing all the selected test + * @param saveInit if >0 (possible values: NO_INIT, SPECIAL_PANEL_INIT or + * SPECIAL_FULL_PANEL_INIT), + * the Initialization of the IC is executed otherwise it is skipped + * @param todo pointer to a TestToDo variable which select the test to do + * @return OK if success or an error code which specify the type of error + */ +int production_test_main(char *pathThresholds, int stop_on_fail, int saveInit, + TestToDo *todo) +{ + int res, ret; + + pr_info("MAIN Production test is starting...\n"); + + pr_info("ITO TEST:\n"); + res = production_test_ito(pathThresholds, todo); + if (res < 0) { + pr_err("Error during ITO TEST! ERROR %08X\n", res); + goto END;/* in case of ITO TEST failure is no sense keep going + * */ + } else + pr_info("ITO TEST OK!\n"); + + pr_info("INITIALIZATION TEST :\n"); + if (saveInit != NO_INIT) { + res = production_test_initialization((u8)saveInit); + if (res < 0) { + pr_err("Error during INITIALIZATION TEST! ERROR %08X\n", + res); + if (stop_on_fail) + goto END; + } else + pr_info("INITIALIZATION TEST OK!\n"); + } else + pr_info("INITIALIZATION TEST :................. SKIPPED\n"); + + if (saveInit == 1) { + pr_info("Cleaning up...\n"); + ret = fts_system_reset(); + if (ret < 0) { + pr_err("production_test_main: system reset ERROR %08X\n", + ret); + res |= ret; + if (stop_on_fail) + goto END; + } + } + + pr_info("PRODUCTION DATA TEST:\n"); + ret = production_test_data(pathThresholds, stop_on_fail, todo); + if (ret < 0) + pr_err("Error during PRODUCTION DATA TEST! ERROR %08X\n", ret); + else + pr_info("PRODUCTION DATA TEST OK!\n"); + + res |= ret; + /* the OR is important because if the data test is OK but + * the init test fail, the main production test result should = FAIL */ + +END: + if (res < 0) { + pr_err("MAIN Production test finished.................FAILED\n"); + return res; + } else { + pr_info("MAIN Production test finished.................OK\n"); + return OK; + } +} + +/** + * 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 stop_on_fail if 1, the test flow stops at the first data check + * failure + * otherwise it keeps going performing all the selected test + * @param todo pointer to a TestToDo variable which select the test to do + * @return OK if success or an error code which specify the type of error + */ +int production_test_ms_raw(char *path_limits, int stop_on_fail, TestToDo *todo) +{ + int ret, count_fail = 0; + MutualSenseFrame msRawFrame; + + + int *thresholds = NULL; + int trows, tcolumns; + + u16 *adj = NULL; + + /************** Mutual Sense Test *************/ + pr_info("MS RAW DATA TEST is starting...\n"); + if (todo->MutualRaw == 1 || todo->MutualRawGap == 1 || + todo->MutualRawAdj == 1) { + ret = setScanMode(SCAN_MODE_LOCKED, LOCKED_ACTIVE); + mdelay(WAIT_FOR_FRESH_FRAMES); + ret |= setScanMode(SCAN_MODE_ACTIVE, 0x00); + mdelay(WAIT_AFTER_SENSEOFF); + ret |= getMSFrame3(MS_RAW, &msRawFrame); + if (ret < OK) { + pr_err("production_test_data: getMSFrame failed... ERROR %08X\n", + ERROR_PROD_TEST_DATA); + return ret | ERROR_PROD_TEST_DATA; + } + + print_frame_short("MS Raw frame =", + array1dTo2d_short( + msRawFrame.node_data, + msRawFrame.node_data_size, + msRawFrame.header.sense_node), + msRawFrame.header.force_node, + msRawFrame.header.sense_node); + + pr_info("MS RAW MIN MAX TEST:\n"); + if (todo->MutualRaw == 1) { + ret = parseProductionTestLimits(path_limits, + &limit_file, + MS_RAW_MIN_MAX, + &thresholds, &trows, + &tcolumns); + if (ret < OK || (trows != 1 || tcolumns != 2)) { + pr_err("production_test_data: parseProductionTestLimits MS_RAW_MIN_MAX failed... ERROR %08X\n", + ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + + ret = checkLimitsMinMax(msRawFrame.node_data, + msRawFrame.header.force_node, + msRawFrame.header.sense_node, + thresholds[0], + thresholds[1]); + if (ret != OK) { + pr_err("production_test_data: checkLimitsMinMax MS RAW failed... ERROR COUNT = %d\n", + ret); + pr_err("MS RAW MIN MAX TEST:.................FAIL\n\n"); + count_fail += 1; + if (stop_on_fail == 1) + goto ERROR; + } else + pr_info("MS RAW MIN MAX TEST:.................OK\n"); + kfree(thresholds); + thresholds = NULL; + } else + pr_info("MS RAW MIN MAX TEST:.................SKIPPED\n"); + + pr_info("MS RAW GAP TEST:\n"); + if (todo->MutualRawGap == 1) { + ret = parseProductionTestLimits(path_limits, + &limit_file, MS_RAW_GAP, + &thresholds, &trows, + &tcolumns); + if (ret < 0 || (trows != 1 || tcolumns != 1)) { + pr_err("production_test_data: parseProductionTestLimits MS_RAW_GAP failed... ERROR %08X\n", + ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + ret = checkLimitsGap(msRawFrame.node_data, + msRawFrame.header.force_node, + msRawFrame.header.sense_node, + thresholds[0]); + if (ret != OK) { + pr_err("production_test_data: checkLimitsGap MS RAW failed... ERROR = %08X\n", + ret); + count_fail += 1; + if (stop_on_fail == 1) + goto ERROR; + } else + pr_info("MS RAW GAP TEST:.................OK\n\n"); + kfree(thresholds); + thresholds = NULL; + } else + pr_info("MS RAW GAP TEST:.................SKIPPED\n"); + + pr_info("MS RAW ADJ TEST:\n"); + if (todo->MutualRawAdj == 1) { + pr_info("MS RAW ADJ HORIZONTAL TEST:\n"); + ret = computeAdjHorizTotal(msRawFrame.node_data, + msRawFrame.header.force_node, + msRawFrame.header.sense_node, + &adj); + if (ret < OK) { + pr_err("production_test_data: computeAdjHoriz failed... ERROR %08X\n", + ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + ret = parseProductionTestLimits(path_limits, + &limit_file, + MS_RAW_ADJH, + &thresholds, &trows, + &tcolumns); + if (ret < OK || (trows != + msRawFrame.header.force_node || + tcolumns != + msRawFrame.header.sense_node - 1)) { + pr_err("production_test_data: parseProductionTestLimits MS_RAW_ADJH failed... ERROR %08X\n", + ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + + ret = checkLimitsMapAdjTotal(adj, + msRawFrame.header. + force_node, + msRawFrame.header. + sense_node - 1, + thresholds); + if (ret != OK) { + pr_err("production_test_data: checkLimitsAdj MS RAW ADJH failed... ERROR COUNT = %d\n", + ret); + pr_err("MS RAW ADJ HORIZONTAL TEST:.................FAIL\n\n"); + count_fail += 1; + if (stop_on_fail == 1) + goto ERROR; + } else + pr_info("MS RAW ADJ HORIZONTAL TEST:.................OK\n"); + + kfree(thresholds); + thresholds = NULL; + + kfree(adj); + adj = NULL; + + pr_info("MS RAW ADJ VERTICAL TEST:\n"); + ret = computeAdjVertTotal(msRawFrame.node_data, + msRawFrame.header.force_node, + msRawFrame.header.sense_node, + &adj); + if (ret < OK) { + pr_err("production_test_data: computeAdjVert failed... ERROR %08X\n", + ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + ret = parseProductionTestLimits(path_limits, + &limit_file, + MS_RAW_ADJV, + &thresholds, &trows, + &tcolumns); + if (ret < OK || (trows != msRawFrame.header.force_node - + 1 || tcolumns != + msRawFrame.header.sense_node)) { + pr_err("production_test_data: parseProductionTestLimits MS_RAW_ADJV failed... ERROR %08X\n", + ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + + ret = checkLimitsMapAdjTotal(adj, + msRawFrame.header. + force_node - 1, + msRawFrame.header. + sense_node, thresholds); + if (ret != OK) { + pr_err("production_test_data: checkLimitsAdj MS RAW ADJV failed... ERROR COUNT = %d\n", + ret); + pr_err("MS RAW ADJ VERTICAL TEST:.................FAIL\n\n"); + count_fail += 1; + if (stop_on_fail == 1) + goto ERROR; + } else + pr_info("MS RAW ADJ VERTICAL TEST:.................OK\n"); + kfree(thresholds); + thresholds = NULL; + + kfree(adj); + adj = NULL; + } else + pr_info("MS RAW ADJ TEST:.................SKIPPED\n"); + } else + pr_info("MS RAW FRAME TEST:.................SKIPPED\n"); + + pr_info("MS KEY RAW TEST:\n"); + if (todo->MutualKeyRaw == 1) { + ret = production_test_ms_key_raw(path_limits); + if (ret < 0) { + pr_err("production_test_data: production_test_ms_key_raw failed... ERROR = %08X\n", + ret); + count_fail += 1; + if (count_fail == 1) { + pr_err("MS RAW DATA TEST:.................FAIL fails_count = %d\n\n", + count_fail); + goto ERROR_LIMITS; + } + } + } else + pr_info("MS KEY RAW TEST:.................SKIPPED\n"); + + ret = production_test_ms_raw_lp(path_limits, stop_on_fail, todo); + if (ret < 0) { + pr_err("production_test_data: production_test_ms_raw_lp failed... ERROR = %08X\n", + ret); + count_fail += 1; + if (count_fail == 1) { + pr_err("MS RAW DATA TEST:.................FAIL fails_count = %d\n\n", + count_fail); + goto ERROR_LIMITS; + } + } + +ERROR: + + if (count_fail == 0) { + if (msRawFrame.node_data != NULL) { + kfree(msRawFrame.node_data); + msRawFrame.node_data = NULL; + } + pr_info("MS RAW DATA TEST finished!.................OK\n"); + return OK; + } else { + if (msRawFrame.node_data != NULL) + kfree(msRawFrame.node_data); + if (thresholds != NULL) + kfree(thresholds); + if (adj != NULL) + kfree(adj); + pr_err("MS RAW DATA TEST:.................FAIL fails_count = %d\n\n", + count_fail); + return ERROR_PROD_TEST_DATA | ERROR_TEST_CHECK_FAIL; + } + + +ERROR_LIMITS: + if (msRawFrame.node_data != NULL) + kfree(msRawFrame.node_data); + if (thresholds != NULL) + kfree(thresholds); + return ret; +} + + +/** + * 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 stop_on_fail if 1, the test flow stops at the first data check + * failure + * otherwise it keeps going performing all the selected test + * @param todo pointer to a TestToDo variable which select the test to do + * @return OK if success or an error code which specify the type of error + */ +int production_test_ms_raw_lp(char *path_limits, int stop_on_fail, + TestToDo *todo) +{ + int ret, count_fail = 0; + MutualSenseFrame msRawFrame; + + + int *thresholds = NULL; + int trows, tcolumns; + + u16 *adj = NULL; + + /************** Mutual Sense Test **************/ + pr_info("MS RAW LP DATA TEST:\n"); + if (todo->MutualRawLP == 1 || todo->MutualRawGapLP == 1 || + todo->MutualRawAdjLP == 1) { + ret = setScanMode(SCAN_MODE_LOCKED, LOCKED_LP_ACTIVE); + mdelay(WAIT_FOR_FRESH_FRAMES); + ret |= setScanMode(SCAN_MODE_ACTIVE, 0x00); + mdelay(WAIT_AFTER_SENSEOFF); + ret |= getMSFrame3(MS_RAW, &msRawFrame); + if (ret < 0) { + pr_err("production_test_data: getMSFrame failed... ERROR %08X\n", + ERROR_PROD_TEST_DATA); + return ret | ERROR_PROD_TEST_DATA; + } + + print_frame_short("MS Raw LP frame =", + array1dTo2d_short( + msRawFrame.node_data, + msRawFrame.node_data_size, + msRawFrame.header.sense_node), + msRawFrame.header.force_node, + msRawFrame.header.sense_node); + + pr_info("MS RAW LP MIN MAX TEST:\n"); + if (todo->MutualRawLP == 1) { + ret = parseProductionTestLimits(path_limits, + &limit_file, + MS_RAW_LP_MIN_MAX, + &thresholds, &trows, + &tcolumns); + if (ret < 0 || (trows != 1 || tcolumns != 2)) { + pr_err("production_test_data: parseProductionTestLimits MS_RAW_LP_MIN_MAX failed... ERROR %08X\n", + ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + + ret = checkLimitsMinMax(msRawFrame.node_data, + msRawFrame.header.force_node, + msRawFrame.header.sense_node, + thresholds[0], + thresholds[1]); + if (ret != OK) { + pr_err("production_test_data: checkLimitsMinMax MS RAW LP failed... ERROR COUNT = %d\n", + ret); + pr_err("MS RAW LP MIN MAX TEST:.................FAIL\n\n"); + count_fail += 1; + if (stop_on_fail == 1) + goto ERROR; + } else + pr_info("MS RAW LP MIN MAX TEST:.................OK\n"); + kfree(thresholds); + thresholds = NULL; + } else + pr_info("MS RAW LP MIN MAX TEST:.................SKIPPED\n"); + + pr_info("MS RAW LP GAP TEST:\n"); + if (todo->MutualRawGapLP == 1) { + ret = parseProductionTestLimits(path_limits, + &limit_file, + MS_RAW_LP_GAP, + &thresholds, &trows, + &tcolumns); + if (ret < 0 || (trows != 1 || tcolumns != 1)) { + pr_err("production_test_data: parseProductionTestLimits MS_RAW_LP_GAP failed... ERROR %08X\n", + ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + ret = checkLimitsGap(msRawFrame.node_data, + msRawFrame.header.force_node, + msRawFrame.header.sense_node, + thresholds[0]); + if (ret != OK) { + pr_err("production_test_data: checkLimitsGap MS RAW LP failed... ERROR = %08X\n", + ret); + count_fail += 1; + if (stop_on_fail == 1) + goto ERROR; + } else + pr_info("MS RAW LP GAP TEST:.................OK\n\n"); + kfree(thresholds); + thresholds = NULL; + } else + pr_info("MS RAW LP GAP TEST:.................SKIPPED\n"); + + pr_info("MS RAW LP ADJ TEST:\n"); + if (todo->MutualRawAdjLP == 1) { + pr_info("MS RAW LP ADJ HORIZONTAL TEST:\n"); + ret = computeAdjHorizTotal(msRawFrame.node_data, + msRawFrame.header.force_node, + msRawFrame.header.sense_node, + &adj); + if (ret < 0) { + pr_err("production_test_data: computeAdjHoriz failed... ERROR %08X\n", + ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + ret = parseProductionTestLimits(path_limits, + &limit_file, + MS_RAW_LP_ADJH, + &thresholds, &trows, + &tcolumns); + if (ret < 0 || (trows != msRawFrame.header.force_node || + tcolumns != + msRawFrame.header.sense_node - 1)) { + pr_err("production_test_data: parseProductionTestLimits MS_RAW_LP_ADJH failed... ERROR %08X\n", + ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + + ret = checkLimitsMapAdjTotal(adj, + msRawFrame.header. + force_node, + msRawFrame.header. + sense_node - 1, + thresholds); + if (ret != OK) { + pr_err("production_test_data: checkLimitsAdj MS RAW LP ADJH failed... ERROR COUNT = %d\n", + ret); + pr_err("MS RAW LP ADJ HORIZONTAL TEST:.................FAIL\n\n"); + count_fail += 1; + if (stop_on_fail == 1) + goto ERROR; + } else + pr_info("MS RAW LP ADJ HORIZONTAL TEST:.................OK\n"); + + kfree(thresholds); + thresholds = NULL; + + kfree(adj); + adj = NULL; + + pr_info("MS RAW LP ADJ VERTICAL TEST:\n"); + ret = computeAdjVertTotal(msRawFrame.node_data, + msRawFrame.header.force_node, + msRawFrame.header.sense_node, + &adj); + if (ret < 0) { + pr_err("production_test_data: computeAdjVert failed... ERROR %08X\n", + ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + ret = parseProductionTestLimits(path_limits, + &limit_file, + MS_RAW_LP_ADJV, + &thresholds, &trows, + &tcolumns); + if (ret < 0 || (trows != msRawFrame.header.force_node - + 1 || tcolumns != + msRawFrame.header.sense_node)) { + pr_err("production_test_data: parseProductionTestLimits MS_RAW_ADJV failed... ERROR %08X\n", + ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + + ret = checkLimitsMapAdjTotal(adj, + msRawFrame.header. + force_node - 1, + msRawFrame.header. + sense_node, thresholds); + if (ret != OK) { + pr_err("production_test_data: checkLimitsAdj MS RAW ADJV failed... ERROR COUNT = %d\n", + ret); + pr_err("MS RAW LP ADJ VERTICAL TEST:.................FAIL\n\n"); + count_fail += 1; + if (stop_on_fail == 1) + goto ERROR; + } else + pr_info("MS RAW LP ADJ VERTICAL TEST:.................OK\n"); + kfree(thresholds); + thresholds = NULL; + + kfree(adj); + adj = NULL; + } else + pr_info("MS RAW LP ADJ TEST:.................SKIPPED\n"); + } else + pr_info("MS RAW LP FRAME TEST:.................SKIPPED\n"); + +ERROR: + if (count_fail == 0) { + if (msRawFrame.node_data != NULL) { + kfree(msRawFrame.node_data); + msRawFrame.node_data = NULL; + } + pr_info("MS RAW DATA TEST finished!.................OK\n"); + return OK; + } else { + if (msRawFrame.node_data != NULL) + kfree(msRawFrame.node_data); + if (thresholds != NULL) + kfree(thresholds); + if (adj != NULL) + kfree(adj); + pr_err("MS RAW LP DATA TEST:.................FAIL fails_count = %d\n\n", + count_fail); + return ERROR_PROD_TEST_DATA | ERROR_TEST_CHECK_FAIL; + } + + +ERROR_LIMITS: + if (msRawFrame.node_data != NULL) + kfree(msRawFrame.node_data); + if (thresholds != NULL) + kfree(thresholds); + return ret; +} + +/** + * Perform MS raw test for keys data + * @param path_limits name of Production Limit file to load or + * "NULL" if the limits data should be loaded by a .h file + * @return OK if success or an error code which specify the type of error + */ +int production_test_ms_key_raw(char *path_limits) +{ + int ret; + MutualSenseFrame msRawFrame; + + int *thresholds = NULL; + int trows, tcolumns; + + /************** Mutual Sense Test **************/ + pr_info("MS KEY RAW DATA TEST is starting...\n"); + ret = setScanMode(SCAN_MODE_ACTIVE, 0xFF); + mdelay(WAIT_FOR_FRESH_FRAMES); + ret |= setScanMode(SCAN_MODE_ACTIVE, 0x00); + mdelay(WAIT_AFTER_SENSEOFF); + ret |= getMSFrame3(MS_KEY_RAW, &msRawFrame); + if (ret < 0) { + pr_err("production_test_data: getMSKeyFrame failed... ERROR %08X\n", + ERROR_PROD_TEST_DATA); + return ret | ERROR_PROD_TEST_DATA; + } + + ret = parseProductionTestLimits(path_limits, &limit_file, + MS_KEY_RAW_MIN_MAX, &thresholds, &trows, + &tcolumns); + if (ret < 0 || (trows != 1 || tcolumns != 2)) { + pr_err("production_test_data: parseProductionTestLimits MS_KEY_RAW_MIN_MAX failed... ERROR %08X\n", + ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + ret = checkLimitsMinMax(msRawFrame.node_data, + msRawFrame.header.force_node, + msRawFrame.header.sense_node, + thresholds[0], thresholds[1]); + if (ret != OK) { + pr_err("production_test_data: checkLimitsMinMax MS KEY RAW failed... ERROR COUNT = %d\n", + ret); + goto ERROR; + } else + pr_info("MS KEY RAW TEST:.................OK\n\n"); + + kfree(thresholds); + thresholds = NULL; + + kfree(msRawFrame.node_data); + msRawFrame.node_data = NULL; + return OK; + +ERROR: + print_frame_short("MS Key Raw frame =", array1dTo2d_short( + msRawFrame.node_data, + msRawFrame.node_data_size, + msRawFrame.header.sense_node), + msRawFrame.header.force_node, + msRawFrame.header.sense_node); + if (msRawFrame.node_data != NULL) + kfree(msRawFrame.node_data); + if (thresholds != NULL) + kfree(thresholds); + pr_err("MS KEY RAW TEST:.................FAIL\n\n"); + return ERROR_PROD_TEST_DATA | ERROR_TEST_CHECK_FAIL; + +ERROR_LIMITS: + if (msRawFrame.node_data != NULL) + kfree(msRawFrame.node_data); + if (thresholds != NULL) + kfree(thresholds); + return ret; +} + +/** + * Perform all the tests selected in a TestTodo variable related to MS 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 + * otherwise it keeps going performing all the selected test + * @param todo pointer to a TestToDo variable which select the test to do + * @return OK if success or an error code which specify the type of error + */ +int production_test_ms_cx(char *path_limits, int stop_on_fail, TestToDo *todo) +{ + int ret; + int count_fail = 0; + + int *thresholds = NULL; + int *thresholds_min = NULL; + int *thresholds_max = NULL; + int trows, tcolumns; + + MutualSenseData msCompData; + TotMutualSenseData totCompData; + + u8 *adjhor = NULL; + + u8 *adjvert = NULL; + + u16 container; + /* u16 *total_cx = NULL; */ + u16 *total_adjhor = NULL; + u16 *total_adjvert = NULL; + + + /* MS CX TEST */ + pr_info("MS CX Testes are starting...\n"); + + ret = readMutualSenseCompensationData(LOAD_CX_MS_TOUCH, &msCompData); + /* read MS compensation data */ + if (ret < 0) { + pr_err("production_test_data: readMutualSenseCompensationData failed... ERROR %08X\n", + ERROR_PROD_TEST_DATA); + return ret | ERROR_PROD_TEST_DATA; + } + + ret = readTotMutualSenseCompensationData(LOAD_PANEL_CX_TOT_MS_TOUCH, + &totCompData); + /* read TOT MS compensation data */ + if (ret < 0) { + pr_err("production_test_data: readTotMutualSenseCompensationData failed... ERROR %08X\n", + ERROR_PROD_TEST_DATA); + kfree(msCompData.node_data); + msCompData.node_data = NULL; + return ret | ERROR_PROD_TEST_DATA; + } + + pr_info("MS CX1 TEST:\n"); + if (todo->MutualCx1 == 1) { + ret = parseProductionTestLimits(path_limits, &limit_file, + MS_CX1_MIN_MAX, &thresholds, + &trows, &tcolumns); + if (ret < 0 || (trows != 1 || tcolumns != 2)) { + pr_err("production_test_data: parseProductionTestLimits MS_CX1_MIN_MAX failed... ERROR %08X\n", + ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + container = (u16)msCompData.cx1; + ret = checkLimitsMinMax(&container, 1, 1, thresholds[0], + thresholds[1]); + /* check the limits */ + if (ret != OK) { + pr_err("production_test_data: checkLimitsMinMax MS CX1 failed... ERROR COUNT = %d\n", + ret); + pr_err("MS CX1 TEST:.................FAIL\n\n"); + count_fail += 1; + if (stop_on_fail) + goto ERROR; + } else + pr_info("MS CX1 TEST:.................OK\n\n"); + } else + pr_info("MS CX1 TEST:.................SKIPPED\n\n"); + + kfree(thresholds); + thresholds = NULL; + + pr_info("MS CX2 MIN MAX TEST:\n"); + if (todo->MutualCx2 == 1) { + ret = parseProductionTestLimits(path_limits, &limit_file, + MS_CX2_MAP_MIN, &thresholds_min, + &trows, &tcolumns); + /* load min thresholds */ + if (ret < 0 || (trows != msCompData.header.force_node || + tcolumns != msCompData.header.sense_node)) { + pr_err("production_test_data: parseProductionTestLimits MS_CX2_MAP_MIN failed... ERROR %08X\n", + ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + ret = parseProductionTestLimits(path_limits, &limit_file, + MS_CX2_MAP_MAX, &thresholds_max, + &trows, &tcolumns); + /* load max thresholds */ + if (ret < 0 || (trows != msCompData.header.force_node || + tcolumns != msCompData.header.sense_node)) { + pr_err("production_test_data: parseProductionTestLimits MS_CX2_MAP_MAX failed... ERROR %08X\n", + ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + ret = checkLimitsMap(msCompData.node_data, + msCompData.header.force_node, + msCompData.header.sense_node, + thresholds_min, thresholds_max); + /* check the limits */ + if (ret != OK) { + pr_err("production_test_data: checkLimitsMap MS CX2 MIN MAX failed... ERROR COUNT = %d\n", + ret); + pr_err("MS CX2 MIN MAX TEST:.................FAIL\n\n"); + count_fail += 1; + if (stop_on_fail) + goto ERROR; + } else + pr_info("MS CX2 MIN MAX TEST:.................OK\n\n"); + + kfree(thresholds_min); + thresholds_min = NULL; + kfree(thresholds_max); + thresholds_max = NULL; + } else + pr_info("MS CX2 MIN MAX TEST:.................SKIPPED\n\n"); + + pr_info("MS CX2 ADJ TEST:\n"); + if (todo->MutualCx2Adj == 1) { + /* MS CX2 ADJ HORIZ */ + pr_info("MS CX2 ADJ HORIZ TEST:\n"); + + ret = computeAdjHoriz(msCompData.node_data, + msCompData.header.force_node, + msCompData.header.sense_node, + &adjhor); + if (ret < 0) { + pr_err("production_test_data: computeAdjHoriz failed... ERROR %08X\n", + ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + pr_info("MS CX2 ADJ HORIZ computed!\n"); + + ret = parseProductionTestLimits(path_limits, &limit_file, + MS_CX2_ADJH_MAP_MAX, + &thresholds_max, &trows, + &tcolumns); + if (ret < 0 || (trows != msCompData.header.force_node || + tcolumns != msCompData.header.sense_node - 1)) { + pr_err("production_test_data: parseProductionTestLimits MS_CX2_ADJH_MAP_MAX failed... ERROR %08X\n", + ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + ret = checkLimitsMapAdj(adjhor, msCompData.header.force_node, + msCompData.header.sense_node - 1, + thresholds_max); + if (ret != OK) { + pr_err("production_test_data: checkLimitsMapAdj CX2 ADJH failed... ERROR COUNT = %d\n", + ret); + pr_err("MS CX2 ADJ HORIZ TEST:.................FAIL\n\n"); + count_fail += 1; + if (stop_on_fail) + goto ERROR; + } else + pr_info("MS CX2 ADJ HORIZ TEST:.................OK\n\n"); + + kfree(thresholds_max); + thresholds_max = NULL; + kfree(adjhor); + adjhor = NULL; + + /* MS CX2 ADJ VERT */ + pr_info("MS CX2 ADJ VERT TEST:\n"); + + ret = computeAdjVert(msCompData.node_data, + msCompData.header.force_node, + msCompData.header.sense_node, + &adjvert); + if (ret < 0) { + pr_err("production_test_data: computeAdjVert failed... ERROR %08X\n", + ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + pr_info("MS CX2 ADJ VERT computed!\n"); + + ret = parseProductionTestLimits(path_limits, &limit_file, + MS_CX2_ADJV_MAP_MAX, + &thresholds_max, &trows, + &tcolumns); + if (ret < 0 || (trows != msCompData.header.force_node - 1 || + tcolumns != msCompData.header.sense_node)) { + pr_err("production_test_data: parseProductionTestLimits MS_CX2_ADJV_MAP_MAX failed... ERROR %08X\n", + ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + ret = checkLimitsMapAdj(adjvert, msCompData.header.force_node - + 1, msCompData.header.sense_node - 1, + thresholds_max); + if (ret != OK) { + pr_err("production_test_data: checkLimitsMapAdj CX2 ADJV failed... ERROR COUNT = %d\n", + ret); + pr_err("MS CX2 ADJ HORIZ TEST:.................FAIL\n\n"); + count_fail += 1; + if (stop_on_fail) + goto ERROR; + } else + pr_info("MS CX2 ADJ VERT TEST:.................OK\n\n"); + + kfree(thresholds_max); + thresholds_max = NULL; + kfree(adjvert); + adjvert = NULL; + } else + pr_info("MS CX2 ADJ TEST:.................SKIPPED\n\n"); + + /* START OF TOTAL CHECK */ + pr_info("MS TOTAL CX TEST:\n"); + + if (todo->MutualCxTotal == 1 || todo->MutualCxTotalAdj == 1) { + pr_info("MS TOTAL CX MIN MAX TEST:\n"); + if (todo->MutualCxTotal == 1) { + ret = parseProductionTestLimits(path_limits, + &limit_file, + MS_TOTAL_CX_MAP_MIN, + &thresholds_min, + &trows, &tcolumns); + /* load min thresholds */ + if (ret < 0 || (trows != + totCompData.header.force_node || + tcolumns != + totCompData.header.sense_node)) { + pr_err("production_test_data: parseProductionTestLimits MS_TOTAL_CX_MAP_MIN failed... ERROR %08X\n", + ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + ret = parseProductionTestLimits(path_limits, + &limit_file, + MS_TOTAL_CX_MAP_MAX, + &thresholds_max, + &trows, &tcolumns); + /* load max thresholds */ + if (ret < 0 || (trows != + totCompData.header.force_node || + tcolumns != + totCompData.header.sense_node)) { + pr_err("production_test_data: parseProductionTestLimits MS_TOTAL_CX_MAP_MAX failed... ERROR %08X\n", + ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + ret = checkLimitsMapTotal(totCompData.node_data, + totCompData.header.force_node, + totCompData.header.sense_node, + thresholds_min, + thresholds_max); + /* check the limits */ + if (ret != OK) { + pr_err("production_test_data: checkLimitsMap MS TOTAL CX TEST failed... ERROR COUNT = %d\n", + ret); + pr_err("MS TOTAL CX MIN MAX TEST:.................FAIL\n\n"); + count_fail += 1; + if (stop_on_fail) + goto ERROR; + } else + pr_info("MS TOTAL CX MIN MAX TEST:.................OK\n\n"); + + kfree(thresholds_min); + thresholds_min = NULL; + kfree(thresholds_max); + thresholds_max = NULL; + } else + pr_info("MS TOTAL CX MIN MAX TEST:.................SKIPPED\n\n"); + + + pr_info("MS TOTAL CX ADJ TEST:\n"); + if (todo->MutualCxTotalAdj == 1) { + /* MS TOTAL CX ADJ HORIZ */ + pr_info("MS TOTAL CX ADJ HORIZ TEST:\n"); + + ret = computeAdjHorizTotal(totCompData.node_data, + totCompData.header.force_node, + totCompData.header.sense_node, + &total_adjhor); + if (ret < 0) { + pr_err("production_test_data: computeAdjHoriz failed... ERROR %08X\n", + ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + pr_info("MS TOTAL CX ADJ HORIZ computed!\n"); + + ret = parseProductionTestLimits(path_limits, + &limit_file, + MS_TOTAL_CX_ADJH_MAP_MAX, + &thresholds_max, + &trows, &tcolumns); + if (ret < 0 || (trows != + totCompData.header.force_node || + tcolumns != + totCompData.header.sense_node - 1)) { + pr_err("production_test_data: parseProductionTestLimits MS_TOTAL_CX_ADJH_MAP_MAX failed... ERROR %08X\n", + ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + ret = checkLimitsMapAdjTotal(total_adjhor, + totCompData.header. + force_node, + totCompData.header. + sense_node - 1, + thresholds_max); + if (ret != OK) { + pr_err("production_test_data: checkLimitsMapAdj MS TOTAL CX ADJH failed... ERROR COUNT = %d\n", + ret); + pr_err("MS TOTAL CX ADJ HORIZ TEST:.................FAIL\n\n"); + count_fail += 1; + if (stop_on_fail) + goto ERROR; + } else + pr_info("MS TOTAL CX ADJ HORIZ TEST:.................OK\n\n"); + + kfree(thresholds_max); + thresholds_max = NULL; + kfree(total_adjhor); + total_adjhor = NULL; + + /* MS TOTAL CX ADJ VERT */ + pr_info("MS TOTAL CX ADJ VERT TEST:\n"); + + ret = computeAdjVertTotal(totCompData.node_data, + totCompData.header.force_node, + totCompData.header.sense_node, + &total_adjvert); + if (ret < 0) { + pr_err("production_test_data: computeAdjVert failed... ERROR %08X\n", + ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + pr_info("MS TOTAL CX ADJ VERT computed!\n"); + + ret = parseProductionTestLimits(path_limits, + &limit_file, + MS_TOTAL_CX_ADJV_MAP_MAX, + &thresholds_max, + &trows, &tcolumns); + if (ret < 0 || (trows != totCompData.header.force_node - + 1 || tcolumns != + totCompData.header.sense_node)) { + pr_err("production_test_data: parseProductionTestLimits MS_TOTAL_CX_ADJV_MAP_MAX failed... ERROR %08X\n", + ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + ret = checkLimitsMapAdjTotal(total_adjvert, + totCompData.header. + force_node - 1, + totCompData.header. + sense_node - 1, + thresholds_max); + if (ret != OK) { + pr_err("production_test_data: checkLimitsMapAdj MS TOTAL CX ADJV failed... ERROR COUNT = %d\n", + ret); + pr_err("MS TOTAL CX ADJ HORIZ TEST:.................FAIL\n"); + count_fail += 1; + if (stop_on_fail) + goto ERROR; + } else + pr_info("MS TOTAL CX ADJ VERT TEST:.................OK\n"); + + kfree(thresholds_max); + thresholds_max = NULL; + kfree(total_adjvert); + total_adjvert = NULL; + } else + pr_info("MS TOTAL CX ADJ TEST:.................SKIPPED\n"); + + kfree(totCompData.node_data); + totCompData.node_data = NULL; + } else + pr_info("MS TOTAL CX TEST:.................SKIPPED\n"); + + + + if ((todo->MutualKeyCx1 | todo->MutualKeyCx2 | + todo->MutualKeyCxTotal) == 1) { + ret = production_test_ms_key_cx(path_limits, stop_on_fail, + todo); + if (ret < 0) { + count_fail += 1; + pr_err("production_test_data: production_test_ms_key_cx failed... ERROR = %08X\n", + ret); + pr_err("MS CX testes finished!.................FAILED fails_count = %d\n\n", + count_fail); + return ret; + } + } else + pr_info("MS KEY CX TEST:.................SKIPPED\n"); + +ERROR: + + if (count_fail == 0) { + pr_info("MS CX testes finished!.................OK\n"); + kfree(msCompData.node_data); + msCompData.node_data = NULL; + return OK; + } else { + print_frame_i8("MS Init Data (Cx2) =", array1dTo2d_i8( + msCompData.node_data, + msCompData.node_data_size, + msCompData.header.sense_node), + msCompData.header.force_node, + msCompData.header.sense_node); + print_frame_short(" TOT MS Init Data (Cx) =", array1dTo2d_short( + totCompData.node_data, + totCompData.node_data_size, + totCompData.header.sense_node), + totCompData.header.force_node, + totCompData.header.sense_node); + pr_err("MS CX testes finished!.................FAILED fails_count = %d\n\n", + count_fail); + if (thresholds != NULL) + kfree(thresholds); + if (thresholds_min != NULL) + kfree(thresholds_min); + if (thresholds_max != NULL) + kfree(thresholds_max); + if (adjhor != NULL) + kfree(adjhor); + if (adjvert != NULL) + kfree(adjvert); + if (totCompData.node_data != NULL) + kfree(totCompData.node_data); + if (total_adjhor != NULL) + kfree(total_adjhor); + if (total_adjvert != NULL) + kfree(total_adjvert); + if (msCompData.node_data != NULL) + kfree(msCompData.node_data); + return ERROR_TEST_CHECK_FAIL | ERROR_PROD_TEST_DATA; + } + +ERROR_LIMITS: + if (thresholds != NULL) + kfree(thresholds); + if (thresholds_min != NULL) + kfree(thresholds_min); + if (thresholds_max != NULL) + kfree(thresholds_max); + if (adjhor != NULL) + kfree(adjhor); + if (adjvert != NULL) + kfree(adjvert); + if (totCompData.node_data != NULL) + kfree(totCompData.node_data); + if (total_adjhor != NULL) + kfree(total_adjhor); + if (total_adjvert != NULL) + kfree(total_adjvert); + if (msCompData.node_data != NULL) + kfree(msCompData.node_data); + return ret; +} + +/** + * Perform all the tests selected in a TestTodo variable related to MS Init + * data of the keys + * @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 + * otherwise it keeps going performing all the selected test + * @param todo pointer to a TestToDo variable which select the test to do + * @return OK if success or an error code which specify the type of error + */ +int production_test_ms_key_cx(char *path_limits, int stop_on_fail, + TestToDo *todo) +{ + int ret; + int count_fail = 0; + int num_keys = 0; + + int *thresholds = NULL; + int *thresholds_min = NULL; + int *thresholds_max = NULL; + int trows, tcolumns; + + MutualSenseData msCompData; + TotMutualSenseData totCompData; + + + short container; + + + /* MS CX TEST */ + pr_info("MS KEY CX Testes are starting...\n"); + + ret = readMutualSenseCompensationData(LOAD_CX_MS_KEY, &msCompData); + /* read MS compensation data */ + if (ret < 0) { + pr_err("production_test_data: readMutualSenseCompensationData failed... ERROR %08X\n", + ERROR_PROD_TEST_DATA); + return ret | ERROR_PROD_TEST_DATA; + } + + if (msCompData.header.force_node > msCompData.header.sense_node) + /* the meaningful data are only in the first row, + * the other rows are only a copy of the first one */ + num_keys = msCompData.header.force_node; + else + num_keys = msCompData.header.sense_node; + + pr_info("MS KEY CX1 TEST:\n"); + if (todo->MutualKeyCx1 == 1) { + ret = parseProductionTestLimits(path_limits, &limit_file, + MS_KEY_CX1_MIN_MAX, &thresholds, + &trows, &tcolumns); + if (ret < 0 || (trows != 1 || tcolumns != 2)) { + pr_err("production_test_data: parseProductionTestLimits MS_KEY_CX1_MIN_MAX failed... ERROR %08X\n", + ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + container = (short)msCompData.cx1; + ret = checkLimitsMinMax(&container, 1, 1, thresholds[0], + thresholds[1]); + /* check the limits */ + if (ret != OK) { + pr_err("production_test_data: checkLimitsMinMax MS CX1 failed... ERROR COUNT = %d\n", + ret); + pr_err("MS KEY CX1 TEST:.................FAIL\n\n"); + count_fail += 1; + if (stop_on_fail) + goto ERROR; + } else + pr_info("MS KEY CX1 TEST:.................OK\n\n"); + } else + pr_info("MS KEY CX1 TEST:.................SKIPPED\n\n"); + + kfree(thresholds); + thresholds = NULL; + + pr_info("MS KEY CX2 TEST:\n"); + if (todo->MutualKeyCx2 == 1) { + ret = parseProductionTestLimits(path_limits, &limit_file, + MS_KEY_CX2_MAP_MIN, + &thresholds_min, &trows, + &tcolumns); + /* load min thresholds */ + if (ret < 0 || (trows != msCompData.header.force_node || + tcolumns != msCompData.header.sense_node)) { + pr_err("production_test_data: parseProductionTestLimits MS_KEY_CX2_MAP_MIN failed... ERROR %08X\n", + ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + ret = parseProductionTestLimits(path_limits, &limit_file, + MS_KEY_CX2_MAP_MAX, + &thresholds_max, &trows, + &tcolumns); + /* load max thresholds */ + if (ret < 0 || (trows != msCompData.header.force_node || + tcolumns != msCompData.header.sense_node)) { + pr_err("production_test_data: parseProductionTestLimits MS_KEY_CX2_MAP_MAX failed... ERROR %08X\n", + ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + ret = checkLimitsMap(msCompData.node_data, + msCompData.header.force_node, + msCompData.header.sense_node, + thresholds_min, thresholds_max); + /* check the limits */ + if (ret != OK) { + pr_err("production_test_data: checkLimitsMap MS KEY CX2 failed... ERROR COUNT = %d\n", + ret); + pr_err("MS KEY CX2 TEST:.................FAIL\n\n"); + count_fail += 1; + if (stop_on_fail) + goto ERROR; + } else + pr_info("MS KEY CX2 TEST:.................OK\n\n"); + + kfree(thresholds_min); + thresholds_min = NULL; + kfree(thresholds_max); + thresholds_max = NULL; + } else + pr_info("MS CX2 TEST:.................SKIPPED\n\n"); + + /* START OF TOTAL CHECK */ + pr_info("MS KEY TOTAL CX TEST:\n"); + + if (todo->MutualKeyCxTotal == 1) { + ret = readTotMutualSenseCompensationData( + LOAD_PANEL_CX_TOT_MS_KEY, &totCompData); + if (ret < 0) { + pr_err("production_test_data: computeTotalCx failed... ERROR %08X\n", + ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + ret = parseProductionTestLimits(path_limits, &limit_file, + MS_KEY_TOTAL_CX_MAP_MIN, + &thresholds_min, &trows, + &tcolumns); + /* load min thresholds */ + if (ret < 0 || (trows != totCompData.header.force_node || + tcolumns != totCompData.header.sense_node)) { + pr_err("production_test_data: parseProductionTestLimits MS_KEY_TOTAL_CX_MAP_MIN failed... ERROR %08X\n", + ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + ret = parseProductionTestLimits(path_limits, &limit_file, + MS_KEY_TOTAL_CX_MAP_MAX, + &thresholds_max, &trows, + &tcolumns); + /* load max thresholds */ + if (ret < 0 || (trows != totCompData.header.force_node || + tcolumns != totCompData.header.sense_node)) { + pr_err("production_test_data: parseProductionTestLimits MS_KEY_TOTAL_CX_MAP_MAX failed... ERROR %08X\n", + ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + ret = checkLimitsMapTotal(totCompData.node_data, + totCompData.header.force_node, + totCompData.header.sense_node, + thresholds_min, thresholds_max); + /* check the limits */ + if (ret != OK) { + pr_err("production_test_data: checkLimitsMap MS TOTAL KEY CX TEST failed... ERROR COUNT = %d\n", + ret); + pr_err("MS KEY TOTAL CX TEST:.................FAIL\n\n"); + count_fail += 1; + if (stop_on_fail) + goto ERROR; + } else + pr_info("MS KEY TOTAL CX TEST:.................OK\n\n"); + + kfree(thresholds_min); + thresholds_min = NULL; + kfree(thresholds_max); + thresholds_max = NULL; + + kfree(totCompData.node_data); + totCompData.node_data = NULL; + } else + pr_info("MS KEY TOTAL CX TEST:.................SKIPPED\n"); + + +ERROR: + if (count_fail == 0) { + pr_info("MS KEY CX testes finished!.................OK\n"); + kfree(msCompData.node_data); + msCompData.node_data = NULL; + return OK; + } else { + print_frame_i8("MS Key Init Data (Cx2) =", array1dTo2d_i8( + msCompData.node_data, + msCompData.node_data_size, + msCompData.header.sense_node), + msCompData.header.force_node, + msCompData.header.sense_node); + pr_err("MS Key CX testes finished!.................FAILED fails_count = %d\n\n", + count_fail); + if (thresholds != NULL) + kfree(thresholds); + if (thresholds_min != NULL) + kfree(thresholds_min); + if (thresholds_max != NULL) + kfree(thresholds_max); + if (msCompData.node_data != NULL) + kfree(msCompData.node_data); + if (totCompData.node_data != NULL) + kfree(totCompData.node_data); + return ERROR_TEST_CHECK_FAIL | ERROR_PROD_TEST_DATA; + } + +ERROR_LIMITS: + if (thresholds != NULL) + kfree(thresholds); + if (thresholds_min != NULL) + kfree(thresholds_min); + if (thresholds_max != NULL) + kfree(thresholds_max); + if (msCompData.node_data != NULL) + kfree(msCompData.node_data); + if (totCompData.node_data != NULL) + kfree(totCompData.node_data); + return ret; +} + +/** + * 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 stop_on_fail if 1, the test flow stops at the first data check + * failure + * otherwise it keeps going performing all the selected test + * @param todo pointer to a TestToDo variable which select the test to do + * @return OK if success or an error code which specify the type of error + */ +int production_test_ss_raw(char *path_limits, int stop_on_fail, TestToDo *todo) +{ + int ret; + int count_fail = 0; + int rows, columns; + + SelfSenseFrame ssRawFrame; + + int *thresholds = NULL; + int trows, tcolumns; + + /* SS TEST */ + pr_info("SS RAW Testes are starting...\n"); + + /************** Self Sense Test **************/ + + pr_info("Getting SS Frame...\n"); + ret = setScanMode(SCAN_MODE_LOCKED, LOCKED_ACTIVE); + mdelay(WAIT_FOR_FRESH_FRAMES); + ret |= setScanMode(SCAN_MODE_ACTIVE, 0x00); + mdelay(WAIT_AFTER_SENSEOFF); + ret |= getSSFrame3(SS_RAW, &ssRawFrame); + if (ret < 0) { + pr_err("production_test_data: getSSFrame failed... ERROR %08X\n", + ERROR_PROD_TEST_DATA); + return ret | ERROR_PROD_TEST_DATA; + } + + print_frame_short("SS Raw force frame =", + array1dTo2d_short( + ssRawFrame.force_data, + ssRawFrame.header.force_node, + 1), + ssRawFrame.header.force_node, 1); + print_frame_short("SS Raw sense frame =", + array1dTo2d_short( + ssRawFrame.sense_data, + ssRawFrame.header.sense_node, + ssRawFrame.header.sense_node), + 1, ssRawFrame.header.sense_node); + + /* SS RAW (PROXIMITY) FORCE TEST */ + pr_info("SS RAW FORCE TEST:\n"); + + + + if (todo->SelfForceRaw == 1 || todo->SelfForceRawGap == 1) { + columns = 1; /* there are no data for the sense channels + * because is a force frame */ + rows = ssRawFrame.header.force_node; + + pr_info("SS RAW FORCE MIN MAX TEST:\n"); + if (todo->SelfForceRaw == 1) { + ret = parseProductionTestLimits(path_limits, + &limit_file, + SS_RAW_FORCE_MIN_MAX, + &thresholds, &trows, + &tcolumns); + if (ret < 0 || (trows != 1 || tcolumns != 2)) { + pr_err("production_test_data: parseProductionTestLimits SS_RAW_FORCE_MIN_MAX failed... ERROR %08X\n", + ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + ret = checkLimitsMinMax(ssRawFrame.force_data, rows, + columns, thresholds[0], + thresholds[1]); + if (ret != OK) { + pr_err("production_test_data: checkLimitsMinMax SS RAW FORCE failed... ERROR COUNT = %d\n", + ret); + pr_err("SS RAW (PROXIMITY) FORCE MIN MAX TEST:.................FAIL\n\n"); + count_fail += 1; + if (stop_on_fail) { + ret = ERROR_PROD_TEST_DATA | + ERROR_TEST_CHECK_FAIL; + goto ERROR_LIMITS; + } + } else + pr_info("SS RAW FORCE MIN MAX TEST:.................OK\n\n"); + + kfree(thresholds); + thresholds = NULL; + } else + pr_info("SS RAW FORCE MIN MAX TEST:.................SKIPPED\n\n"); + + pr_info("SS RAW FORCE GAP TEST:\n"); + if (todo->SelfForceRawGap == 1) { + ret = parseProductionTestLimits(path_limits, + &limit_file, + SS_RAW_FORCE_GAP, + &thresholds, &trows, + &tcolumns); + if (ret < 0 || (trows != 1 || tcolumns != 1)) { + pr_err("production_test_data: parseProductionTestLimits SS_RAW_FORCE_GAP failed... ERROR %08X\n", + ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + ret = checkLimitsGap(ssRawFrame.force_data, rows, + columns, thresholds[0]); + if (ret != OK) { + pr_err("production_test_data: checkLimitsGap SS RAW FORCE GAP failed... ERROR = %08X\n", + ret); + pr_err("SS RAW FORCE GAP TEST:.................FAIL\n\n"); + count_fail += 1; + if (stop_on_fail) { + ret = ERROR_PROD_TEST_DATA | + ERROR_TEST_CHECK_FAIL; + goto ERROR_LIMITS; + } + } else + pr_info("SS RAW FORCE GAP TEST:.................OK\n\n"); + + kfree(thresholds); + thresholds = NULL; + } else + pr_info("SS RAW FORCE GAP TEST:.................SKIPPED\n\n"); + + kfree(ssRawFrame.force_data); + ssRawFrame.force_data = NULL; + } else + pr_info("SS RAW FORCE TEST:.................SKIPPED\n\n"); + + /* SS RAW (PROXIMITY) SENSE TEST */ + pr_info("SS RAW SENSE TEST:\n"); + + if (todo->SelfSenseRaw == 1 || todo->SelfSenseRawGap == 1) { + columns = ssRawFrame.header.sense_node; + rows = 1;/* there are no data for the force channels + * because is a sense frame */ + + pr_info("SS RAW SENSE MIN MAX TEST:\n"); + if (todo->SelfSenseRaw == 1) { + ret = parseProductionTestLimits(path_limits, + &limit_file, + SS_RAW_SENSE_MIN_MAX, + &thresholds, &trows, + &tcolumns); + if (ret < 0 || (trows != 1 || tcolumns != 2)) { + pr_err("production_test_data: parseProductionTestLimits SS_RAW_SENSE_MIN_MAX failed... ERROR %08X\n", + ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + ret = checkLimitsMinMax(ssRawFrame.sense_data, rows, + columns, thresholds[0], + thresholds[1]); + if (ret != OK) { + pr_err("production_test_data: checkLimitsMinMax SS RAW SENSE failed... ERROR COUNT = %d\n", + ret); + pr_err("SS RAW SENSE MIN MAX TEST:.................FAIL\n"); + count_fail += 1; + if (stop_on_fail) { + ret = ERROR_PROD_TEST_DATA | + ERROR_TEST_CHECK_FAIL; + goto ERROR_LIMITS; + } + } else + pr_info("SS RAW SENSE MIN MAX TEST:.................OK\n"); + + kfree(thresholds); + thresholds = NULL; + } else + pr_info("SS RAW SENSE MIN MAX TEST:.................SKIPPED\n"); + + pr_info("SS RAW SENSE GAP TEST:\n"); + if (todo->SelfSenseRawGap == 1) { + ret = parseProductionTestLimits(path_limits, + &limit_file, + SS_RAW_SENSE_GAP, + &thresholds, &trows, + &tcolumns); + if (ret < 0 || (trows != 1 || tcolumns != 1)) { + pr_err("production_test_data: parseProductionTestLimits SS_RAW_SENSE_GAP failed... ERROR %08X\n", + ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + ret = checkLimitsGap(ssRawFrame.sense_data, rows, + columns, thresholds[0]); + if (ret != OK) { + pr_err("production_test_data: checkLimitsGap SS RAW SENSE GAP failed... ERROR = %08X\n", + ret); + pr_err("SS RAW SENSE GAP TEST:.................FAIL\n"); + count_fail += 1; + if (stop_on_fail) { + ret = ERROR_PROD_TEST_DATA | + ERROR_TEST_CHECK_FAIL; + goto ERROR_LIMITS; + } + } else + pr_info("SS RAW SENSE GAP TEST:.................OK\n"); + + kfree(thresholds); + thresholds = NULL; + } else + pr_info("SS RAW SENSE GAP TEST:.................SKIPPED\n"); + + kfree(ssRawFrame.sense_data); + ssRawFrame.sense_data = NULL; + } + + ret = production_test_ss_raw_lp(path_limits, stop_on_fail, todo); + if (ret < OK) { + pr_err("production_test_data: production_test_ss_raw_lp failed... ERROR = %08X\n", + ret); + count_fail += 1; + } + + if (count_fail == 0) { + pr_info("SS RAW testes finished!.................OK\n\n"); + return OK; + } else { + pr_err("SS RAW testes finished!.................FAILED fails_count = %d\n\n", + count_fail); + return ERROR_TEST_CHECK_FAIL | ERROR_PROD_TEST_DATA; + } + +ERROR_LIMITS: + if (ssRawFrame.force_data != NULL) + kfree(ssRawFrame.force_data); + if (ssRawFrame.sense_data != NULL) + kfree(ssRawFrame.sense_data); + if (thresholds != NULL) + kfree(thresholds); + return ret; +} + + +/** + * 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 stop_on_fail if 1, the test flow stops at the first data check + * failure + * otherwise it keeps going performing all the selected test + * @param todo pointer to a TestToDo variable which select the test to do + * @return OK if success or an error code which specify the type of error + */ +int production_test_ss_raw_lp(char *path_limits, int stop_on_fail, + TestToDo *todo) +{ + int ret; + int count_fail = 0; + int rows, columns; + + SelfSenseFrame ssRawFrame; + + int *thresholds = NULL; + int trows, tcolumns; + + /* SS TEST */ + pr_info("SS RAW LP Testes are starting...\n"); + + /************** Self Sense Test **************/ + + pr_info("Getting SS LP Frame...\n"); + ret = setScanMode(SCAN_MODE_LOCKED, LOCKED_LP_DETECT); + mdelay(WAIT_FOR_FRESH_FRAMES); + ret |= setScanMode(SCAN_MODE_ACTIVE, 0x00); + mdelay(WAIT_AFTER_SENSEOFF); + ret |= getSSFrame3(SS_RAW, &ssRawFrame); + if (ret < 0) { + pr_err("production_test_data: getSSFrame failed... ERROR %08X\n", + ERROR_PROD_TEST_DATA); + return ret | ERROR_PROD_TEST_DATA; + } + + print_frame_short("SS Raw LP force frame =", + array1dTo2d_short( + ssRawFrame.force_data, + ssRawFrame.header.force_node, 1), + ssRawFrame.header.force_node, 1); + print_frame_short("SS Raw LP sense frame =", + array1dTo2d_short( + ssRawFrame.sense_data, + ssRawFrame.header.sense_node, + ssRawFrame.header.sense_node), + 1, ssRawFrame.header.sense_node); + + /* SS RAW (PROXIMITY) FORCE TEST */ + pr_info("SS RAW LP FORCE TEST:\n"); + + if (todo->SelfForceRawLP == 1 || todo->SelfForceRawGapLP == 1) { + columns = 1; /* there are no data for the sense channels + * because is a force frame */ + rows = ssRawFrame.header.force_node; + + pr_info("SS RAW LP FORCE MIN MAX TEST:\n"); + if (todo->SelfForceRawLP == 1) { + ret = parseProductionTestLimits(path_limits, + &limit_file, + SS_RAW_LP_FORCE_MIN_MAX, + &thresholds, + &trows, &tcolumns); + if (ret < 0 || (trows != 1 || tcolumns != 2)) { + pr_err("production_test_data: parseProductionTestLimits SS_RAW_FORCE_MIN_MAX failed... ERROR %08X\n", + ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + ret = checkLimitsMinMax(ssRawFrame.force_data, rows, + columns, thresholds[0], + thresholds[1]); + if (ret != OK) { + pr_err("production_test_data: checkLimitsMinMax SS RAW FORCE failed... ERROR COUNT = %d\n", + ret); + pr_err("SS RAW LP FORCE MIN MAX TEST:.................FAIL\n\n"); + count_fail += 1; + if (stop_on_fail) { + ret = ERROR_PROD_TEST_DATA | + ERROR_TEST_CHECK_FAIL; + goto ERROR_LIMITS; + } + } else + pr_info("SS RAW LP FORCE MIN MAX TEST:.................OK\n\n"); + + kfree(thresholds); + thresholds = NULL; + } else + pr_info("SS RAW LP FORCE MIN MAX TEST:.................SKIPPED\n\n"); + + pr_info("SS RAW LP FORCE GAP TEST:\n"); + if (todo->SelfForceRawGapLP == 1) { + ret = parseProductionTestLimits(path_limits, + &limit_file, + SS_RAW_LP_FORCE_GAP, + &thresholds, &trows, + &tcolumns); + if (ret < OK || (trows != 1 || tcolumns != 1)) { + pr_err("production_test_data: parseProductionTestLimits SS_RAW_FORCE_GAP failed... ERROR %08X\n", + ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + ret = checkLimitsGap(ssRawFrame.force_data, rows, + columns, thresholds[0]); + if (ret != OK) { + pr_err("production_test_data: checkLimitsGap SS RAW FORCE GAP failed... ERROR = %08X\n", + ret); + pr_err("SS RAW LP FORCE GAP TEST:.................FAIL\n\n"); + count_fail += 1; + if (stop_on_fail) { + ret = ERROR_PROD_TEST_DATA | + ERROR_TEST_CHECK_FAIL; + goto ERROR_LIMITS; + } + } else + pr_info("SS RAW LP FORCE GAP TEST:.................OK\n\n"); + + kfree(thresholds); + thresholds = NULL; + } else + pr_info("SS RAW LP FORCE GAP TEST:.................SKIPPED\n\n"); + + kfree(ssRawFrame.force_data); + ssRawFrame.force_data = NULL; + } else + pr_info("SS RAW LP FORCE TEST:.................SKIPPED\n\n"); + + /* SS RAW (PROXIMITY) SENSE TEST */ + pr_info("SS RAW LP SENSE TEST:\n"); + + if (todo->SelfSenseRawLP == 1 || todo->SelfSenseRawGapLP == 1) { + columns = ssRawFrame.header.sense_node; + rows = 1;/* there are no data for the force channels + * because is a sense frame */ + + pr_info("SS RAW LP SENSE MIN MAX TEST:\n"); + if (todo->SelfSenseRawLP == 1) { + ret = parseProductionTestLimits(path_limits, + &limit_file, + SS_RAW_LP_SENSE_MIN_MAX, + &thresholds, + &trows, &tcolumns); + if (ret < OK || (trows != 1 || tcolumns != 2)) { + pr_err("production_test_data: parseProductionTestLimits SS_RAW_SENSE_MIN_MAX failed... ERROR %08X\n", + ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + ret = checkLimitsMinMax(ssRawFrame.sense_data, rows, + columns, thresholds[0], + thresholds[1]); + if (ret != OK) { + pr_err("production_test_data: checkLimitsMinMax SS RAW SENSE failed... ERROR COUNT = %d\n", + ret); + pr_err("SS RAW LP SENSE MIN MAX TEST:.................FAIL\n"); + count_fail += 1; + if (stop_on_fail) { + ret = ERROR_PROD_TEST_DATA | + ERROR_TEST_CHECK_FAIL; + goto ERROR_LIMITS; + } + } else + pr_info("SS RAW SENSE MIN MAX TEST:.................OK\n"); + + kfree(thresholds); + thresholds = NULL; + } else + pr_info("SS RAW LP SENSE MIN MAX TEST:.................SKIPPED\n"); + + pr_info("SS RAW LP SENSE GAP TEST:\n"); + if (todo->SelfSenseRawGapLP == 1) { + ret = parseProductionTestLimits(path_limits, + &limit_file, + SS_RAW_LP_SENSE_GAP, + &thresholds, &trows, + &tcolumns); + if (ret < OK || (trows != 1 || tcolumns != 1)) { + pr_err("production_test_data: parseProductionTestLimits SS_RAW_SENSE_GAP failed... ERROR %08X\n", + ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + ret = checkLimitsGap(ssRawFrame.sense_data, rows, + columns, thresholds[0]); + if (ret != OK) { + pr_err("production_test_data: checkLimitsGap SS RAW SENSE GAP failed... ERROR = %08X\n", + ret); + pr_err("SS RAW LP SENSE GAP TEST:.................FAIL\n"); + count_fail += 1; + if (stop_on_fail) { + ret = ERROR_PROD_TEST_DATA | + ERROR_TEST_CHECK_FAIL; + goto ERROR_LIMITS; + } + } else + pr_info("SS RAW LP SENSE GAP TEST:.................OK\n"); + + kfree(thresholds); + thresholds = NULL; + } else + pr_info("SS RAW LP SENSE GAP TEST:.................SKIPPED\n"); + + kfree(ssRawFrame.sense_data); + ssRawFrame.sense_data = NULL; + } + + if (count_fail == 0) { + pr_info("SS RAW LP testes finished!.................OK\n\n"); + return OK; + } else { + pr_err("SS RAW LP testes finished!.................FAILED fails_count = %d\n\n", + count_fail); + return ERROR_TEST_CHECK_FAIL | ERROR_PROD_TEST_DATA; + } + +ERROR_LIMITS: + if (ssRawFrame.force_data != NULL) + kfree(ssRawFrame.force_data); + if (ssRawFrame.sense_data != NULL) + kfree(ssRawFrame.sense_data); + if (thresholds != NULL) + kfree(thresholds); + return ret; +} + +/** + * 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 stop_on_fail if 1, the test flow stops at the first data check + * failure + * otherwise it keeps going performing all the selected test + * @param todo pointer to a TestToDo variable which select the test to do + * @return OK if success or an error code which specify the type of error + */ +int production_test_ss_ix_cx(char *path_limits, int stop_on_fail, + TestToDo *todo) +{ + int ret; + int count_fail = 0; + + int *thresholds = NULL; + int trows, tcolumns; + int *thresholds_min = NULL; + int *thresholds_max = NULL; + + SelfSenseData ssCompData; + TotSelfSenseData totCompData; + + u8 *adjhor = NULL; + u8 *adjvert = NULL; + + short container; + + u16 *total_adjhor = NULL; + u16 *total_adjvert = NULL; + + pr_info("SS IX CX testes are starting...\n"); + ret = readSelfSenseCompensationData(LOAD_CX_SS_TOUCH, &ssCompData); + /* read the SS compensation data */ + if (ret < 0) { + pr_err("production_test_data: readSelfSenseCompensationData failed... ERROR %08X\n", + ERROR_PROD_TEST_DATA); + return ret | ERROR_PROD_TEST_DATA; + } + + ret = readTotSelfSenseCompensationData(LOAD_PANEL_CX_TOT_SS_TOUCH, + &totCompData); + /* read the TOT SS compensation data */ + if (ret < 0) { + pr_err("production_test_data: readTotSelfSenseCompensationData failed... ERROR %08X\n", + ERROR_PROD_TEST_DATA); + kfree(ssCompData.ix2_fm); + kfree(ssCompData.ix2_sn); + kfree(ssCompData.cx2_fm); + kfree(ssCompData.cx2_sn); + return ret | ERROR_PROD_TEST_DATA; + } + + /************* SS FORCE IX **************/ + /* SS IX1 FORCE TEST */ + pr_info("SS IX1 FORCE TEST:\n"); + if (todo->SelfForceIx1 == 1) { + ret = parseProductionTestLimits(path_limits, &limit_file, + SS_IX1_FORCE_MIN_MAX, + &thresholds, &trows, &tcolumns); + if (ret < 0 || (trows != 1 || tcolumns != 2)) { + pr_err("production_test_data: parseProductionTestLimits SS_IX1_FORCE_MIN_MAX failed... ERROR %08X\n", + ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + container = (short)ssCompData.f_ix1; + ret = checkLimitsMinMax(&container, 1, 1, thresholds[0], + thresholds[1]); + /* check the limits */ + if (ret != OK) { + pr_err("production_test_data: checkLimitsMinMax SS IX1 FORCE TEST failed... ERROR COUNT = %d\n", + ret); + count_fail += 1; + if (stop_on_fail) + goto ERROR; + } else + pr_info("SS IX1 FORCE TEST:.................OK\n\n"); + } else + pr_info("SS IX1 FORCE TEST:.................SKIPPED\n\n"); + + kfree(thresholds); + thresholds = NULL; + /* SS IX2 FORCE TEST */ + pr_info("SS IX2 FORCE MIN MAX TEST:\n"); + if (todo->SelfForceIx2 == 1) { + ret = parseProductionTestLimits(path_limits, &limit_file, + SS_IX2_FORCE_MAP_MIN, + &thresholds_min, &trows, + &tcolumns); + /* load the min thresholds */ + if (ret < 0 || (trows != ssCompData.header.force_node || + tcolumns != 1)) { + pr_err("production_test_data: parseProductionTestLimits SS_IX2_FORCE_MAP_MIN failed... ERROR %08X\n", + ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + ret = parseProductionTestLimits(path_limits, &limit_file, + SS_IX2_FORCE_MAP_MAX, + &thresholds_max, &trows, + &tcolumns); + /* load the max thresholds */ + if (ret < 0 || (trows != ssCompData.header.force_node || + tcolumns != 1)) { + pr_err("production_test_data: parseProductionTestLimits SS_IX2_FORCE_MAP_MAX failed... ERROR %08X\n", + ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + ret = checkLimitsMapFromU(ssCompData.ix2_fm, + ssCompData.header.force_node, 1, + thresholds_min, + thresholds_max); /* check the + * values with + * thresholds */ + if (ret != OK) { + pr_err("production_test_data: checkLimitsMap SS IX2 FORCE failed... ERROR COUNT = %d\n", + ret); + pr_err("SS IX2 FORCE MIN MAX TEST:.................FAIL\n\n"); + count_fail += 1; + if (stop_on_fail) + goto ERROR; + } else + pr_info("SS IX2 FORCE MIN MAX TEST:.................OK\n\n"); + + kfree(thresholds_min); + thresholds_min = NULL; + kfree(thresholds_max); + thresholds_max = NULL; + } else + pr_info("SS IX2 FORCE MIN MAX TEST:.................SKIPPED\n\n"); + + pr_info("SS IX2 FORCE ADJ TEST:\n"); + if (todo->SelfForceIx2Adj == 1) { + /* SS IX2 FORCE ADJV TEST */ + pr_info("SS IX2 FORCE ADJVERT TEST:\n"); + ret = computeAdjVertFromU(ssCompData.ix2_fm, + ssCompData.header.force_node, 1, + &adjvert); + if (ret < 0) { + pr_err("production_test_data: computeAdjVert SS IX2 FORCE ADJV failed... ERROR %08X\n", + ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + pr_info("SS IX2 FORCE ADJV computed!\n"); + + ret = parseProductionTestLimits(path_limits, &limit_file, + SS_IX2_FORCE_ADJV_MAP_MAX, + &thresholds_max, &trows, + &tcolumns); /* load the max + * thresholds */ + if (ret < 0 || (trows != ssCompData.header.force_node - 1 || + tcolumns != 1)) { + pr_err("production_test_data: parseProductionTestLimits SS_IX2_FORCE_ADJV_MAP_MAX failed... ERROR %08X\n", + ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + ret = checkLimitsMapAdj(adjvert, ssCompData.header.force_node - + 1, 1, thresholds_max); /* check the + * values with + * thresholds */ + if (ret != OK) { + pr_err("production_test_data: checkLimitsMap SS IX2 FORCE failed... ERROR COUNT = %d\n", + ret); + pr_err("SS IX2 FORCE ADJV TEST:.................FAIL\n\n"); + count_fail += 1; + if (stop_on_fail) + goto ERROR; + } else + pr_info("SS IX2 FORCE ADJV TEST:.................OK\n\n"); + + kfree(thresholds_max); + thresholds_max = NULL; + kfree(adjvert); + adjvert = NULL; + } else + pr_info("SS IX2 FORCE ADJ TEST:.................SKIPPED\n\n"); + + /* SS TOTAL FORCE IX */ + pr_info("SS TOTAL IX FORCE TEST:\n"); + if (todo->SelfForceIxTotal == 1 || todo->SelfForceIxTotalAdj == 1) { + pr_info("SS TOTAL IX FORCE MIN MAX TEST:\n"); + if (todo->SelfForceIxTotal == 1) { + ret = parseProductionTestLimits(path_limits, + &limit_file, + SS_TOTAL_IX_FORCE_MAP_MIN, + &thresholds_min, + &trows, &tcolumns); + /* load the min thresholds */ + if (ret < 0 || (trows != + totCompData.header.force_node || + tcolumns != 1)) { + pr_err("production_test_data: parseProductionTestLimits SS_TOTAL_IX_FORCE_MAP_MIN failed... ERROR %08X\n", + ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + ret = parseProductionTestLimits(path_limits, + &limit_file, + SS_TOTAL_IX_FORCE_MAP_MAX, + &thresholds_max, + &trows, &tcolumns); + /* load the max thresholds */ + if (ret < 0 || (trows != + totCompData.header.force_node || + tcolumns != 1)) { + pr_err("production_test_data: parseProductionTestLimits SS_TOTAL_IX_FORCE_MAP_MAX failed... ERROR %08X\n", + ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + ret = checkLimitsMapTotalFromU(totCompData.ix_fm, + totCompData.header. + force_node, 1, + thresholds_min, + thresholds_max); + /* check the values with thresholds */ + if (ret != OK) { + pr_err("production_test_data: checkLimitsMap SS TOTAL IX FORCE failed... ERROR COUNT = %d\n", + ret); + pr_err("SS TOTAL IX FORCE MIN MAX TEST:.................FAIL\n\n"); + count_fail += 1; + if (stop_on_fail) + goto ERROR; + } else + pr_info("SS TOTAL IX FORCE MIN MAX TEST:.................OK\n\n"); + + kfree(thresholds_min); + thresholds_min = NULL; + kfree(thresholds_max); + thresholds_max = NULL; + } else + pr_info("SS TOTAL IX FORCE MIN MAX TEST:.................SKIPPED\n"); + + pr_info("SS TOTAL IX FORCE ADJ TEST:\n"); + if (todo->SelfForceIxTotalAdj == 1) { + /* SS TOTAL IX FORCE ADJV TEST */ + pr_info("SS TOTAL IX FORCE ADJVERT TEST:\n"); + ret = computeAdjVertTotalFromU(totCompData.ix_fm, + totCompData.header. + force_node, 1, + &total_adjvert); + if (ret < 0) { + pr_err("production_test_data: computeAdjVert SS TOTAL IX FORCE ADJV failed... ERROR %08X\n", + ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + pr_info("SS TOTAL IX FORCE ADJV computed!\n"); + + ret = parseProductionTestLimits(path_limits, + &limit_file, + SS_TOTAL_IX_FORCE_ADJV_MAP_MAX, + &thresholds_max, &trows, + &tcolumns); + /* load the max thresholds */ + if (ret < 0 || (trows != totCompData.header.force_node - + 1 || tcolumns != 1)) { + pr_err("production_test_data: parseProductionTestLimits SS_TOTAL_IX_FORCE_ADJV_MAP_MAX... ERROR %08X\n", + ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + ret = checkLimitsMapAdjTotal(total_adjvert, + totCompData.header. + force_node - 1, 1, + thresholds_max); + /* check the values with thresholds */ + if (ret != OK) { + pr_err("production_test_data: checkLimitsMap SS TOTAL IX FORCE failed... ERROR COUNT = %d\n", + ret); + pr_err("SS TOTAL IX FORCE ADJV TEST:.................FAIL\n\n"); + count_fail += 1; + if (stop_on_fail) + goto ERROR; + } else + pr_info("SS TOTAL IX FORCE ADJV TEST:.................OK\n\n"); + + kfree(thresholds_max); + thresholds_max = NULL; + kfree(total_adjvert); + total_adjvert = NULL; + } else + pr_info("SS TOTAL IX FORCE ADJ TEST:.................SKIPPED\n"); + } else + pr_info("SS TOTAL IX FORCE TEST:.................SKIPPED\n\n"); + + + /************** SS SENSE IX **************/ + /* SS IX1 SENSE TEST */ + pr_info("SS IX1 SENSE TEST:\n"); + if (todo->SelfSenseIx1 == 1) { + ret = parseProductionTestLimits(path_limits, &limit_file, + SS_IX1_SENSE_MIN_MAX, + &thresholds, &trows, &tcolumns); + if (ret < 0 || (trows != 1 || tcolumns != 2)) { + pr_err("production_test_data: parseProductionTestLimits SS_IX1_SENSE_MIN_MAX failed... ERROR %08X\n", + ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + container = (short)ssCompData.s_ix1; + ret = checkLimitsMinMax(&container, 1, 1, thresholds[0], + thresholds[1]); + /* check the limits */ + if (ret != OK) { + pr_err("production_test_data: checkLimitsMinMax SS IX1 SENSE TEST failed... ERROR COUNT = %d\n", + ret); + count_fail += 1; + if (stop_on_fail) + goto ERROR; + } else + pr_info("SS IX1 SENSE TEST:.................OK\n\n"); + } else + pr_info("SS IX1 SENSE TEST:.................SKIPPED\n\n"); + + kfree(thresholds); + thresholds = NULL; + /* SS IX2 SENSE TEST */ + pr_info("SS IX2 SENSE MIN MAX TEST:\n"); + if (todo->SelfSenseIx2 == 1) { + ret = parseProductionTestLimits(path_limits, &limit_file, + SS_IX2_SENSE_MAP_MIN, + &thresholds_min, &trows, + &tcolumns); + /* load the min thresholds */ + if (ret < 0 || (trows != 1 || tcolumns != + ssCompData.header.sense_node)) { + pr_err("production_test_data: parseProductionTestLimits SS_IX2_SENSE_MAP_MIN failed... ERROR %08X\n", + ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + ret = parseProductionTestLimits(path_limits, &limit_file, + SS_IX2_SENSE_MAP_MAX, + &thresholds_max, &trows, + &tcolumns); + /* load the max thresholds */ + if (ret < 0 || (trows != 1 || tcolumns != + ssCompData.header.sense_node)) { + pr_err("production_test_data: parseProductionTestLimits SS_IX2_SENSE_MAP_MAX failed... ERROR %08X\n", + ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + ret = checkLimitsMapFromU(ssCompData.ix2_sn, 1, + ssCompData.header.sense_node, + thresholds_min, thresholds_max); + /* check the values with thresholds */ + if (ret != OK) { + pr_err("production_test_data: checkLimitsMap SS IX2 SENSE failed... ERROR COUNT = %d\n", + ret); + pr_err("SS IX2 SENSE MIN MAX TEST:.................FAIL\n\n"); + count_fail += 1; + if (stop_on_fail) + goto ERROR; + } else + pr_info("SS IX2 SENSE MIN MAX TEST:.................OK\n\n"); + + kfree(thresholds_min); + thresholds_min = NULL; + kfree(thresholds_max); + thresholds_max = NULL; + } else + pr_info("SS IX2 SENSE MIN MAX TEST:.................SKIPPED\n\n"); + + pr_info("SS IX2 SENSE ADJ TEST:\n"); + if (todo->SelfSenseIx2Adj == 1) { + /* SS IX2 SENSE ADJH TEST */ + pr_info("SS IX2 SENSE ADJHORIZ TEST:\n"); + ret = computeAdjHorizFromU(ssCompData.ix2_sn, 1, + ssCompData.header.sense_node, + &adjhor); + if (ret < 0) { + pr_err("production_test_data: computeAdjHoriz SS IX2 SENSE ADJH failed... ERROR %08X\n", + ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + pr_info("SS IX2 SENSE ADJ HORIZ computed!\n"); + + + ret = parseProductionTestLimits(path_limits, &limit_file, + SS_IX2_SENSE_ADJH_MAP_MAX, + &thresholds_max, &trows, + &tcolumns); + /* load the max thresholds */ + if (ret < 0 || (trows != 1 || tcolumns != + ssCompData.header.sense_node - 1)) { + pr_err("production_test_data: parseProductionTestLimits SS_IX2_SENSE_ADJH_MAP_MAX failed... ERROR %08X\n", + ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + ret = checkLimitsMapAdj(adjhor, 1, + ssCompData.header.sense_node - 1, + thresholds_max); + /* check the values with thresholds */ + if (ret != OK) { + pr_err("production_test_data: checkLimitsMapAdj SS IX2 SENSE ADJH failed... ERROR COUNT = %d\n", + ret); + pr_err("SS IX2 SENSE ADJH TEST:.................FAIL\n\n"); + count_fail += 1; + if (stop_on_fail) + goto ERROR; + } else + pr_info("SS IX2 SENSE ADJH TEST:.................OK\n\n"); + + kfree(thresholds_max); + thresholds_max = NULL; + kfree(adjhor); + adjhor = NULL; + } else + pr_info("SS IX2 SENSE ADJ TEST:.................SKIPPED\n"); + + /* SS TOTAL IX SENSE */ + pr_info("SS TOTAL IX SENSE TEST:\n"); + if (todo->SelfSenseIxTotal == 1 || todo->SelfSenseIxTotalAdj == 1) { + pr_info("SS TOTAL IX SENSE MIN MAX TEST:\n"); + if (todo->SelfSenseIxTotal == 1) { + ret = parseProductionTestLimits(path_limits, + &limit_file, + SS_TOTAL_IX_SENSE_MAP_MIN, + &thresholds_min, + &trows, &tcolumns); + /* load the min thresholds */ + if (ret < 0 || (trows != 1 || tcolumns != + totCompData.header.sense_node)) { + pr_err("production_test_data: parseProductionTestLimits SS_TOTAL_IX_SENSE_MAP_MIN failed... ERROR %08X\n", + ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + ret = parseProductionTestLimits(path_limits, + &limit_file, + SS_TOTAL_IX_SENSE_MAP_MAX, + &thresholds_max, + &trows, &tcolumns); + /* load the max thresholds */ + if (ret < 0 || (trows != 1 || tcolumns != + totCompData.header.sense_node)) { + pr_err("production_test_data: parseProductionTestLimits SS_TOTAL_IX_SENSE_MAP_MAX failed... ERROR %08X\n", + ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + ret = checkLimitsMapTotalFromU(totCompData.ix_sn, 1, + totCompData.header. + sense_node, + thresholds_min, + thresholds_max); + /* check the values with thresholds */ + if (ret != OK) { + pr_err("production_test_data: checkLimitsMap SS TOTAL IX SENSE failed... ERROR COUNT = %d\n", + ret); + pr_err("SS TOTAL IX SENSE MIN MAX TEST:.................FAIL\n\n"); + count_fail += 1; + if (stop_on_fail) + goto ERROR; + } else + pr_info("SS TOTAL IX SENSE MIN MAX TEST:.................OK\n\n"); + + kfree(thresholds_min); + thresholds_min = NULL; + kfree(thresholds_max); + thresholds_max = NULL; + } else + pr_info("SS TOTAL IX SENSE MIN MAX TEST:.................SKIPPED\n"); + + + pr_info("SS TOTAL IX SENSE ADJ TEST:\n"); + if (todo->SelfSenseIxTotalAdj == 1) { + /* SS TOTAL IX SENSE ADJH TEST */ + pr_info("SS TOTAL IX SENSE ADJHORIZ TEST:\n"); + ret = computeAdjHorizTotalFromU(totCompData.ix_sn, 1, + totCompData.header. + sense_node, + &total_adjhor); + if (ret < 0) { + pr_err("production_test_data: computeAdjHoriz SS TOTAL IX SENSE ADJH failed... ERROR %08X\n", + ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + pr_info("SS TOTAL IX SENSE ADJ HORIZ computed!\n"); + + ret = parseProductionTestLimits(path_limits, + &limit_file, + SS_TOTAL_IX_SENSE_ADJH_MAP_MAX, + &thresholds_max, &trows, + &tcolumns); + /* load the max thresholds */ + if (ret < 0 || (trows != 1 || tcolumns != + totCompData.header.sense_node - 1)) { + pr_err("production_test_data: parseProductionTestLimits SS_TOTAL_IX_SENSE_ADJH_MAP_MAX failed... ERROR %08X\n", + ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + ret = checkLimitsMapAdjTotal(total_adjhor, 1, + totCompData.header. + sense_node - 1, + thresholds_max); + /* check the values with thresholds */ + if (ret != OK) { + pr_err("production_test_data: checkLimitsMapAdj SS TOTAL IX SENSE ADJH failed... ERROR COUNT = %d\n", + ret); + pr_err("SS TOTAL IX SENSE ADJH TEST:.................FAIL\n\n"); + count_fail += 1; + if (stop_on_fail) + goto ERROR; + } else + pr_info("SS TOTAL IX SENSE ADJH TEST:.................OK\n\n"); + + kfree(thresholds_max); + thresholds_max = NULL; + kfree(total_adjhor); + total_adjhor = NULL; + } else + pr_info("SS TOTAL IX SENSE ADJ TEST:.................SKIPPED\n"); + } else + pr_info("SS TOTAL IX SENSE TEST:.................SKIPPED\n"); + + /************* SS SENSE CX **************/ + /* SS CX1 FORCE TEST */ + pr_info("SS CX1 FORCE TEST:\n"); + if (todo->SelfForceCx1 == 1) { + ret = parseProductionTestLimits(path_limits, &limit_file, + SS_CX1_FORCE_MIN_MAX, + &thresholds, &trows, &tcolumns); + if (ret < 0 || (trows != 1 || tcolumns != 2)) { + pr_err("production_test_data: parseProductionTestLimits SS_CX1_FORCE_MIN_MAX failed... ERROR %08X\n", + ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + container = (short)ssCompData.f_cx1; + ret = checkLimitsMinMax(&container, 1, 1, thresholds[0], + thresholds[1]); + /* check the limits */ + if (ret != OK) { + pr_err("production_test_data: checkLimitsMinMax SS CX1 FORCE TEST failed... ERROR COUNT = %d\n", + ret); + count_fail += 1; + if (stop_on_fail) + goto ERROR; + } else + pr_info("SS CX1 FORCE TEST:.................OK\n\n"); + kfree(thresholds); + thresholds = NULL; + } else + pr_info("SS CX1 FORCE TEST:.................SKIPPED\n\n"); + + /* SS CX2 FORCE TEST */ + pr_info("SS CX2 FORCE MIN MAX TEST:\n"); + if (todo->SelfForceCx2 == 1) { + ret = parseProductionTestLimits(path_limits, &limit_file, + SS_CX2_FORCE_MAP_MIN, + &thresholds_min, &trows, + &tcolumns); + /* load the min thresholds */ + if (ret < 0 || (trows != ssCompData.header.force_node || + tcolumns != 1)) { + pr_err("production_test_data: parseProductionTestLimits SS_CX2_FORCE_MAP_MIN failed... ERROR %08X\n", + ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + ret = parseProductionTestLimits(path_limits, &limit_file, + SS_CX2_FORCE_MAP_MAX, + &thresholds_max, &trows, + &tcolumns); + /* load the max thresholds */ + if (ret < 0 || (trows != ssCompData.header.force_node || + tcolumns != 1)) { + pr_err("production_test_data: parseProductionTestLimits SS_CX2_FORCE_MAP_MAX failed... ERROR %08X\n", + ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + ret = checkLimitsMap(ssCompData.cx2_fm, + ssCompData.header.force_node, 1, + thresholds_min, + thresholds_max); + /* check the values with thresholds */ + if (ret != OK) { + pr_err("production_test_data: checkLimitsMap SS CX2 FORCE failed... ERROR COUNT = %d\n", + ret); + pr_err("SS CX2 FORCE MIN MAX TEST:.................FAIL\n\n"); + count_fail += 1; + if (stop_on_fail) + goto ERROR; + } else + pr_info("SS CX2 FORCE MIN MAX TEST:.................OK\n\n"); + + kfree(thresholds_min); + thresholds_min = NULL; + kfree(thresholds_max); + thresholds_max = NULL; + } else + pr_info("SS CX2 FORCE MIN MAX TEST:.................SKIPPED\n"); + + pr_info("SS CX2 FORCE ADJ TEST:\n"); + if (todo->SelfForceCx2Adj == 1) { + /* SS CX2 FORCE ADJV TEST */ + pr_info("SS CX2 FORCE ADJVERT TEST:\n"); + ret = computeAdjVert(ssCompData.cx2_fm, + ssCompData.header.force_node, 1, &adjvert); + /* compute the ADJV for CX2 FORCE */ + if (ret < 0) { + pr_err("production_test_data: computeAdjVert SS CX2 FORCE ADJV failed... ERROR %08X\n", + ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + pr_info("SS CX2 FORCE ADJV computed!\n"); + + ret = parseProductionTestLimits(path_limits, &limit_file, + SS_CX2_FORCE_ADJV_MAP_MAX, + &thresholds_max, &trows, + &tcolumns); + /* load the max thresholds */ + if (ret < 0 || (trows != ssCompData.header.force_node - 1 || + tcolumns != 1)) { + pr_err("production_test_data: parseProductionTestLimits SS_CX2_FORCE_ADJV_MAP_MAX failed... ERROR %08X\n", + ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + ret = checkLimitsMapAdj(adjvert, ssCompData.header.force_node - + 1, 1, thresholds_max); + /* check the values with thresholds */ + if (ret != OK) { + pr_err("production_test_data: checkLimitsMap SS IX2 FORCE failed... ERROR COUNT = %d\n", + ret); + pr_err("SS CX2 FORCE ADJV TEST:.................FAIL\n\n"); + count_fail += 1; + if (stop_on_fail) + goto ERROR; + } else + pr_info("SS CX2 FORCE ADJV TEST:.................OK\n\n"); + + kfree(thresholds_max); + thresholds_max = NULL; + kfree(adjvert); + adjvert = NULL; + } else + pr_info("SS CX2 FORCE ADJ TEST:.................SKIPPED\n\n"); + + /* SS TOTAL CX FORCE */ + pr_info("SS TOTAL CX FORCE TEST:\n"); + if (todo->SelfForceCxTotal == 1 || todo->SelfForceCxTotalAdj == 1) { + pr_info("SS TOTAL CX FORCE MIN MAX TEST:\n"); + if (todo->SelfForceCxTotal == 1) { + ret = parseProductionTestLimits(path_limits, + &limit_file, + SS_TOTAL_CX_FORCE_MAP_MIN, + &thresholds_min, + &trows, &tcolumns); + /* load the min thresholds */ + if (ret < 0 || (trows != + totCompData.header.force_node || + tcolumns != 1)) { + pr_err("production_test_data: parseProductionTestLimits SS_TOTAL_CX_FORCE_MAP_MIN failed... ERROR %08X\n", + ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + ret = parseProductionTestLimits(path_limits, + &limit_file, + SS_TOTAL_CX_FORCE_MAP_MAX, + &thresholds_max, + &trows, &tcolumns); + /* load the max thresholds */ + if (ret < 0 || (trows != + totCompData.header.force_node || + tcolumns != 1)) { + pr_err("production_test_data: parseProductionTestLimits SS_TOTAL_CX_FORCE_MAP_MAX failed... ERROR %08X\n", + ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + ret = checkLimitsMapTotal(totCompData.cx_fm, + totCompData.header.force_node, + 1, thresholds_min, + thresholds_max); + /* check the values with thresholds */ + if (ret != OK) { + pr_err("production_test_data: checkLimitsMap SS TOTAL FORCE failed... ERROR COUNT = %d\n", + ret); + pr_err("SS TOTAL FORCE MIN MAX TEST:.................FAIL\n\n"); + count_fail += 1; + if (stop_on_fail) + goto ERROR; + } else + pr_info("SS TOTAL FORCE MIN MAX TEST:.................OK\n\n"); + + kfree(thresholds_min); + thresholds_min = NULL; + kfree(thresholds_max); + thresholds_max = NULL; + } else + pr_info("SS TOTAL CX FORCE MIN MAX TEST:.................SKIPPED\n"); + + /* SS TOTAL CX FORCE ADJV TEST */ + pr_info("SS TOTAL CX FORCE ADJ TEST:\n"); + if (todo->SelfForceCxTotalAdj == 1) { + pr_info("SS TOTAL CX FORCE ADJVERT TEST:\n"); + ret = computeAdjVertTotal(totCompData.cx_fm, + totCompData.header.force_node, + 1, &total_adjvert); + /* compute the ADJV for CX2 FORCE */ + if (ret < 0) { + pr_err("production_test_data: computeAdjVert SS TOTAL CX FORCE ADJV failed... ERROR %08X\n", + ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + pr_info("SS TOTAL CX FORCE ADJV computed!\n"); + + ret = parseProductionTestLimits(path_limits, + &limit_file, + SS_TOTAL_CX_FORCE_ADJV_MAP_MAX, + &thresholds_max, &trows, + &tcolumns); + /* load the max thresholds */ + if (ret < 0 || (trows != totCompData.header.force_node - + 1 || tcolumns != 1)) { + pr_err("production_test_data: parseProductionTestLimits SS_TOTAL_CX_FORCE_ADJV_MAP_MAX failed... ERROR %08X\n", + ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + ret = checkLimitsMapAdjTotal(total_adjvert, + totCompData.header. + force_node - 1, 1, + thresholds_max); + /* check the values with thresholds */ + if (ret != OK) { + pr_err("production_test_data: checkLimitsMap SS TOTAL CX FORCE failed... ERROR COUNT = %d\n", + ret); + pr_err("SS TOTAL CX FORCE ADJV TEST:.................FAIL\n\n"); + count_fail += 1; + if (stop_on_fail) + goto ERROR; + } else + pr_info("SS TOTAL CX FORCE ADJV TEST:.................OK\n\n"); + + kfree(thresholds_max); + thresholds_max = NULL; + kfree(total_adjvert); + total_adjvert = NULL; + } else + pr_info("SS TOTAL CX FORCE ADJ TEST:.................SKIPPED\n"); + } else + pr_info("SS TOTAL CX FORCE TEST:.................SKIPPED\n\n"); + + + + /************* SS SENSE CX *************/ + /* SS CX1 SENSE TEST */ + pr_info("SS CX1 SENSE TEST:\n"); + if (todo->SelfSenseCx1 == 1) { + ret = parseProductionTestLimits(path_limits, &limit_file, + SS_CX1_SENSE_MIN_MAX, + &thresholds, &trows, &tcolumns); + if (ret < 0 || (trows != 1 || tcolumns != 2)) { + pr_err("production_test_data: parseProductionTestLimits SS_CX1_SENSE_MIN_MAX failed... ERROR %08X\n", + ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + container = (short)ssCompData.s_cx1; + ret = checkLimitsMinMax(&container, 1, 1, thresholds[0], + thresholds[1]); + /* check the limits */ + if (ret != OK) { + pr_err("production_test_data: checkLimitsMinMax SS CX1 SENSE TEST failed... ERROR COUNT = %d\n", + ret); + count_fail += 1; + if (stop_on_fail) + goto ERROR; + } else + pr_info("SS CX1 SENSE TEST:.................OK\n\n"); + + kfree(thresholds); + thresholds = NULL; + } else + pr_info("SS CX1 SENSE TEST:.................SKIPPED\n\n"); + + + /* SS CX2 SENSE TEST */ + pr_info("SS CX2 SENSE MIN MAX TEST:\n"); + if (todo->SelfSenseCx2 == 1) { + ret = parseProductionTestLimits(path_limits, &limit_file, + SS_CX2_SENSE_MAP_MIN, + &thresholds_min, &trows, + &tcolumns); + /* load the min thresholds */ + if (ret < 0 || (trows != 1 || tcolumns != + ssCompData.header.sense_node)) { + pr_err("production_test_data: parseProductionTestLimits SS_CX2_SENSE_MAP_MIN failed... ERROR %08X\n", + ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + ret = parseProductionTestLimits(path_limits, &limit_file, + SS_CX2_SENSE_MAP_MAX, + &thresholds_max, &trows, + &tcolumns); + /* load the max thresholds */ + if (ret < 0 || (trows != 1 || tcolumns != + ssCompData.header.sense_node)) { + pr_err("production_test_data: parseProductionTestLimits SS_CX2_SENSE_MAP_MAX failed... ERROR %08X\n", + ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + ret = checkLimitsMap(ssCompData.cx2_sn, 1, + ssCompData.header.sense_node, + thresholds_min, thresholds_max); + /* check the values with thresholds */ + if (ret != OK) { + pr_err("production_test_data: checkLimitsMap SS CX2 SENSE failed... ERROR COUNT = %d\n", + ret); + pr_err("SS CX2 SENSE MIN MAX TEST:.................FAIL\n\n"); + count_fail += 1; + if (stop_on_fail) + goto ERROR; + } else + pr_info("SS CX2 SENSE MIN MAX TEST:.................OK\n\n"); + + kfree(thresholds_min); + thresholds_min = NULL; + kfree(thresholds_max); + thresholds_max = NULL; + } else + pr_info("SS CX2 SENSE MIN MAX TEST:.................SKIPPED\n"); + + pr_info("SS CX2 SENSE ADJ TEST:\n"); + if (todo->SelfSenseCx2Adj == 1) { + /* SS CX2 SENSE ADJH TEST */ + pr_info("SS CX2 SENSE ADJHORIZ TEST:\n"); + ret = computeAdjHoriz(ssCompData.cx2_sn, 1, + ssCompData.header.sense_node, &adjhor); + if (ret < 0) { + pr_err("production_test_data: computeAdjHoriz SS CX2 SENSE ADJH failed... ERROR %08X\n", + ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + pr_info("SS CX2 SENSE ADJH computed!\n"); + + + ret = parseProductionTestLimits(path_limits, &limit_file, + SS_CX2_SENSE_ADJH_MAP_MAX, + &thresholds_max, &trows, + &tcolumns); + /* load the max thresholds */ + if (ret < 0 || (trows != 1 || tcolumns != + ssCompData.header.sense_node - 1)) { + pr_err("production_test_data: parseProductionTestLimits SS_IX2_SENSE_MAP_MAX failed... ERROR %08X\n", + ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + ret = checkLimitsMapAdj(adjhor, 1, + ssCompData.header.sense_node - 1, + thresholds_max); + /* check the values with thresholds */ + if (ret != OK) { + pr_err("production_test_data: checkLimitsMapAdj SS CX2 SENSE ADJH failed... ERROR COUNT = %d\n", + ret); + pr_err("SS CX2 SENSE ADJH TEST:.................FAIL\n\n"); + count_fail += 1; + if (stop_on_fail) + goto ERROR; + } else + pr_info("SS CX2 SENSE ADJH TEST:.................OK\n"); + + kfree(thresholds_max); + thresholds_max = NULL; + kfree(adjhor); + adjhor = NULL; + } else + pr_info("SS CX2 SENSE ADJ TEST:.................SKIPPED\n\n"); + + /* SS TOTAL CX SENSE */ + pr_info("SS TOTAL CX SENSE TEST:\n"); + if (todo->SelfSenseCxTotal == 1 || todo->SelfSenseCxTotalAdj == 1) { + pr_info("SS TOTAL CX SENSE MIN MAX TEST:\n"); + if (todo->SelfSenseCxTotal == 1) { + ret = parseProductionTestLimits(path_limits, + &limit_file, + SS_TOTAL_CX_SENSE_MAP_MIN, + &thresholds_min, + &trows, &tcolumns); + /* load the min thresholds */ + if (ret < 0 || (trows != 1 || tcolumns != + totCompData.header.sense_node)) { + pr_err("production_test_data: parseProductionTestLimits SS_TOTAL_CX_SENSE_MAP_MIN failed... ERROR %08X\n", + ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + ret = parseProductionTestLimits(path_limits, + &limit_file, + SS_TOTAL_CX_SENSE_MAP_MAX, + &thresholds_max, + &trows, &tcolumns); + /* load the max thresholds */ + if (ret < 0 || (trows != 1 || tcolumns != + totCompData.header.sense_node)) { + pr_err("production_test_data: parseProductionTestLimits SS_TOTAL_CX_SENSE_MAP_MAX failed... ERROR %08X\n", + ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + ret = checkLimitsMapTotal(totCompData.cx_sn, 1, + totCompData.header.sense_node, + thresholds_min, + thresholds_max); + /* check the values with thresholds */ + if (ret != OK) { + pr_err("production_test_data: checkLimitsMap SS TOTAL CX SENSE failed... ERROR COUNT = %d\n", + ret); + pr_err("SS TOTAL CX SENSE MIN MAX TEST:.................FAIL\n\n"); + count_fail += 1; + if (stop_on_fail) + goto ERROR; + } else + pr_info("SS TOTAL CX SENSE MIN MAX TEST:.................OK\n\n"); + + kfree(thresholds_min); + thresholds_min = NULL; + kfree(thresholds_max); + thresholds_max = NULL; + } else + pr_info("SS TOTAL CX SENSE MIN MAX TEST:.................SKIPPED\n"); + + + /* SS TOTAL IX SENSE ADJH TEST */ + pr_info("SS TOTAL CX SENSE ADJ TEST:\n"); + if (todo->SelfSenseCxTotalAdj == 1) { + pr_info("SS TOTAL CX SENSE ADJHORIZ TEST:\n"); + ret = computeAdjHorizTotal(totCompData.cx_sn, 1, + totCompData.header.sense_node, + &total_adjhor); + if (ret < 0) { + pr_err("production_test_data: computeAdjHoriz SS TOTAL CX SENSE ADJH failed... ERROR %08X\n", + ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + pr_info("SS TOTAL CX SENSE ADJ HORIZ computed!\n"); + + + ret = parseProductionTestLimits(path_limits, + &limit_file, + SS_TOTAL_CX_SENSE_ADJH_MAP_MAX, + &thresholds_max, &trows, + &tcolumns); + /* load the max thresholds */ + if (ret < 0 || (trows != 1 || tcolumns != + totCompData.header.sense_node - 1)) { + pr_err("production_test_data: parseProductionTestLimits SS_TOTAL_CX_SENSE_ADJH_MAP_MAX failed... ERROR %08X\n", + ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + ret = checkLimitsMapAdjTotal(total_adjhor, 1, + totCompData.header. + sense_node - 1, + thresholds_max); + /* check the values with thresholds */ + if (ret != OK) { + pr_err("production_test_data: checkLimitsMapAdj SS TOTAL CX SENSE ADJH failed... ERROR COUNT = %d\n", + ret); + pr_err("SS TOTAL CX SENSE ADJH TEST:.................FAIL\n\n"); + count_fail += 1; + if (stop_on_fail) + goto ERROR; + } else + pr_info("SS TOTAL CX SENSE ADJH TEST:.................OK\n\n"); + + kfree(thresholds_max); + thresholds_max = NULL; + kfree(total_adjhor); + total_adjhor = NULL; + } else + pr_info("SS TOTAL CX SENSE ADJ TEST:.................SKIPPED\n"); + } else + pr_info("SS TOTAL CX SENSE TEST:.................SKIPPED\n"); + + + +ERROR: + if (count_fail == 0) { + kfree(ssCompData.ix2_fm); + ssCompData.ix2_fm = NULL; + kfree(ssCompData.ix2_sn); + ssCompData.ix2_sn = NULL; + kfree(ssCompData.cx2_fm); + ssCompData.cx2_fm = NULL; + kfree(ssCompData.cx2_sn); + ssCompData.cx2_sn = NULL; + kfree(totCompData.ix_fm); + totCompData.ix_fm = NULL; + kfree(totCompData.ix_sn); + totCompData.ix_sn = NULL; + kfree(totCompData.cx_fm); + totCompData.cx_fm = NULL; + kfree(totCompData.cx_sn); + totCompData.cx_sn = NULL; + pr_info("SS IX CX testes finished!.................OK\n\n"); + return OK; + } else { + /* print all kind of data in just one row for readability reason */ + print_frame_u8("SS Init Data Ix2_fm = ", array1dTo2d_u8( + ssCompData.ix2_fm, + ssCompData.header.force_node, 1), + ssCompData.header.force_node, 1); + print_frame_i8("SS Init Data Cx2_fm = ", array1dTo2d_i8( + ssCompData.cx2_fm, + ssCompData.header.force_node, 1), + ssCompData.header.force_node, 1); + print_frame_u8("SS Init Data Ix2_sn = ", array1dTo2d_u8( + ssCompData.ix2_sn, + ssCompData.header.sense_node, + ssCompData.header.sense_node), 1, + ssCompData.header.sense_node); + print_frame_i8("SS Init Data Cx2_sn = ", array1dTo2d_i8( + ssCompData.cx2_sn, + ssCompData.header.sense_node, + ssCompData.header.sense_node), 1, + ssCompData.header.sense_node); + print_frame_u16("TOT SS Init Data Ix_fm = ", array1dTo2d_u16( + totCompData.ix_fm, + totCompData.header.force_node, 1), + totCompData.header.force_node, 1); + print_frame_short("TOT SS Init Data Cx_fm = ", + array1dTo2d_short(totCompData.cx_fm, + totCompData.header. + force_node, 1), + totCompData.header.force_node, 1); + print_frame_u16("TOT SS Init Data Ix_sn = ", array1dTo2d_u16( + totCompData.ix_sn, + totCompData.header.sense_node, + totCompData.header.sense_node), 1, + totCompData.header.sense_node); + print_frame_short("TOT SS Init Data Cx_sn = ", + array1dTo2d_short(totCompData.cx_sn, + totCompData.header. + sense_node, + totCompData.header. + sense_node), + 1, totCompData.header.sense_node); + pr_err("SS IX CX testes finished!.................FAILED fails_count = %d\n\n", + count_fail); + if (thresholds != NULL) + kfree(thresholds); + if (thresholds_min != NULL) + kfree(thresholds_min); + if (thresholds_max != NULL) + kfree(thresholds_max); + if (adjhor != NULL) + kfree(adjhor); + if (adjvert != NULL) + kfree(adjvert); + if (total_adjhor != NULL) + kfree(total_adjhor); + if (total_adjvert != NULL) + kfree(total_adjvert); + if (ssCompData.ix2_fm != NULL) + kfree(ssCompData.ix2_fm); + if (ssCompData.ix2_sn != NULL) + kfree(ssCompData.ix2_sn); + if (ssCompData.cx2_fm != NULL) + kfree(ssCompData.cx2_fm); + if (ssCompData.cx2_sn != NULL) + kfree(ssCompData.cx2_sn); + if (totCompData.ix_fm != NULL) + kfree(totCompData.ix_fm); + if (totCompData.ix_sn != NULL) + kfree(totCompData.ix_sn); + if (totCompData.cx_fm != NULL) + kfree(totCompData.cx_fm); + if (totCompData.cx_sn != NULL) + kfree(totCompData.cx_sn); + return ERROR_TEST_CHECK_FAIL | ERROR_PROD_TEST_DATA; + } + +ERROR_LIMITS: + if (thresholds != NULL) + kfree(thresholds); + if (thresholds_min != NULL) + kfree(thresholds_min); + if (thresholds_max != NULL) + kfree(thresholds_max); + if (adjhor != NULL) + kfree(adjhor); + if (adjvert != NULL) + kfree(adjvert); + if (total_adjhor != NULL) + kfree(total_adjhor); + if (total_adjvert != NULL) + kfree(total_adjvert); + if (ssCompData.ix2_fm != NULL) + kfree(ssCompData.ix2_fm); + if (ssCompData.ix2_sn != NULL) + kfree(ssCompData.ix2_sn); + if (ssCompData.cx2_fm != NULL) + kfree(ssCompData.cx2_fm); + if (ssCompData.cx2_sn != NULL) + kfree(ssCompData.cx2_sn); + if (totCompData.ix_fm != NULL) + kfree(totCompData.ix_fm); + if (totCompData.ix_sn != NULL) + kfree(totCompData.ix_sn); + if (totCompData.cx_fm != NULL) + kfree(totCompData.cx_fm); + if (totCompData.cx_sn != NULL) + kfree(totCompData.cx_sn); + return ret; +} + +/** + * Perform a complete Data Test check of the IC + * @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 + * otherwise it keeps going performing all the selected test + * @param todo pointer to a TestToDo variable which select the test to do + * @return OK if success or an error code which specify the type of error + */ +int production_test_data(char *path_limits, int stop_on_fail, TestToDo *todo) +{ + int res = OK, ret; + + if (todo == NULL) { + pr_err("production_test_data: No TestToDo specified!! ERROR = %08X\n", + (ERROR_OP_NOT_ALLOW | ERROR_PROD_TEST_DATA)); + return ERROR_OP_NOT_ALLOW | ERROR_PROD_TEST_DATA; + } + + + pr_info("DATA Production test is starting...\n"); + + + ret = production_test_ms_raw(path_limits, stop_on_fail, todo); + res |= ret; + if (ret < 0) { + pr_err("production_test_data: production_test_ms_raw failed... ERROR = %08X\n", + ret); + if (stop_on_fail == 1) + goto END; + } + + + + ret = production_test_ms_cx(path_limits, stop_on_fail, todo); + res |= ret; + if (ret < 0) { + pr_err("production_test_data: production_test_ms_cx failed... ERROR = %08X\n", + ret); + if (stop_on_fail == 1) + goto END; + } + + + ret = production_test_ss_raw(path_limits, stop_on_fail, todo); + res |= ret; + if (ret < 0) { + pr_err("production_test_data: production_test_ss_raw failed... ERROR = %08X\n", + ret); + if (stop_on_fail == 1) + goto END; + } + + ret = production_test_ss_ix_cx(path_limits, stop_on_fail, todo); + res |= ret; + if (ret < 0) { + pr_err("production_test_data: production_test_ss_ix_cx failed... ERROR = %08X\n", + ret); + if (stop_on_fail == 1) + goto END; + } + +END: + freeLimitsFile(&limit_file); /* /< release the limit file loaded + * during the test */ + if (res < OK) + pr_err("DATA Production test failed!\n"); + else + pr_info("DATA Production test finished!\n"); + return res; +} + + +/*************** TP Sensitivity calibration API ********************/ + +/** + * Perform the Pre Calibration MS Test when the stimpad is down + * @param[out] frame pointer to the frame which will contain + * the average frame resulting from the test + * @param target reference value for the frame, each node should be + * around +-percentage% this value + * @param percentage percentage of the target value which define + * the valid interval for the frame, if <0 the test will be skipped + * @return OK if success or an error code which specify the type of error + */ +int tp_sensitivity_test_pre_cal_ms(MutualSenseFrame *finalFrame, short target, + int percentage) +{ + int ret = OK; + int count = 0, i = 0, j = 0; + short min, max; + MutualSenseFrame frame; + + finalFrame->node_data = NULL; + + + pr_info("%s: Start TP sensitivity MS Pre Cal...\n", __func__); + pr_info("%s: IMPORTANT!!! Stimpad should be on the display of the device!\n", + __func__); + ret = getMSFrame3(MS_STRENGTH, &frame); + if (ret < OK) { + pr_err("%s: can not read MS Frame... ERROR %08X\n", + __func__, ret); + goto ERROR; + } + + finalFrame->header = frame.header; + finalFrame->node_data_size = frame.node_data_size; + + finalFrame->node_data = (short *)kzalloc(frame.node_data_size * + sizeof(short), GFP_KERNEL); + if (finalFrame->node_data == NULL) { + pr_err("%s: can not allocate node_data ERROR %08X\n", + __func__, ERROR_ALLOC | ERROR_GET_FRAME); + ret = ERROR_ALLOC | ERROR_GET_FRAME; + goto ERROR; + } + + /* collecting frames */ + do { + for (i = 0; i < finalFrame->node_data_size; i++) { + finalFrame->node_data[i] += (frame.node_data[i] * 10) / + SENS_TEST_NUM_FRAMES; + } + + if (frame.node_data != NULL) { + kfree(frame.node_data); + frame.node_data = NULL; + } + + count++; + + /* exclude one more reading at the end*/ + if (count < SENS_TEST_NUM_FRAMES) + ret = getMSFrame3(MS_STRENGTH, &frame); + } while ((count < SENS_TEST_NUM_FRAMES) && (ret >= OK)); + + if (ret < OK) { + pr_err("%s: Error while capturing the frame %d! ERROR %08X\n", + __func__, count, ret); + goto ERROR; + } + + ret = OK; + /* check against +-percentage% target */ + pr_info("%s: Computing average frame...\n", __func__); + + min = target - (target * percentage / 100); + max = target + (target * percentage / 100); + + for (i = 0; i < finalFrame->header.force_node; i++) { + for (j = 0; j < finalFrame->header.sense_node; j++) { + finalFrame->node_data[i * + finalFrame->header.sense_node + + j] /= 10; + /*if percentage is <0 skip this test, just collect data */ + if ((percentage > 0) && + ((finalFrame->node_data[i * finalFrame->header. + sense_node + + j] > + max) || + (finalFrame->node_data[i * + finalFrame->header. + sense_node + + j] < + min))) { + pr_err("%s: MS Force Node[%d, %d] = %d exceed limit [%d, %d]\n", + __func__, i, j, + finalFrame->node_data[i * + finalFrame + ->header. + sense_node + j], + min, max); + ret = ERROR_TEST_CHECK_FAIL; + } + } + } + + + /* print average frame in the log */ + print_frame_short("MS FS Mean =", + array1dTo2d_short( + finalFrame->node_data, + finalFrame->node_data_size, + finalFrame->header.sense_node), + finalFrame->header.force_node, + finalFrame->header.sense_node); + + if (ret != OK) + pr_err("%s: TP sensitivity MS Pre Cal test FAILED... ERROR %08X\n", + __func__, ret); + else + pr_info("%s: TP sensitivity MS Pre Cal FINISHED!\n", + __func__); + + return ret; + + +ERROR: + if (frame.node_data != NULL) { + kfree(frame.node_data); + frame.node_data = NULL; + } + + + if (finalFrame->node_data != NULL) { + kfree(finalFrame->node_data); + finalFrame->node_data = NULL; + } + + return ret; +} + + + +/** + * Perform the Pre Calibration SS Test when the stimpad is down + * @param[out] frame pointer to the frame which will contain the average frame + * resulting from the test + * @param target reference value for the frame, each node should be around + * +-percentage% this value + * @param percentage percentage of the target value which define the valid + * interval for the frame + * @return OK if success or an error code which specify the type of error + */ +int tp_sensitivity_test_pre_cal_ss(SelfSenseFrame *finalFrame, short target, + int percentage) +{ + int ret = OK; + int count = 0, i = 0; + short min, max; + SelfSenseFrame frame; + int *temp_force = NULL; + int *temp_sense = NULL; + + finalFrame->force_data = NULL; + finalFrame->sense_data = NULL; + + pr_info("%s: Start TP sensitivity SS Pre Cal...\n", __func__); + pr_info("%s: IMPORTANT!!! Stimpad should be on the display of the device!\n", + __func__); + ret = getSSFrame3(SS_STRENGTH, &frame); + if (ret < OK) { + pr_err("%s: can not read SS Frame... ERROR %08X\n", + __func__, ret); + goto ERROR; + } + + finalFrame->header = frame.header; + + finalFrame->force_data = (short *)kzalloc(frame.header.force_node * + sizeof(short), GFP_KERNEL); + temp_force = (int *)kzalloc(frame.header.force_node * + sizeof(int), GFP_KERNEL); + finalFrame->sense_data = (short *)kzalloc(frame.header.sense_node * + sizeof(short), GFP_KERNEL); + temp_sense = (int *)kzalloc(frame.header.sense_node * + sizeof(int), GFP_KERNEL); + if (finalFrame->force_data == NULL || + temp_force == NULL || + finalFrame->sense_data == NULL || + temp_sense == NULL) { + + pr_err("%s: can not allocate memory ERROR %08X\n", + __func__, ERROR_ALLOC | ERROR_GET_FRAME); + ret = ERROR_ALLOC | ERROR_GET_FRAME; + goto ERROR; + } + + /* collecting frames */ + do { + for (i = 0; i < finalFrame->header.force_node; i++) + temp_force[i] += frame.force_data[i]; + + for (i = 0; i < finalFrame->header.sense_node; i++) + temp_sense[i] += frame.sense_data[i]; + + count++; + + if (frame.force_data != NULL) { + kfree(frame.force_data); + frame.force_data = NULL; + } + if (frame.sense_data != NULL) { + kfree(frame.sense_data); + frame.sense_data = NULL; + } + + /* exclude one more reading at the end*/ + if (count < SENS_TEST_NUM_FRAMES) + ret = getSSFrame3(SS_STRENGTH, &frame); + } while ((count < SENS_TEST_NUM_FRAMES) && (ret >= OK)); + + if (ret < OK) { + pr_err("%s: Error while capturing the frame %d! ERROR %08X\n", + __func__, count, ret); + goto ERROR; + } + + ret = OK; + + /* compute the average and check against +-percentage% target */ + min = target - (target * percentage / 100); + max = target + (target * percentage / 100); + + for (i = 0; i < finalFrame->header.force_node; i++) { + finalFrame->force_data[i] = temp_force[i] / + SENS_TEST_NUM_FRAMES; + if ((percentage > 0) && ((finalFrame->force_data[i] > max) || + (finalFrame->force_data[i] < min))) { + pr_err("%s: SS Force Node[%d] = %d exceed limit [%d, %d]\n", + __func__, i, finalFrame->force_data[i], + min, max); + ret = ERROR_TEST_CHECK_FAIL; + } + } + + for (i = 0; i < finalFrame->header.sense_node; i++) { + finalFrame->sense_data[i] = temp_sense[i] / + SENS_TEST_NUM_FRAMES; + if ((finalFrame->sense_data[i] > max) || + (finalFrame->sense_data[i] < min)) { + pr_err("%s: SS Sense Node[%d] = %d exceed limit [%d, %d]\n", + __func__, i, finalFrame->sense_data[i], + min, max); + ret = ERROR_TEST_CHECK_FAIL; + } + } + + /* print average frame in the log */ + print_frame_short("SS FS force Mean =", + array1dTo2d_short( + finalFrame->force_data, + finalFrame->header.force_node, + 1), + finalFrame->header.force_node, 1); + print_frame_short("SS FS sense Mean =", + array1dTo2d_short( + finalFrame->sense_data, + finalFrame->header.sense_node, + finalFrame->header.sense_node), + 1, finalFrame->header.sense_node); + + + kfree(temp_force); + temp_force = NULL; + + kfree(temp_sense); + temp_sense = NULL; + + if (ret < OK) + pr_err("%s: TP sensitivity SS Pre Cal test FAILED... ERROR %08X\n", + __func__, ret); + else { + pr_info("%s: TP sensitivity SS Pre Cal FINISHED!\n", + __func__); + ret = OK; + } + + return ret; + + +ERROR: + + kfree(temp_force); + temp_force = NULL; + + kfree(temp_sense); + temp_sense = NULL; + + kfree(frame.force_data); + frame.force_data = NULL; + + kfree(frame.sense_data); + frame.sense_data = NULL; + + kfree(finalFrame->force_data); + finalFrame->force_data = NULL; + + kfree(finalFrame->sense_data); + finalFrame->sense_data = NULL; + + return ret; +} + +/** + * Compute Digital gains for calibration + * @param frame pointer to the frame used as reference to compute the gains + * @param target reference target value for computing the gains + * @param saveGain if 1, will save the gain table into the chip otherwise will + * not save it + * @return OK if success or an error code which specify the type of error + */ +int tp_sensitivity_compute_gains(MutualSenseFrame *frame, short target, + int saveGain) +{ + int ret = OK; + int i = 0; + u8 gains[frame->node_data_size]; + + if ((frame->node_data == NULL) || (frame->node_data_size == 0)) { + pr_err("%s: Invalid frame data passed as argument! ERROR %08X\n", + __func__, ERROR_OP_NOT_ALLOW); + return ERROR_OP_NOT_ALLOW; + } + + memset(gains, 0, frame->node_data_size); + + pr_info("%s: Start to compute Digital Gains...\n", __func__); + for (i = 0; i < frame->node_data_size; i++) + gains[i] = ((target * 100) / frame->node_data[i]) > 255 ? + (u8)(255) : (u8)(((target * 100) / + frame->node_data[i])); + /* clamp the max value to 255 because gain is only one byte */ + + + /* print average frame in the log */ + print_frame_u8("MS Digital Gain =", + array1dTo2d_u8( + gains, + frame->node_data_size, + frame->header.sense_node), + frame->header.force_node, + frame->header.sense_node); + + + /* if(saveGain==1){ */ + /* write gains into the IC */ + ret = writeHostDataMemory(LOAD_SENS_CAL_COEFF, gains, + frame->header.force_node, + frame->header.sense_node, 0, 0, saveGain); + if (ret != OK) + pr_err("%s: impossible to write digital gains! ERROR %08X\n", + __func__, ret); + /* } */ + + if (ret < OK) + pr_err("%s: compute Digital Gains FAILED! ERROR %08X\n", + __func__, ret); + else { + pr_info("%s: compute Digital Gains FINISHED!\n", __func__); + ret = OK; + } + + return ret; +} + +/** + * Perform the Post Calibration MS Test when the stimpad is down + * @param[out] finalFrame pointer to the frame which will contain + * the average frame resulting from the test + * @param[out] deltas pointer to the frame which will contain + * the FS Uniform frame (worst_neighborhood/mean) + * @param target reference value for the frame, each node should be + * around +-percentage% this value + * @param percentage percentage of the target value which define + * the valid interval for the frame, if <0 the test will be skipped + * @param[out] mean_normal pointer to the variable which will contain the mean + * of the normal area + * @param[out] mean_edge pointer to the variable which will contain the mean of + * the edge area + * @return OK if success or an error code which specify the type of error + */ +int tp_sensitivity_test_post_cal_ms(MutualSenseFrame *finalFrame, + MutualSenseFrame *deltas, short target, + int percentage, int *mean_normal, + int *mean_edge) +{ + short currentNode; + int final_force_num; + int final_sense_num; + short *final_node; + int delta_sense_num; + short *delta_node; + short *delta; + short adjNode; + int ret = OK; + int i = 0, j = 0, min, max; + + + if ((finalFrame == NULL) || (deltas == NULL) || (mean_normal == NULL) || + (mean_edge == NULL)) { + pr_err("%s: Invalid arguments Passed! ERROR %08X\n", + __func__, ERROR_OP_NOT_ALLOW); + return ERROR_OP_NOT_ALLOW; + } + + *mean_normal = 0; + *mean_edge = 0; + + finalFrame->node_data = NULL; + deltas->node_data = NULL; + + pr_info("%s: Start TP sensitivity MS Post Cal...\n", __func__); + pr_info("%s: IMPORTANT!!! Stimpad should be on the display of the device!\n", + __func__); + + /* collect frames skipping the tests + print on the log */ + ret = tp_sensitivity_test_pre_cal_ms(finalFrame, target, -1); + if (ret < OK) { + pr_err("%s: can not collect MS Frame... ERROR %08X\n", + __func__, ret); + goto ERROR; + } + + + deltas->header = finalFrame->header; + deltas->node_data_size = finalFrame->node_data_size; + + deltas->node_data = (short *)kzalloc(deltas->node_data_size * + sizeof(short), GFP_KERNEL); + if (deltas->node_data == NULL) { + pr_err("%s: can not allocate deltas node_data ERROR %08X\n", + __func__, ERROR_ALLOC | ERROR_GET_FRAME); + ret = ERROR_ALLOC | ERROR_GET_FRAME; + goto ERROR; + } + + /* compute the average of the whole panel and check against + * +-percentage% target */ + pr_info("%s: Computing average of whole panel and delta for each node...\n", + __func__); + + final_force_num = finalFrame->header.force_node; + final_sense_num = finalFrame->header.sense_node; + final_node = finalFrame->node_data; + delta_sense_num = deltas->header.sense_node; + delta_node = deltas->node_data; + + + for (i = 0; i < final_force_num; i++) { + for (j = 0; j < final_sense_num; j++) { + currentNode = finalFrame->node_data[i * + finalFrame->header. + sense_node + j]; + delta = &delta_node[i * delta_sense_num + j]; + + if ((i == 0) || + (i == (final_force_num - 1)) || + (j == 0) || + (j == (final_sense_num - 1))) { + /* edge nodes */ + *mean_edge += currentNode; + if ((i == 0) || + (i == final_force_num - 1)) { + /* need to check adj node up or down for + * nodes in the corners */ + if ((i == 0) && + ((j == 0) || + (j == final_sense_num - 1))) { + adjNode = currentNode - + final_node[(i + 1) * + final_sense_num + j]; + if (abs(adjNode) > *delta) + *delta = abs(adjNode); + } + + if ((i == (final_force_num - 1)) && + ((j == 0) || + (j == final_sense_num - 1))) { + adjNode = currentNode - + final_node[(i - 1) * + final_sense_num + j]; + if (abs(adjNode) > *delta) + *delta = abs(adjNode); + } + + /* scan the row */ + if ((j - 1) >= 0) { + adjNode = currentNode - + final_node[i * + final_sense_num + + (j - 1)]; + if (abs(adjNode) > *delta) + *delta = abs(adjNode); + } + + if ((j + 1) < final_sense_num) { + adjNode = currentNode - + final_node[i * + final_sense_num + + (j + 1)]; + if (abs(adjNode) > *delta) + *delta = abs(adjNode); + } + } + + if ((j == 0) || + (j == final_sense_num - 1)) { + /* scan the column */ + if ((i - 1) >= 0) { + adjNode = currentNode - + final_node[(i - 1) * + final_sense_num + j]; + if (abs(adjNode) > *delta) + *delta = abs(adjNode); + } + + if ((i + 1) < final_force_num) { + adjNode = currentNode - + final_node[(i + 1) * + final_sense_num + j]; + if (abs(adjNode) > *delta) + *delta = abs(adjNode); + } + } + } else { + /*normal nodes */ + *mean_normal += currentNode; + + /* picking up the worst difference between + * one pixel and its neighbors */ + if ((i - 1) >= 1) { + adjNode = currentNode - + final_node[(i - 1) * + final_sense_num + j]; + if (abs(adjNode) > *delta) + *delta = abs(adjNode); + } + + if ((i + 1) < (final_force_num - 1)) { + adjNode = currentNode - + final_node[(i + 1) * + final_sense_num + j]; + if (abs(adjNode) > *delta) + *delta = abs(adjNode); + } + if ((j - 1) >= 1) { + adjNode = currentNode - + final_node[i * + final_sense_num + (j - 1)]; + if (abs(adjNode) > *delta) + *delta = abs(adjNode); + } + + if ((j + 1) < (final_sense_num - 1)) { + adjNode = currentNode - + final_node[i * + final_sense_num + (j + 1)]; + if (abs(adjNode) > *delta) + *delta = abs(adjNode); + } + } + } + } + + *mean_normal /= (finalFrame->header.force_node - 2) * + (finalFrame->header.sense_node - 2); + *mean_edge /= (finalFrame->header.force_node * 2) + + (finalFrame->header.sense_node - 2) * 2; + + pr_info("%s: Normal Frame average = %d\n", __func__, *mean_normal); + pr_info("%s: Edge Frame average = %d\n", __func__, *mean_edge); + /* compute the average and check against +-% target */ + min = target - (target * percentage / 100); + max = target + (target * percentage / 100); + + if ((percentage > 0) && ((*mean_normal < min) || (*mean_normal > + max))) { + pr_err("%s: Normal Frame average = %d exceed limit [%d, %d]\n", + __func__, *mean_normal, min, max); + ret = ERROR_TEST_CHECK_FAIL; + } + + if ((percentage > 0) && ((*mean_edge < min) || (*mean_edge > max))) { + pr_err("%s: Edge Frame average = %d exceed limit [%d, %d]\n", + __func__, *mean_edge, min, max); + ret = ERROR_TEST_CHECK_FAIL; + } + + for (i = 0; i < deltas->header.force_node; i++) { + for (j = 0; j < deltas->header.sense_node; j++) { + if ((i == 0) || (i == deltas->header.force_node) || + (j == 0) || (j == deltas->header.sense_node)) + deltas->node_data[i * + deltas->header.sense_node + + j] = + deltas->node_data[i * + deltas->header. + sense_node + j] * + 100 / + (*mean_edge); + else + deltas->node_data[i * + deltas->header.sense_node + + j] = + deltas->node_data[i * + deltas->header. + sense_node + j] * + 100 / + (*mean_normal); + + if ((percentage > 0) && (deltas->node_data[i * + deltas-> + header. + sense_node + + j] > + percentage)) { + pr_err("%s: Delta Node[%d, %d] = %d exceed limit [%d]\n", + __func__, i, j, + deltas->node_data[i * + deltas + ->header.sense_node + + j], percentage); + ret = ERROR_TEST_CHECK_FAIL; + } + } + } + + + /* print average frame in the log */ + print_frame_short("FS Uniform (%) =", + array1dTo2d_short( + deltas->node_data, + deltas->node_data_size, + deltas->header.sense_node), + deltas->header.force_node, + deltas->header.sense_node); + + + if (ret < OK) + pr_err("%s: TP sensitivity MS Post Cal test FAILED... ERROR %08X\n", + __func__, ret); + else { + pr_info("%s: TP sensitivity MS Post Cal FINISHED!\n", + __func__); + ret = OK; + } + + return ret; + + +ERROR: + if (deltas->node_data != NULL) { + kfree(deltas->node_data); + deltas->node_data = NULL; + } + + + if (finalFrame->node_data != NULL) { + kfree(finalFrame->node_data); + finalFrame->node_data = NULL; + } + + return ret; +} + + +/** + * Compute Digital gains for calibration + * @param enter if =1 turn on TP Sensitivity mode, otherwise will turn it off + * @param saveGain if 1, will save the gain table into the chip otherwise will + * not save it + * @return OK if success or an error code which specify the type of error + */ +int tp_sensitivity_mode(u8 enter, int saveGain) +{ + int res, ret = OK; + u8 cmd[4] = { 0xC0, 0x00, 0x00, 0x00 }; + u8 sett = SPECIAL_WRITE_HOST_MEM_TO_FLASH; + + pr_info("%s: Start TP Sensitivity Mode... enter = %02X\n", + __func__, enter); + if (enter == 1) { + /* enter TP Sensitivity mode*/ + ret = fts_disableInterrupt(); + pr_info("%s: Entering TP Sensitivity Mode disabling algos...\n", + __func__); + cmd[3] = 0x01; + res = fts_writeFwCmd(cmd, 4); + if (res < OK) + pr_err("%s: Error while turning on TP Sens Mode! ERROR %08X\n", + __func__, res); + } else { + /* exit TP Sensitivity mode*/ + pr_info("%s: Exiting TP Sensitivity Mode enabling algos...\n", + __func__); + res = fts_writeFwCmd(cmd, 4); + if (res < OK) + pr_err("%s: Error while turning off TP Sens Mode! ERROR %08X\n", + __func__, res); + + if (saveGain == 1) { + pr_info("%s: Trigger writing gains into the flash...\n", + __func__); + ret = writeSysCmd(SYS_CMD_SPECIAL, &sett, 1); + if (ret < OK) + pr_err("%s: error while writing gains into the flash! ERROR %08X\n", + __func__, res); + } + + res |= senseOn(); + res |= fts_enableInterrupt(); + } + + res |= ret; + + if (res < OK) + pr_err("%s: TP Sensitivity Mode... ERROR %08X!\n", + __func__, res); + else + pr_info("%s: TP Sensitivity Mode FINISHED!\n", __func__); + + return res; +} + + +/** + * Compute Digital gains for calibration + * @param scan select the scan mode which should be enabled + * @param enableGains =1 apply gains when computing the strength otherwise + * the gains will be ignored + * @return OK if success or an error code which specify the type of error + */ +int tp_sensitivity_set_scan_mode(u8 scan, int enableGains) +{ + int res, ret = OK; + u8 cmd[4] = { 0xC0, 0x00, 0x01, 0x00 }; + + + pr_info("%s: Set TP Sensitivity Scan Mode... scan = %02X, enableGains = %d\n", + __func__, scan, enableGains); + + + if (enableGains == 1) { + /* Consider Sensitivity Gains when computing Strength */ + cmd[3] = 0x01; + ret = fts_writeFwCmd(cmd, 4); + if (ret < OK) + pr_err("%s: Error while enabling Gains in TP Sens Mode! ERROR %08X\n", + __func__, ret); + } else { + /* Exclude Sensitivity Gains when computing Strength */ + ret = fts_writeFwCmd(cmd, 4); + if (ret < OK) + pr_err("%s: Error while disabling Gain in TP Sens Mode! ERROR %08X\n", + __func__, ret); + } + + res = setScanMode(SCAN_MODE_LOCKED, scan); + if (res < OK) + pr_err("Error while setting the scan frequency... ERROR %08X\n", + res); + + res |= ret; + + if (res < OK) + pr_err("%s: Set TP Sensitivity Scan Mode... ERROR %08X!\n", + __func__, res); + else + pr_info("%s: Set TP Sensitivity Scan FINISHED!\n", __func__); + + return res; +} + + + + +/** + * Compute the standard deviation for each node form a series of frames + * @param numFrames number of frames to collect to compute the standard + * deviation + * @param[out] std pointer to the frame which will contain the standard + * deviation for each node + * @return OK if success or an error code which specify the type of error + */ +int tp_sensitivity_test_std_ms(int numFrames, MutualSenseFrame *std) +{ + int ret = OK; + int i = 0, count = 0; + MutualSenseFrame frame; + int *mean = NULL;/* store the mean value for each node */ + unsigned long *stdTemp = NULL; + + + if (std == NULL) { + pr_err("%s: Invalid arguments Passed! ERROR %08X\n", + __func__, ERROR_OP_NOT_ALLOW); + return ERROR_OP_NOT_ALLOW; + } + + std->node_data = NULL; + + pr_info("%s: Start TP sensitivity STD... collecting %d frames!\n", + __func__, numFrames); + + /* collect frames skipping the tests + print on the log */ + ret = getMSFrame3(MS_STRENGTH, &frame); + if (ret < OK) { + pr_err("%s: can not read MS Frame... ERROR %08X\n", + __func__, ret); + goto ERROR; + } + + std->header = frame.header; + std->node_data_size = frame.node_data_size; + + std->node_data = (short *)kzalloc(std->node_data_size * sizeof(short), + GFP_KERNEL); + mean = (int *)kzalloc(std->node_data_size * sizeof(int), GFP_KERNEL); + stdTemp = (unsigned long *)kzalloc(std->node_data_size * + sizeof(unsigned long), + GFP_KERNEL); + if (std->node_data == NULL || + mean == NULL || + stdTemp == NULL) { + pr_err("%s: can not allocate memory ERROR %08X\n", + __func__, ERROR_ALLOC | ERROR_GET_FRAME); + ret = ERROR_ALLOC | ERROR_GET_FRAME; + goto ERROR; + } + + /* collecting frames */ + do { + for (i = 0; i < frame.node_data_size; i++) { + mean[i] += frame.node_data[i]; + stdTemp[i] += frame.node_data[i] * frame.node_data[i]; + } + count++; + + if (frame.node_data != NULL) { + kfree(frame.node_data); + frame.node_data = NULL; + } + + /* exclude one more reading at the end*/ + if (count < numFrames) + ret = getMSFrame3(MS_STRENGTH, &frame); + } while ((count < numFrames) && (ret >= OK)); + + if (ret < OK) { + pr_err("%s: error while collecting the frames! ERROR%08X\n", + __func__, ret); + goto ERROR; + } + + /* compute the average for each node */ + pr_info("%s: Computing std for each node...\n", __func__); + + for (i = 0; i < std->node_data_size; i++) { + mean[i] /= numFrames; + stdTemp[i] = stdTemp[i] / numFrames - (mean[i] * mean[i]); + std->node_data[i] = (short)int_sqrt(stdTemp[i]); + } + + kfree(stdTemp); + stdTemp = NULL; + kfree(mean); + mean = NULL; + + /* print average frame in the log */ + print_frame_short("STD =", + array1dTo2d_short( + std->node_data, + std->node_data_size, + std->header.sense_node), + std->header.force_node, + std->header.sense_node); + + if (ret < OK) + pr_err("%s: TP sensitivity STD test FAILED... ERROR %08X\n", + __func__, ret); + else { + pr_info("%s: TP sensitivity STD FINISHED!\n", + __func__); + ret = OK; + } + + return ret; + +ERROR: + + kfree(frame.node_data); + frame.node_data = NULL; + + kfree(std->node_data); + std->node_data = NULL; + + kfree(stdTemp); + stdTemp = NULL; + + kfree(mean); + mean = NULL; + + return ret; +} + + +/** + * 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 + */ +int getLimitsFile(char *path, LimitFile *file) +{ + const struct firmware *fw = NULL; + struct device *dev = NULL; + int fd = -1; + + pr_info("Get Limits File starting... %s\n", path); + + if (file->data != NULL) { + /* to avoid memory leak on consecutive call of + * the function with the same pointer */ + pr_err("Pointer to Limits Data already contains something... freeing its content!\n"); + 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("Loading Limits File from .h!\n"); + 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("Error while allocating data... ERROR %08X\n", + path, ERROR_ALLOC); + return ERROR_ALLOC; + } +#else + pr_err("limit file path NULL... ERROR %08X\n", + ERROR_FILE_NOT_FOUND); + return ERROR_FILE_NOT_FOUND; +#endif + } else { + dev = getDev(); + if (dev != NULL) { + pr_info("Loading Limits File from .csv!\n"); + fd = request_firmware(&fw, path, dev); + if (fd == 0) { + pr_info("Start to copy %s...\n", 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_info("Limit file Size = %d\n", + file->size); + release_firmware(fw); + return OK; + } else { + pr_err("Error while allocating data... ERROR %08X\n", + ERROR_ALLOC); + release_firmware(fw); + return ERROR_ALLOC; + } + } else { + pr_err("Request the file %s failed... ERROR %08X\n", + path, ERROR_FILE_NOT_FOUND); + return ERROR_FILE_NOT_FOUND; + } + } else { + pr_err("Error while getting the device ERROR %08X\n", + 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 + */ + +int freeLimitsFile(LimitFile *file) +{ + pr_info("Freeing Limit File ...\n"); + if (file != NULL) { + if (file->data != NULL) { + kfree(file->data); + file->data = NULL; + } else + pr_err("Limit File was already freed!\n"); + file->size = 0; + strlcpy(file->name, " ", MAX_LIMIT_FILE_NAME); + return OK; + } else { + pr_err("Passed a NULL argument! ERROR %08X\n", + 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 + */ +int freeCurrentLimitsFile(void) +{ + return freeLimitsFile(&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 parseProductionTestLimits(char *path, LimitFile *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("No limit File data passed... try to get them from the system!\n"); + ret = getLimitsFile(LIMITS_FILE, &limit_file); + if (ret < OK) { + pr_err("parseProductionTestLimits: ERROR %08X\n", + ERROR_FILE_NOT_FOUND); + return ERROR_FILE_NOT_FOUND; + } + size = limit_file.size; + data_file = limit_file.data; + } else { + pr_info("Limit File data passed as arguments!\n"); + size = file->size; + data_file = file->data; + } + + + + pr_info("The size of the limits file is %d bytes...\n", size); + + + + while (find == 0) { + /* start to look for the wanted label */ + if (readLine(&data_file[pointer], line, size - pointer, &n) < + 0) { + find = -1; + break; + } + pointer += n; + if (line[0] == '*') { + /* each header row start with * ex. *label,n_row,n_colum */ + line2 = kstrdup(line, GFP_KERNEL); + if (line2 == NULL) { + pr_err("parseProductionTestLimits: kstrdup ERROR %08X\n", + ERROR_ALLOC); + ret = ERROR_ALLOC; + goto END; + } + buf = line2; + line2 += 1; + token = strsep(&line2, ","); + if (strcmp(token, label) == 0) { + /* if the row is the wanted one, r + * retrieve rows and columns info */ + find = 1; + token = strsep(&line2, ","); + if (token != NULL) { + sscanf(token, "%d", row); + pr_info("Row = %d\n", *row); + } else { + pr_err("parseProductionTestLimits 1: ERROR %08X\n", + ERROR_FILE_PARSE); + ret = ERROR_FILE_PARSE; + goto END; + } + token = strsep(&line2, ","); + if (token != NULL) { + sscanf(token, "%d", column); + pr_info("Column = %d\n", *column); + } else { + pr_err("parseProductionTestLimits 2: ERROR %08X\n", + ERROR_FILE_PARSE); + ret = ERROR_FILE_PARSE; + goto END; + } + + kfree(buf); + buf = NULL; + *data = (int *)kmalloc(((*row) * (*column)) * + sizeof(int), GFP_KERNEL); + /* allocate the memory for containing the data */ + j = 0; + if (*data == NULL) { + pr_err("parseProductionTestLimits: ERROR %08X\n", + ERROR_ALLOC); + ret = ERROR_ALLOC; + goto END; + } + + + /* start to read the data */ + for (i = 0; i < *row; i++) { + if (readLine(&data_file[pointer], line, + size - pointer, &n) < 0) { + pr_err("parseProductionTestLimits : ERROR %08X\n", + ERROR_FILE_READ); + ret = ERROR_FILE_READ; + goto END; + } + pointer += n; + line2 = kstrdup(line, GFP_KERNEL); + if (line2 == NULL) { + pr_err("parseProductionTestLimits: kstrdup ERROR %08X\n", + ERROR_ALLOC); + ret = ERROR_ALLOC; + goto END; + } + buf = line2; + token = strsep(&line2, ","); + for (z = 0; (z < *column) && (token != + NULL); + z++) { + sscanf(token, "%d", ((*data) + + j)); + j++; + token = strsep(&line2, ","); + } + kfree(buf); + buf = NULL; + } + if (j == ((*row) * (*column))) { + /* check that all the data are read */ + pr_info("READ DONE!\n"); + ret = OK; + goto END; + } + pr_err("parseProductionTestLimits 3: ERROR %08X\n", + ERROR_FILE_PARSE); + ret = ERROR_FILE_PARSE; + goto END; + } + kfree(buf); + buf = NULL; + } + } + pr_err("parseProductionTestLimits: ERROR %08X\n", + 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 readLine(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; +} |