// SPDX-License-Identifier: GPL-2.0-only
/*
 * FTS Capacitive touch screen controller (FingerTipS)
 *
 * Copyright (C) 2016-2019, STMicroelectronics Limited.
 * Authors: AMG(Analog Mems Group) <marco.cali@st.com>
 *
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 as published by
 * the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License along with
 * this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <linux/device.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/input.h>
#include <linux/input/mt.h>
#include <linux/interrupt.h>
#include <linux/hrtimer.h>
#include <linux/delay.h>
#include <linux/firmware.h>
#include <linux/i2c.h>
#include <linux/i2c-dev.h>
#include <linux/completion.h>
/*#include <linux/wakelock.h>*/
#include <linux/pm_wakeup.h>

#include <linux/gpio.h>
#include <linux/of_gpio.h>
#include <linux/regulator/consumer.h>
#include "fts.h"
#include "fts_lib/ftsCompensation.h"
#include "fts_lib/ftsIO.h"
#include "fts_lib/ftsError.h"
#include "fts_lib/ftsFrame.h"
#include "fts_lib/ftsFlash.h"
#include "fts_lib/ftsTest.h"
#include "fts_lib/ftsTime.h"
#include "fts_lib/ftsTool.h"

#ifdef DRIVER_TEST

#define MAX_PARAMS 50

/*DEFINE COMMANDS TO TEST*/
#define CMD_READ               0x00
#define CMD_WRITE              0x01
#define CMD_READU16            0x02
#define CMD_READB2             0x03
#define CMD_READB2U16          0x04
#define CMD_POLLFOREVENT       0x05
#define CMD_SYSTEMRESET        0x06
#define CMD_CLEANUP            0x07
#define CMD_GETFORCELEN        0x08
#define CMD_GETSENSELEN        0x09
#define CMD_GETMSFRAME         0x0A
/*#define CMD_GETMSKEYFRAME        0x0B*/
#define CMD_GETSSFRAME         0x0C
#define CMD_REQCOMPDATA        0x0D
#define CMD_READCOMPDATAHEAD   0x0E
#define CMD_READMSCOMPDATA     0x0F
#define CMD_READSSCOMPDATA     0x10
#define CMD_READGNCOMPDATA     0x11
#define CMD_GETFWVER           0x12
#define CMD_FLASHSTATUS        0x13
#define CMD_FLASHUNLOCK        0x14
#define CMD_READFWFILE         0x15
#define CMD_FLASHPROCEDURE     0x16
#define CMD_ITOTEST            0x17
#define CMD_INITTEST           0x18
#define CMD_MSRAWTEST          0x19
#define CMD_MSINITDATATEST     0x1A
#define CMD_SSRAWTEST          0x1B
#define CMD_SSINITDATATEST     0x1C
#define CMD_MAINTEST           0x1D
#define CMD_POWERCYCLE         0x1E
#define CMD_FWWRITE            0x1F
#define CMD_READCHIPINFO       0x20
#define CMD_REQFRAME           0x21

static char tag[8] = "[ FTS ]\0";
static u32 functionToTest[MAX_PARAMS];
static int numberParam;

static ssize_t stm_driver_test_store(struct device *dev,
	struct device_attribute *attr, const char *buf, size_t count)
{
	int n;
	char *p = (char *)buf;
	int ret;

	memset(functionToTest, 0, MAX_PARAMS * sizeof(u32));

	for (n = 0; n < (count + 1) / 3 && n < MAX_PARAMS; n++) {
		ret = sscanf(p, "%02X ", &functionToTest[n]);
		if (ret != 1)
			return -EINVAL;
		p += 3;
		logError(1, "%s functionToTest[%d] = %02X\n", tag, n,
			functionToTest[n]);
	}

	numberParam = n;
	logError(1, "%s Number of Parameters = %d\n", tag, numberParam);
	return count;
}

static ssize_t stm_driver_test_show(struct device *dev,
	struct device_attribute *attr, char *buf)
{
	char buff[CMD_STR_LEN] = {0};
	int res = -1, j, count;
	int size = 6 * 2;
	int temp = 0;
	int i;
	int byteToRead = 0;
	u8 *readData = NULL;
	u8 *all_strbuff = NULL;
	u8 *cmd = NULL;

	struct MutualSenseFrame frameMS = {0};
	struct SelfSenseFrame frameSS = {0};

	struct DataHeader dataHead = {0};
	struct MutualSenseData compData = {0};
	struct SelfSenseData comData = {0};
	struct GeneralData gnData = {0};

	u16 address = 0;
	u16 fw_version = 0;
	u16 config_id = 0;

	struct Firmware fw;

	/*struct used for defining which test*/
	/*perform during the  MP test*/

	struct TestToDo todoDefault;

	struct i2c_client *client = to_i2c_client(dev);
	struct fts_ts_info *info = i2c_get_clientdata(client);

	fw.data = NULL;

	todoDefault.MutualRaw = 1;
	todoDefault.MutualRawGap = 1;
	todoDefault.MutualCx1 = 0;
	todoDefault.MutualCx2 = 1;
	todoDefault.MutualCx2Adj = 1;
	todoDefault.MutualCxTotal = 0;
	todoDefault.MutualCxTotalAdj = 0;

	todoDefault.MutualKeyRaw = 0;
	todoDefault.MutualKeyCx1 = 0;
	todoDefault.MutualKeyCx2 = 0;
	todoDefault.MutualKeyCxTotal = 0;

	todoDefault.SelfForceRaw = 1;
	todoDefault.SelfForceRawGap = 0;
	todoDefault.SelfForceIx1 = 0;
	todoDefault.SelfForceIx2 = 0;
	todoDefault.SelfForceIx2Adj = 0;
	todoDefault.SelfForceIxTotal = 1;
	todoDefault.SelfForceIxTotalAdj = 0;
	todoDefault.SelfForceCx1 = 0;
	todoDefault.SelfForceCx2 = 0;
	todoDefault.SelfForceCx2Adj = 0;
	todoDefault.SelfForceCxTotal = 0;
	todoDefault.SelfForceCxTotalAdj = 0;

	todoDefault.SelfSenseRaw = 1;
	todoDefault.SelfSenseRawGap = 0;
	todoDefault.SelfSenseIx1 = 0;
	todoDefault.SelfSenseIx2 = 0;
	todoDefault.SelfSenseIx2Adj = 0;
	todoDefault.SelfSenseIxTotal = 1;
	todoDefault.SelfSenseIxTotalAdj = 0;
	todoDefault.SelfSenseCx1 = 0;
	todoDefault.SelfSenseCx2 = 0;
	todoDefault.SelfSenseCx2Adj = 0;
	todoDefault.SelfSenseCxTotal = 0;
	todoDefault.SelfSenseCxTotalAdj = 0;

	if (numberParam < 1) {
		logError(1, "%s NO COMMAND SPECIFIED!!! ", tag);
		logError(1, "do: 'echo [cmd_code] [args] > stm_fts_cmd' ");
		logError(1, "before looking for result!\n");
		res = ERROR_OP_NOT_ALLOW;
		goto END;
	}

	res = fts_disableInterrupt();
	if (res < 0) {
		logError(0, "%s %s: ERROR %08X\n", tag, __func__, res);
		res = (res | ERROR_DISABLE_INTER);
		goto END;
	}
	switch (functionToTest[0]) {
	case CMD_READ:
		if (numberParam != 4) {
			logError(1, "%s Wrong number of parameters!\n", tag);
			res = ERROR_OP_NOT_ALLOW;
			break;
		}
		/**
		 * need to pass:cmdLength
		 * cmd[0]cmd[1]…cmd[cmdLength-1]
		 * byteToRead
		 */
		temp = (int)functionToTest[1];
		if (numberParam == 4 + (temp - 1) && temp != 0) {
			cmd = (u8 *)kmalloc_array(temp, sizeof(u8), GFP_KERNEL);
			if (!cmd) {
				res = ERROR_OP_NOT_ALLOW;
				break;
			}
			for (i = 0; i < temp; i++)
				cmd[i] = functionToTest[i + 2];
			byteToRead = functionToTest[i + 2];
			readData = (u8 *)kmalloc_array(byteToRead, sizeof(u8),
					GFP_KERNEL);
			if (!readData) {
				kfree(cmd);
				res = ERROR_OP_NOT_ALLOW;
				break;
			}
			res = fts_readCmd(cmd, temp, readData, byteToRead);
			size += (byteToRead * sizeof(u8)) * 2;
			kfree(cmd);
		} else {
			logError(1, "%s Wrong parameters!\n", tag);
			res = ERROR_OP_NOT_ALLOW;
		}
		break;

	case CMD_WRITE:
		if (numberParam != 3)  {
			logError(1, "%s Wrong number of parameters!\n", tag);
			res = ERROR_OP_NOT_ALLOW;
			break;
		}
		/**
		 * need to pass:cmdLength
		 * cmd[0] cmd[1]…cmd[cmdLength-1]
		 */
		temp = (int)functionToTest[1];
		if (numberParam == 3 + (temp - 1) && temp != 0) {
			cmd = (u8 *)kmalloc_array(temp, sizeof(u8), GFP_KERNEL);
			if (!cmd) {
				res = ERROR_OP_NOT_ALLOW;
				break;
			}
			for (i = 0; i < temp; i++)
				cmd[i] = functionToTest[i + 2];
			res = fts_writeCmd(cmd, temp);
			kfree(cmd);
		} else {
			logError(1, "%s Wrong parameters!\n", tag);
			res = ERROR_OP_NOT_ALLOW;
		}
		break;

	case CMD_FWWRITE:
		if (numberParam != 3)  {
			logError(1, "%s Wrong number  parameters!\n", tag);
			res = ERROR_OP_NOT_ALLOW;
			break;
		}
		/**
		 * need to pass:cmdLength
		 * cmd[0] cmd[1]…cmd[cmdLength-1]
		 */
		temp = (int)functionToTest[1];
		if (numberParam == 3 + (temp - 1) && temp != 0) {
			cmd = (u8 *)kmalloc_array(temp, sizeof(u8), GFP_KERNEL);
			if (!cmd) {
				res = ERROR_OP_NOT_ALLOW;
				break;
			}
			for (i = 0; i < temp; i++)
				cmd[i] = functionToTest[i + 2];
			res = fts_writeFwCmd(cmd, temp);
			kfree(cmd);
		} else {
			logError(1, "%s Wrong parameters!\n", tag);
			res = ERROR_OP_NOT_ALLOW;
		}
		break;

	case CMD_READU16:
		if (numberParam != 6) {
			logError(1, "%s Wrong number  parameters!\n", tag);
			res = ERROR_OP_NOT_ALLOW;
			break;
		}
		/**
		 * need to pass: cmd addr[0]  addr[1]
		 * byteToRead hasDummyByte
		 */
		byteToRead = functionToTest[4];
		readData = kmalloc_array(byteToRead,
			sizeof(u8), GFP_KERNEL);
		if (!readData) {
			res = ERROR_OP_NOT_ALLOW;
			break;
		}
		res = readCmdU16((u8)functionToTest[1],
			(u16)((((u8) functionToTest[2]
				& 0x00FF) << 8) + ((u8) functionToTest[3]
				& 0x00FF)),
			readData,
			byteToRead,
			functionToTest[5]);
		size += (byteToRead * sizeof(u8)) * 2;
		break;

	case CMD_READB2:
		if (numberParam != 4) {
			logError(1, "%s Wrong number of parameters!\n", tag);
			res = ERROR_OP_NOT_ALLOW;
			break;
		}
		/*need to pass: addr[0]  addr[1] byteToRead*/
		byteToRead = functionToTest[3];
		readData = kmalloc_array(byteToRead,
				sizeof(u8), GFP_KERNEL);
		if (!readData) {
			res = ERROR_OP_NOT_ALLOW;
			break;
		}
		res = readB2((u16)(
			(((u8)functionToTest[1] & 0x00FF) << 8)
				+ ((u8) functionToTest[2] & 0x00FF)),
			readData,
			byteToRead);
		size += (byteToRead * sizeof(u8)) * 2;
		break;

	case CMD_READB2U16:
		if (numberParam != 4) {
			logError(1, "%s Wrong number of parameters!\n", tag);
			res = ERROR_OP_NOT_ALLOW;
			break;
		}
		/*need to pass: addr[0]  addr[1] byteToRead*/
		byteToRead = functionToTest[3];
		readData = (u8 *)kmalloc_array(byteToRead,
			sizeof(u8), GFP_KERNEL);
		if (!readData) {
			res = ERROR_OP_NOT_ALLOW;
			break;
		}
		res = readB2U16((u16)((((u8)functionToTest[1]
			& 0x00FF) << 8) + ((u8)functionToTest[2]
			& 0x00FF)), readData, byteToRead);
		size += (byteToRead * sizeof(u8)) * 2;
		break;

	case CMD_POLLFOREVENT:
		if (numberParam < 5) {
			logError(1, "%s Wrong number of parameters!\n", tag);
			res = ERROR_OP_NOT_ALLOW;
			break;
		}

		/**
		 * need to pass: eventLength event[0] event[1]
		 * … event[eventLength-1] timeTowait
		 */
		temp = (int)functionToTest[1];
		if (numberParam == 5 + (temp - 1) && temp != 0) {
			readData = (u8 *)kmalloc_array(FIFO_EVENT_SIZE,
					sizeof(u8), GFP_KERNEL);
			if (!readData) {
				res = ERROR_OP_NOT_ALLOW;
				break;
			}
			res = pollForEvent((int *)&functionToTest[2],
				temp,
				readData,
				((functionToTest[temp + 2] & 0x00FF) << 8)
					+ (functionToTest[temp + 3] & 0x00FF));
			//pollForEvent return the number of error found
			if (res >= OK)
				res = OK;
			size += (FIFO_EVENT_SIZE * sizeof(u8)) * 2;
			byteToRead = FIFO_EVENT_SIZE;
		} else {
			logError(1, "%s Wrong parameters!\n", tag);
			res = ERROR_OP_NOT_ALLOW;
		}
		break;

	case CMD_SYSTEMRESET:
		res = fts_system_reset();
		break;

	case CMD_READCHIPINFO:
		if (numberParam != 2) {
			logError(1, "%s Wrong number of parameters!\n", tag);
			res = ERROR_OP_NOT_ALLOW;
			break;
		}
		/*need to pass: doRequest */
		res = readChipInfo(functionToTest[1]);
		break;

	/* TOUCH ENABLE/DISABLE */
	case CMD_CLEANUP:
		if (numberParam != 2) {
			logError(1, "%s Wrong number of parameters!\n", tag);
			res = ERROR_OP_NOT_ALLOW;
			break;
		}
		/* need to pass: enableTouch*/
		res = cleanUp(functionToTest[1]);
		break;

	case CMD_GETFORCELEN:
		/*read number Tx channels */
		temp = getForceLen();
		if (temp < OK)
			res = temp;
		else {
			size += (1 * sizeof(u8)) * 2;
			res = OK;
		}
		break;

	case CMD_GETSENSELEN:
		/* read number Rx channels */
		temp = getSenseLen();
		if (temp < OK)
			res = temp;
		else {
			size += (1 * sizeof(u8)) * 2;
			res = OK;
		}
		break;

	case CMD_REQFRAME:
		/* request a frame */
		if (numberParam != 3) {
			logError(1, "%s Wrong number of parameters!\n", tag);
			res = ERROR_OP_NOT_ALLOW;
			break;
		}
		logError(0, "%s Requesting Frame\n", tag);
		res = requestFrame((u16)((((u8)functionToTest[1] & 0x00FF) << 8)
			+ ((u8)functionToTest[2] & 0x00FF)));

		if (res < OK) {
			logError(0, "%s Err requesting frame ERROR:%02X\n",
				tag, res);
		} else {
			logError(0, "%s Requesting Frame Finished!\n", tag);
		}
		break;

	case CMD_GETMSFRAME:
		if (numberParam != 3) {
			logError(1, "%s Wrong number of param!\n", tag);
			res = ERROR_OP_NOT_ALLOW;
			break;
		}
		logError(0, "%s Get 1 MS Frame\n", tag);
		flushFIFO();
		/**
		 * delete the events related to some
		 * touch (allow to call this function
		 * while touching the sreen without
		 * having a flooding of the FIFO)
		 */
		res = getMSFrame2((u16)((((u8)functionToTest[1] & 0x00FF) << 8)
				+ ((u8)functionToTest[2] & 0x00FF)), &frameMS);
		if (res < 0) {
			logError(0, "%s Err while taking  MS frame:%02X\n",
				tag, res);
		} else {
			logError(0, "%s:frame size is %d words\n", tag, res);
			size = (res * sizeof(short) + 8) * 2;
			/*set res to OK because if getMSFrame is*/
			/*successful res = number of words read*/
			res = OK;
			print_frame_short("MS frame =",
				array1dTo2d_short(frameMS.node_data,
					frameMS.node_data_size,
					frameMS.header.sense_node),
				frameMS.header.force_node,
				frameMS.header.sense_node);
		}
		break;

	/*read self raw*/
	case CMD_GETSSFRAME:
		if (numberParam != 3) {
			logError(1, "%s Wrong number of parameters!\n", tag);
			res = ERROR_OP_NOT_ALLOW;
			break;
		}

		logError(0, "%s Get 1 SS Frame\n", tag);
		flushFIFO();
		/**
		 * delete the events related to some
		 * touch (allow to call this function
		 * while touching the sreen without
		 * having a flooding of the FIFO)
		 */
		res = getSSFrame2((u16)((((u8)functionToTest[1] & 0x00FF) << 8)
			+ ((u8)functionToTest[2] & 0x00FF)), &frameSS);

		if (res < OK) {
			logError(0,
			  "%s Error while taking the SS frame... ERROR %02X\n",
			  tag, res);
		} else {
			logError(0, "%s The frame size is %d words\n",
				tag, res);
			size = (res * sizeof(short) + 8) * 2 + 1;

			/*set res to OK because if getMSFrame is*/
			/*successful res = number of words read*/
			res = OK;
			print_frame_short("SS force frame =",
				array1dTo2d_short(frameSS.force_data,
					frameSS.header.force_node, 1),
				frameSS.header.force_node,
				1);
			print_frame_short("SS sense frame =",
				array1dTo2d_short(frameSS.sense_data,
					frameSS.header.sense_node,
					frameSS.header.sense_node),
				1,
				frameSS.header.sense_node);
		}
		break;

	case CMD_REQCOMPDATA:
		/*request comp data*/
		if (numberParam != 3) {
			logError(1, "%s Wrong number of parameters!\n", tag);
			res = ERROR_OP_NOT_ALLOW;
			break;
		}

		logError(0, "%s Requesting Compensation Data\n", tag);
		res = requestCompensationData((u16)
			((((u8)functionToTest[1] & 0x00FF) << 8)
			+ ((u8)functionToTest[2] & 0x00FF)));

		if (res < OK) {
			logError(0,
			  "%s Error requesting compensation data ERROR %02X\n",
			  tag, res);
		} else {
			logError(0,
				"%s Requesting Compensation Data Finished!\n",
				tag);
		}
		break;

	case CMD_READCOMPDATAHEAD:
		/*read comp data header*/
		if (numberParam != 3) {
			logError(1, "%s Wrong number of parameters!\n", tag);
			res = ERROR_OP_NOT_ALLOW;
			break;
		}

		logError(0, "%s Requesting Compensation Data\n", tag);
		res = requestCompensationData(
			(u16) ((((u8)functionToTest[1] & 0x00FF) << 8)
				+ ((u8)functionToTest[2] & 0x00FF)));
		if (res < OK) {
			logError(0, "%s Error requesting:%02X\n", tag, res);
		} else {
			logError(0,
			  "%s Requesting Compensation Data Finished!\n", tag);
			res = readCompensationDataHeader(
				(u16)((((u8)functionToTest[1] & 0x00FF) << 8)
					+((u8)functionToTest[2] & 0x00FF)),
				&dataHead,
				&address);
			if (res < OK) {
				logError(0, "%s Read Header ERROR:%02X\n",
					tag, res);
			} else {
				logError(0, "%s Read Header OK!\n", tag);
				size += (2 * sizeof(u8)) * 2;
			}
		}
		break;
	case CMD_READMSCOMPDATA:
		if (numberParam != 3) {
			logError(1, "%s Wrong number of parameters!\n", tag);
			res = ERROR_OP_NOT_ALLOW;
			break;
		}
		/*read mutual comp data */
		logError(0, "%s Get MS Compensation Data\n", tag);
		res = readMutualSenseCompensationData(
			(u16)((((u8)functionToTest[1] & 0x00FF) << 8)
				+ ((u8)functionToTest[2] & 0x00FF)),
			&compData);

		if (res < OK) {
			logError(0, "%s Error reading MS compe data:%02X\n",
				tag, res);
		} else {
			logError(0, "%s MS Compensa Reading Finished!\n",
				tag);

			size = ((compData.node_data_size + 9) * sizeof(u8)) * 2;
			print_frame_u8("MS Data (Cx2) = ",
				array1dTo2d_u8(compData.node_data,
					compData.node_data_size,
					compData.header.sense_node),
				compData.header.force_node,
				compData.header.sense_node);
		}
		break;
	case CMD_READSSCOMPDATA:
		if (numberParam != 3) {
			logError(1, "%sWrong number of parameters!\n", tag);
			res = ERROR_OP_NOT_ALLOW;
			break;
		}

		/*read self comp data*/
		logError(0, "%s Get SS Compensation Data...\n", tag);
		res = readSelfSenseCompensationData((u16)
			((((u8)functionToTest[1] & 0x00FF) << 8)
				+ ((u8)functionToTest[2] & 0x00FF)),
			&comData);
		if (res < OK) {
			logError(0, "%s Error reading SS Compensa data %02X\n",
				tag, res);
		} else {
			logError(0, "%s SS Compensa Reading Finished!\n", tag);
			size = comData.header.force_node
				+ comData.header.sense_node;
			size = (size * 2 + 12) * sizeof(u8) * 2;
			print_frame_u8("SS Data Ix2_fm = ",
				array1dTo2d_u8(comData.ix2_fm,
					comData.header.force_node,
					comData.header.force_node),
				1,
				comData.header.force_node);
			print_frame_u8("SS Data Cx2_fm = ",
				array1dTo2d_u8(comData.cx2_fm,
					comData.header.force_node,
					comData.header.force_node),
				1,
				comData.header.force_node);
			print_frame_u8("SS Data Ix2_sn = ",
				array1dTo2d_u8(comData.ix2_sn,
					comData.header.sense_node,
					comData.header.sense_node),
				1,
				comData.header.sense_node);
			print_frame_u8("SS Data Cx2_sn = ",
				array1dTo2d_u8(comData.cx2_sn,
					comData.header.sense_node,
					comData.header.sense_node),
				1,
				comData.header.sense_node);
		}
		break;

	case CMD_READGNCOMPDATA:
		if (numberParam != 3) {
			logError(1, "%s Wrong number of parameters!\n", tag);
			res = ERROR_OP_NOT_ALLOW;
			break;
		}
		/*read self comp data */
		logError(0, "%s Get General Compensation Data...\n", tag);
		res = readGeneralCompensationData((u16)
			((((u8)functionToTest[1]
			& 0x00FF) << 8) + ((u8)functionToTest[2]
			& 0x00FF)), &gnData);
		if (res < OK) {
			logError(0,
				"%s Reading General compensa data ERROR %02X\n",
				tag, res);
		} else {
			logError(0, "%s:General compensa Reading Finished!\n",
				tag);
			size = (14) * sizeof(u8) * 2;
		}
		break;
	case CMD_GETFWVER:
		res = getFirmwareVersion(&fw_version, &config_id);
		if (res < OK) {
			logError(1, "%s Reading firmware version ERROR %02X\n",
				tag, res);
		} else {
			logError(0, "%s getFirmware Version Finished!\n", tag);
			size += (4) * sizeof(u8) * 2;
		}
		break;
#ifdef FTM3_CHIP
	case CMD_FLASHSTATUS:
		res = flash_status();
		/*return 0 = flash ready, 1 = flash busy, <0 error*/
		if (res < OK) {
			logError(1, "%s Reading flash status ERROR %02X\n",
				tag, res);
		} else {
			logError(0, "%s Flash Status: %d\n", tag, res);
			size += (1 * sizeof(u8)) * 2;
			/*need to store the value for further display */
			temp = res;

			/*set res =ok for returning code*/
			res = OK;
		}
		break;
#endif
	case CMD_FLASHUNLOCK:
		res = flash_unlock();
		if (res < OK) {
			logError(1, "%s:Impossible Unlock Flash ERROR %02X\n",
				tag, res);
		} else {
			logError(0, "%s Flash Unlock OK!\n", tag);
		}
		break;
	case CMD_READFWFILE:
		if (numberParam != 2) {
			logError(1, "%s Wrong number of parameters!\n", tag);
			res = ERROR_OP_NOT_ALLOW;
			break;
		}
		/*read fw file */
		logError(0, "%s Reading FW File...\n", tag);
		res = readFwFile(PATH_FILE_FW, &fw, functionToTest[1]);
		if (res < OK) {
			logError(0, "%s Error reading FW File:%02X\n",
				tag, res);
		} else {
			logError(0, "%s Read FW File Finished!\n", tag);
		}
		kfree(fw.data);
		break;
	case CMD_FLASHPROCEDURE:
		if (numberParam != 3) {
			logError(1, "%s Wrong number of parameters!\n", tag);
			res = ERROR_OP_NOT_ALLOW;
			break;
		}
		/*flashing procedure*/
		logError(0, "%s Starting Flashing Procedure\n", tag);
		res = flashProcedure(PATH_FILE_FW,
				functionToTest[1], functionToTest[2]);
		if (res < OK) {
			logError(0, "%s During flash procedure ERROR %02X",
				tag, res);
		} else {
			logError(0, "%s Flash Procedure Finished!\n", tag);
		}
		break;

	/*ITO TEST*/
	case CMD_ITOTEST:
		res = production_test_ito();
		break;

	/*Initialization*/
	case CMD_INITTEST:
		if (numberParam != 2) {
			logError(1, "%s Wrong number of parameters!\n", tag);
			res = ERROR_OP_NOT_ALLOW;
			break;
		}
		/*need to specify if if save value on Flash*/
		if (functionToTest[1] == 0x01)
			res = production_test_initialization();
		else
			res = production_test_split_initialization(false);
		break;

	case CMD_MSRAWTEST:
		if (numberParam != 2) {
			logError(1, "%s Wrong number of parameters!\n", tag);
			res = ERROR_OP_NOT_ALLOW;
			break;
		}
		/* MS Raw DATA TEST*/
		/* need to specify if stopOnFail */
		res = production_test_ms_raw(LIMITS_FILE, functionToTest[1],
			&todoDefault);
		break;

	case CMD_MSINITDATATEST:
		/*MS CX DATA TEST*/
		if (numberParam != 2) {
			logError(1, "%s Wrong number of parameters!\n", tag);
			res = ERROR_OP_NOT_ALLOW;
			break;
		}
		/*need to specify if stopOnFail*/
		res = production_test_ms_cx(LIMITS_FILE, functionToTest[1],
			&todoDefault);
		break;

	case CMD_SSRAWTEST:
		/*SS RAW DATA TEST*/
		if (numberParam != 2) {
			logError(1, "%s Wrong number of parameters!\n", tag);
			res = ERROR_OP_NOT_ALLOW;
			break;
		}
		/*need to specify if stopOnFail*/
		res = production_test_ss_raw(LIMITS_FILE, functionToTest[1],
			&todoDefault);
		break;

	case CMD_SSINITDATATEST:
		/*SS IX CX DATA TEST*/
		if (numberParam != 2) {
			logError(1, "%s Wrong number of parameters!\n", tag);
			res = ERROR_OP_NOT_ALLOW;
			break;
		}
		/*need to specify if stopOnFail*/
		res = production_test_ss_ix_cx(LIMITS_FILE, functionToTest[1],
			&todoDefault);
		break;

	case CMD_MAINTEST:
		/*PRODUCTION TEST*/
		if (numberParam != 3) {
			logError(1, "%s Wrong number of parameters!\n", tag);
			res = ERROR_OP_NOT_ALLOW;
			break;
		}
		/*need to specify if stopOnFail and saveInit*/
		res = production_test_main(LIMITS_FILE, functionToTest[1],
			functionToTest[2], &todoDefault, INIT_FIELD);
		break;

	case CMD_POWERCYCLE:
		res = fts_chip_powercycle(info);
		break;

	default:
		logError(1, "%s COMMAND ID NOT VALID!!\n", tag);
		logError(1, "%s Inset a value between 00 and 1E.\n", tag);
		res = ERROR_OP_NOT_ALLOW;
		break;
	}

END:
	/**
	 * here start the reporting phase,
	 * assembling the data to send in the file node
	 */
	all_strbuff = kmalloc(size, GFP_KERNEL);
	memset(all_strbuff, 0, size);

	snprintf(buff, sizeof(buff), "%02X", 0xAA);
	strlcat(all_strbuff, buff, size);

	snprintf(buff, sizeof(buff), "%08X", res);
	strlcat(all_strbuff, buff, size);

	if (res >= OK) {
		/*all the other cases are already*/
		/*fine printing only the res.*/
		switch (functionToTest[0]) {
		case CMD_READ:
		case CMD_READU16:
		case CMD_READB2:
		case CMD_READB2U16:
		case CMD_POLLFOREVENT:
			for (j = 0; j < byteToRead; j++) {
				snprintf(buff, sizeof(buff), "%02X",
					readData[j]);
				strlcat(all_strbuff, buff, size);
			}
			break;

		case CMD_GETFORCELEN:
		case CMD_GETSENSELEN:
		case CMD_FLASHSTATUS:
			snprintf(buff, sizeof(buff), "%02X", (u8)temp);
			strlcat(all_strbuff, buff, size);
			break;

		case CMD_GETMSFRAME:
			snprintf(buff, sizeof(buff), "%02X",
				(u8) frameMS.header.force_node);
			strlcat(all_strbuff, buff, size);

			snprintf(buff, sizeof(buff), "%02X",
				(u8)frameMS.header.sense_node);
			strlcat(all_strbuff, buff, size);

			for (j = 0; j < frameMS.node_data_size; j++) {
				snprintf(buff, sizeof(buff), "%04X",
					frameMS.node_data[j]);
				strlcat(all_strbuff, buff, size);
			}
			kfree(frameMS.node_data);
			break;

		case CMD_GETSSFRAME:
			snprintf(buff, sizeof(buff), "%02X",
				(u8) frameSS.header.force_node);
			strlcat(all_strbuff, buff, size);

			snprintf(buff, sizeof(buff), "%02X",
				(u8)frameSS.header.sense_node);
			strlcat(all_strbuff, buff, size);

			/* Copying self raw data Force */
			for (j = 0; j < frameSS.header.force_node; j++) {
				snprintf(buff, sizeof(buff), "%04X",
					frameSS.force_data[j]);
				strlcat(all_strbuff, buff, size);
			}


			/* Copying self raw data Sense */
			for (j = 0; j < frameSS.header.sense_node; j++) {
				snprintf(buff, sizeof(buff), "%04X",
					frameSS.sense_data[j]);
				strlcat(all_strbuff, buff, size);
			}
			kfree(frameSS.force_data);
			kfree(frameSS.sense_data);
			break;

		case CMD_READMSCOMPDATA:
			snprintf(buff, sizeof(buff), "%02X",
				(u8)compData.header.force_node);
			strlcat(all_strbuff, buff, size);

			snprintf(buff, sizeof(buff), "%02X",
				(u8)compData.header.sense_node);
			strlcat(all_strbuff, buff, size);

			/* Cpying CX1 value */
			snprintf(buff, sizeof(buff), "%02X",
				compData.cx1);
			strlcat(all_strbuff, buff, size);

			/* Copying CX2 values */
			for (j = 0; j < compData.node_data_size; j++) {
				snprintf(buff, sizeof(buff), "%02X",
					*(compData.node_data + j));
				strlcat(all_strbuff, buff, size);
			}
			kfree(compData.node_data);
			break;

		case CMD_READSSCOMPDATA:
			snprintf(buff, sizeof(buff), "%02X",
				comData.header.force_node);
			strlcat(all_strbuff, buff, size);

			snprintf(buff, sizeof(buff), "%02X",
				comData.header.sense_node);
			strlcat(all_strbuff, buff, size);

			snprintf(buff, sizeof(buff), "%02X", comData.f_ix1);
			strlcat(all_strbuff, buff, size);

			snprintf(buff, sizeof(buff), "%02X", comData.s_ix1);
			strlcat(all_strbuff, buff, size);

			snprintf(buff, sizeof(buff), "%02X", comData.f_cx1);
			strlcat(all_strbuff, buff, size);

			snprintf(buff, sizeof(buff), "%02X", comData.s_cx1);
			strlcat(all_strbuff, buff, size);

			/* Copying IX2 Force */
			for (j = 0; j < comData.header.force_node; j++) {
				snprintf(buff, sizeof(buff), "%02X",
					comData.ix2_fm[j]);
				strlcat(all_strbuff, buff, size);
			}
			/* Copying IX2 Sense*/
			for (j = 0; j < comData.header.sense_node; j++) {
				snprintf(buff, sizeof(buff), "%02X",
					comData.ix2_sn[j]);
				strlcat(all_strbuff, buff, size);
			}
			/* Copying CX2 Force */
			for (j = 0; j < comData.header.force_node; j++) {
				snprintf(buff, sizeof(buff), "%02X",
					comData.cx2_fm[j]);
				strlcat(all_strbuff, buff, size);
			}

			/* Copying CX2 Sense */
			for (j = 0; j < comData.header.sense_node; j++) {
				snprintf(buff, sizeof(buff), "%02X",
					comData.cx2_sn[j]);
				strlcat(all_strbuff, buff, size);
			}

			kfree(comData.ix2_fm);
			kfree(comData.ix2_sn);
			kfree(comData.cx2_fm);
			kfree(comData.cx2_sn);
			break;

		case CMD_READGNCOMPDATA:
			snprintf(buff, sizeof(buff), "%02X",
				gnData.header.force_node);
			strlcat(all_strbuff, buff, size);

			snprintf(buff, sizeof(buff), "%02X",
				gnData.header.sense_node);
			strlcat(all_strbuff, buff, size);

			snprintf(buff, sizeof(buff), "%02X",
				gnData.ftsd_lp_timer_cal0);
			strlcat(all_strbuff, buff, size);

			snprintf(buff, sizeof(buff), "%02X",
				gnData.ftsd_lp_timer_cal1);
			strlcat(all_strbuff, buff, size);

			snprintf(buff, sizeof(buff), "%02X",
				gnData.ftsd_lp_timer_cal2);
			strlcat(all_strbuff, buff, size);

			snprintf(buff, sizeof(buff), "%02X",
				gnData.ftsd_lp_timer_cal3);
			strlcat(all_strbuff, buff, size);

			snprintf(buff, sizeof(buff), "%02X",
				gnData.ftsa_lp_timer_cal0);
			strlcat(all_strbuff, buff, size);

			snprintf(buff, sizeof(buff), "%02X",
				gnData.ftsa_lp_timer_cal1);
			strlcat(all_strbuff, buff, size);
			break;

		case CMD_GETFWVER:
			snprintf(buff, sizeof(buff), "%04X", fw_version);
			strlcat(all_strbuff, buff, size);

			snprintf(buff, sizeof(buff), "%04X", config_id);
			strlcat(all_strbuff, buff, size);
			break;

		case CMD_READCOMPDATAHEAD:
			snprintf(buff, sizeof(buff), "%02X",
				dataHead.force_node);
			strlcat(all_strbuff, buff, size);

			snprintf(buff, sizeof(buff), "%02X",
				dataHead.sense_node);
			strlcat(all_strbuff, buff, size);
			break;

		default:
			break;
		}
	}

	snprintf(buff, sizeof(buff), "%02X", 0xBB);
	strlcat(all_strbuff, buff, size);

	count = snprintf(buf, TSP_BUF_SIZE, "%s\n", all_strbuff);
	numberParam = 0;
	/**
	 * need to reset the number of parameters
	 * in order to wait the next command,
	 * comment if you want to repeat
	 * the last command sent just doing a cat
	 */

	kfree(readData);
	kfree(all_strbuff);
	return count;
}

static DEVICE_ATTR_RW(stm_driver_test);

static struct attribute *test_cmd_attributes[] = {
	&dev_attr_stm_driver_test.attr,
	NULL,
};

struct attribute_group test_cmd_attr_group = {
	.attrs = test_cmd_attributes,
};
#endif