summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYahui Wang <yahuiw@codeaurora.org>2017-01-11 23:31:30 +0800
committerJin Fu <jinf@codeaurora.org>2017-02-14 13:33:47 +0800
commited29ea5a01b98c10239a29004df5dd14cd636293 (patch)
tree15da749cb670712a9caef9ede20b9c63039f7b6a
parentf31227c2a21f83c4a4b13841515906d7de4c9c2c (diff)
input: touchpanel: Add ST Touchscreen version 4.1.0 driver
This is the reference driver source code for ST Touchscreen of version 4.1.0. It is used for QVR8998 touchscreen. (cherry picked from commit 2cd09314337d614e69d0ebd99afb71d99d31b69a) Signed-off-by: chenx <chenxiang0527@thundersoft.com> Git-commit: 2cd09314337d614e69d0ebd99afb71d99d31b69a Git-repo: https://source.codeaurora.org/quic/la/kernel/msm-3.10 CRs-Fixed: 1106217 Change-Id: I6674245402c0a5d6cca6bf82a9f8b1bf4f4f4ef3 Signed-off-by: Jin Fu <jinf@codeaurora.org>
-rw-r--r--Documentation/devicetree/bindings/input/touchscreen/STMicroelectronics.txt54
-rw-r--r--drivers/input/touchscreen/Kconfig11
-rw-r--r--drivers/input/touchscreen/Makefile1
-rw-r--r--drivers/input/touchscreen/st/Kconfig9
-rw-r--r--drivers/input/touchscreen/st/Makefile5
-rw-r--r--drivers/input/touchscreen/st/fts.c2354
-rw-r--r--drivers/input/touchscreen/st/fts.h249
-rw-r--r--drivers/input/touchscreen/st/fts_driver_test.c871
-rw-r--r--drivers/input/touchscreen/st/fts_fw.h10
-rw-r--r--drivers/input/touchscreen/st/fts_gui.c359
-rw-r--r--drivers/input/touchscreen/st/fts_lib/Makefile7
-rw-r--r--drivers/input/touchscreen/st/fts_lib/ftsCompensation.c591
-rw-r--r--drivers/input/touchscreen/st/fts_lib/ftsCompensation.h146
-rw-r--r--drivers/input/touchscreen/st/fts_lib/ftsCrossCompile.c43
-rw-r--r--drivers/input/touchscreen/st/fts_lib/ftsCrossCompile.h34
-rw-r--r--drivers/input/touchscreen/st/fts_lib/ftsError.c105
-rw-r--r--drivers/input/touchscreen/st/fts_lib/ftsError.h75
-rw-r--r--drivers/input/touchscreen/st/fts_lib/ftsFlash.c1071
-rw-r--r--drivers/input/touchscreen/st/fts_lib/ftsFlash.h79
-rw-r--r--drivers/input/touchscreen/st/fts_lib/ftsFrame.c569
-rw-r--r--drivers/input/touchscreen/st/fts_lib/ftsFrame.h49
-rw-r--r--drivers/input/touchscreen/st/fts_lib/ftsGesture.c393
-rw-r--r--drivers/input/touchscreen/st/fts_lib/ftsGesture.h74
-rw-r--r--drivers/input/touchscreen/st/fts_lib/ftsHardware.h177
-rw-r--r--drivers/input/touchscreen/st/fts_lib/ftsIO.c403
-rw-r--r--drivers/input/touchscreen/st/fts_lib/ftsIO.h35
-rw-r--r--drivers/input/touchscreen/st/fts_lib/ftsSoftware.h131
-rw-r--r--drivers/input/touchscreen/st/fts_lib/ftsTest.c2324
-rw-r--r--drivers/input/touchscreen/st/fts_lib/ftsTest.h158
-rw-r--r--drivers/input/touchscreen/st/fts_lib/ftsTime.c84
-rw-r--r--drivers/input/touchscreen/st/fts_lib/ftsTime.h29
-rw-r--r--drivers/input/touchscreen/st/fts_lib/ftsTool.c706
-rw-r--r--drivers/input/touchscreen/st/fts_lib/ftsTool.h64
-rw-r--r--drivers/input/touchscreen/st/fts_limits.h10
34 files changed, 11280 insertions, 0 deletions
diff --git a/Documentation/devicetree/bindings/input/touchscreen/STMicroelectronics.txt b/Documentation/devicetree/bindings/input/touchscreen/STMicroelectronics.txt
new file mode 100644
index 000000000000..7799392700a7
--- /dev/null
+++ b/Documentation/devicetree/bindings/input/touchscreen/STMicroelectronics.txt
@@ -0,0 +1,54 @@
+STMicroelectronics touch controller
+
+The STMicroelectronics controller is connected to host processor
+via i2c. The controller generates interrupts when the
+user touches the panel. The host controller is expected
+to read the touch coordinates over i2c and pass the coordinates
+to the rest of the system.
+
+Required properties:
+
+ - compatible : should be "st,fts".
+ - reg : i2c slave address of the device.
+ - interrupt-parent : parent of interrupt.
+ - interrupts : touch sample interrupt to indicate presense or release
+ of fingers on the panel.
+ - vdd-supply : Power supply needed to power up the device.
+ - vcc-supply : Power source required to power up i2c bus.
+ - st,irq-gpio : irq gpio which is to provide interrupts to host,
+ same as "interrupts" node. It will also
+ contain active low or active high information.
+ - st,reset-gpio : reset gpio to control the reset of chip.
+ - pinctrl-names : This should be defined if a target uses pinctrl framework.
+ See "pinctrl" in Documentation/devicetree/bindings/pinctrl/msm-pinctrl.txt.
+ Specify the names of the configs that pinctrl can install in driver.
+ Following are the pinctrl configs that can be installed:
+ "pmx_ts_active" : Active configuration of pins, this should specify active
+ config defined in pin groups of interrupt and reset gpio.
+ "pmx_ts_suspend" : Disabled configuration of pins, this should specify sleep
+ config defined in pin groups of interrupt and reset gpio.
+ "pmx_ts_release" : Release configuration of pins, this should specify
+ release config defined in pin groups of interrupt and reset gpio.
+ - st,regulator_avdd : name of Power supply needed to power up the device.
+ - st,regulator_dvdd : name of Power source required to power up i2c bus.
+Optional properties:
+
+
+Example:
+ i2c@78b9000 { /* BLSP1 QUP5 */
+ st_fts@49 {
+ compatible = "st,fts";
+ reg = <0x49>;
+ interrupt-parent = <&msm_gpio>;
+ interrupts = <13 0x2008>;
+ vdd-supply = <&pm8916_l17>;
+ vcc-supply = <&pm8916_l6>;
+ pinctrl-names = "pmx_ts_active","pmx_ts_suspend";
+ pinctrl-0 = <&ts_int_active &ts_reset_active>;
+ pinctrl-1 = <&ts_int_suspend &ts_reset_suspend>;
+ st,irq-gpio = <&msm_gpio 13 0x00000001>;
+ st,reset-gpio = <&msm_gpio 12 0x0>;
+ st,regulator_dvdd = "vdd";
+ st,regulator_avdd = "avdd";
+ };
+ };
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index 49df5e0afbfb..f13017cd9d46 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -1228,4 +1228,15 @@ config TOUCHSCREEN_GT9XX
If unsure, say N.
source "drivers/input/touchscreen/gt9xx/Kconfig"
+
+config TOUCHSCREEN_ST
+ bool "STMicroelectronics Touchscreen Driver"
+ depends on I2C
+ help
+ Say Y here if you have a STMicroelectronics Touchscreen.
+
+ If unsure, say N.
+
+source "drivers/input/touchscreen/st/Kconfig"
+
endif
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
index 06953a69123f..7606fe53fcff 100644
--- a/drivers/input/touchscreen/Makefile
+++ b/drivers/input/touchscreen/Makefile
@@ -100,3 +100,4 @@ obj-$(CONFIG_TOUCHSCREEN_COLIBRI_VF50) += colibri-vf50-ts.o
obj-$(CONFIG_TOUCHSCREEN_ROHM_BU21023) += rohm_bu21023.o
obj-$(CONFIG_TOUCHSCREEN_MSTAR21XX) += msg21xx_ts.o
obj-$(CONFIG_TOUCHSCREEN_GT9XX) += gt9xx/
+obj-$(CONFIG_TOUCHSCREEN_ST) += st/
diff --git a/drivers/input/touchscreen/st/Kconfig b/drivers/input/touchscreen/st/Kconfig
new file mode 100644
index 000000000000..817faea01742
--- /dev/null
+++ b/drivers/input/touchscreen/st/Kconfig
@@ -0,0 +1,9 @@
+#
+# STMicroelectronics touchscreen driver configuration
+#
+
+config TOUCHSCREEN_ST_I2C
+ tristate "STMicroelectronics i2c touchscreen"
+ depends on TOUCHSCREEN_ST
+ help
+ This enables support for ST touch panel over I2C based touchscreens.
diff --git a/drivers/input/touchscreen/st/Makefile b/drivers/input/touchscreen/st/Makefile
new file mode 100644
index 000000000000..0aa7b4a364da
--- /dev/null
+++ b/drivers/input/touchscreen/st/Makefile
@@ -0,0 +1,5 @@
+#
+## Makefile for the STMicroelectronics touchscreen driver.
+#
+
+obj-$(CONFIG_TOUCHSCREEN_ST_I2C) += fts.o fts_gui.o fts_driver_test.o fts_lib/
diff --git a/drivers/input/touchscreen/st/fts.c b/drivers/input/touchscreen/st/fts.c
new file mode 100644
index 000000000000..bbe872001407
--- /dev/null
+++ b/drivers/input/touchscreen/st/fts.c
@@ -0,0 +1,2354 @@
+/*
+ * fts.c
+ *
+ * FTS Capacitive touch screen controller (FingerTipS)
+ *
+ * Copyright (C) 2016, 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.
+ */
+
+#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/gpio.h>
+#include <linux/of_gpio.h>
+#include <linux/regulator/consumer.h>
+
+#include <linux/notifier.h>
+#include <linux/fb.h>
+
+#ifdef KERNEL_ABOVE_2_6_38
+#include <linux/input/mt.h>
+#endif
+
+#include "fts.h"
+#include "fts_lib/ftsCompensation.h"
+#include "fts_lib/ftsIO.h"
+#include "fts_lib/ftsError.h"
+#include "fts_lib/ftsFlash.h"
+#include "fts_lib/ftsFrame.h"
+#include "fts_lib/ftsGesture.h"
+#include "fts_lib/ftsTest.h"
+#include "fts_lib/ftsTime.h"
+#include "fts_lib/ftsTool.h"
+
+#define LINK_KOBJ_NAME "tp"
+
+/*
+ * Uncomment to use polling mode instead of interrupt mode.
+ *
+ */
+/* #define FTS_USE_POLLING_MODE */
+
+/*
+ * Event installer helpers
+ */
+#define event_id(_e) EVENTID_##_e
+#define handler_name(_h) fts_##_h##_event_handler
+
+#define install_handler(_i, _evt, _hnd) \
+do { \
+ _i->event_dispatch_table[event_id(_evt)] = handler_name(_hnd); \
+} while (0)
+
+/*
+ * Asyncronouns command helper
+ */
+#define WAIT_WITH_TIMEOUT(_info, _timeout, _command) \
+do { \
+ if (wait_for_completion_timeout(&_info->cmd_done, _timeout) == 0) { \
+ dev_warn(_info->dev, "Waiting for %s command: timeout\n", \
+ #_command); \
+ } \
+} while (0)
+
+#ifdef KERNEL_ABOVE_2_6_38
+#define TYPE_B_PROTOCOL
+#endif
+
+#if defined(SCRIPTLESS) || defined(DRIVER_TEST)
+static struct class *fts_cmd_class;
+#endif
+
+extern chipInfo ftsInfo;
+
+unsigned char tune_version_same;
+
+char tag[8] = "[ FTS ]\0";
+
+static u32 *typeOfComand;
+static int numberParameters;
+static int feature_feasibility = ERROR_OP_NOT_ALLOW;
+#ifdef PHONE_GESTURE
+static u8 mask[GESTURE_MASK_SIZE+2];
+#endif
+static void fts_interrupt_enable(struct fts_ts_info *info);
+static int fts_init_hw(struct fts_ts_info *info);
+static int fts_mode_handler(struct fts_ts_info *info, int force);
+static int fts_command(struct fts_ts_info *info, unsigned char cmd);
+
+static int fts_chip_initialization(struct fts_ts_info *info);
+
+void touch_callback(unsigned int status)
+{
+ /* Empty */
+}
+
+unsigned int le_to_uint(const unsigned char *ptr)
+{
+ return (unsigned int) ptr[0] + (unsigned int) ptr[1] * 0x100;
+}
+
+unsigned int be_to_uint(const unsigned char *ptr)
+{
+ return (unsigned int) ptr[1] + (unsigned int) ptr[0] * 0x100;
+}
+
+/* force update firmware*/
+static ssize_t fts_fw_control_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count){
+ int ret, mode;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct fts_ts_info *info = i2c_get_clientdata(client);
+
+ /* reading out firmware upgrade mode */
+ sscanf(buf, "%d", &mode);
+#ifdef FTM3_CHIP
+ ret = flashProcedure(PATH_FILE_FW, mode, !mode);
+#else
+ ret = flashProcedure(PATH_FILE_FW, mode, 1);
+#endif
+ info->fwupdate_stat = ret;
+
+ if (ret < OK)
+ logError(1, "%s %s :Unable to upgrade firmware\n", tag, __func__);
+ return count;
+}
+
+static ssize_t fts_sysfs_config_id_show(struct device *dev, struct device_attribute *attr,
+ char *buf) {
+ int error;
+
+ error = snprintf(buf, TSP_BUF_SIZE, "%x.%x\n", ftsInfo.u16_fwVer, ftsInfo.u16_cfgId);
+ return error;
+}
+
+static ssize_t fts_sysfs_fwupdate_show(struct device *dev, struct device_attribute *attr,
+ char *buf) {
+ struct i2c_client *client = to_i2c_client(dev);
+ struct fts_ts_info *info = i2c_get_clientdata(client);
+
+ /* fwupdate_stat: ERROR code Returned by flashProcedure. */
+ return snprintf(buf, TSP_BUF_SIZE, "%08X\n", info->fwupdate_stat);
+}
+
+static ssize_t fts_fw_test_show(struct device *dev, struct device_attribute *attr,
+ char *buf) {
+
+ Firmware fw;
+ int ret;
+
+ fw.data = NULL;
+ ret = readFwFile(PATH_FILE_FW, &fw, 0);
+
+ if (ret < OK) {
+ logError(1, "%s: Error during reading FW file! ERROR %08X\n", tag, ret);
+ } else
+ logError(1, "%s: fw_version = %04X, config_version = %04X, size = %d bytes\n",
+ tag, fw.fw_ver, fw.config_id, fw.data_size);
+
+ kfree(fw.data);
+ return 0;
+}
+
+/* TODO: edit this function according to the features policy to allow during the screen on/off */
+int check_feature_feasibility(struct fts_ts_info *info, unsigned int feature)
+{
+ int res = ERROR_OP_NOT_ALLOW;
+
+ if (info->resume_bit == 0) {
+ switch (feature) {
+#ifdef PHONE_GESTURE
+ case FEAT_GESTURE:
+ res = OK;
+ break;
+#endif
+ default:
+ logError(1, "%s %s: Feature not allowed in this operating mode! ERROR %08X\n", tag, __func__, res);
+ break;
+
+ }
+ } else{
+ switch (feature) {
+#ifdef PHONE_GESTURE
+ case FEAT_GESTURE:
+#endif
+ case FEAT_GLOVE:
+ /* glove mode can only activate during sense on */
+ res = OK;
+ break;
+
+ default:
+ logError(1, "%s %s: Feature not allowed in this operating mode! ERROR %08X\n", tag, __func__, res);
+ break;
+
+ }
+ }
+
+ return res;
+
+}
+
+static ssize_t fts_feature_enable_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count) {
+ struct i2c_client *client = to_i2c_client(dev);
+ struct fts_ts_info *info = i2c_get_clientdata(client);
+ char *p = (char *)buf;
+ unsigned int temp;
+ int res = OK;
+
+ if ((count + 1) / 3 != 2) {
+ logError(1, "%s fts_feature_enable: Number of parameter wrong! %d > %d\n",
+ tag, (count + 1) / 3, 2);
+ } else{
+ sscanf(p, "%02X ", &temp);
+ p += 3;
+ res = check_feature_feasibility(info, temp);
+ if (res >= OK) {
+ switch (temp) {
+#ifdef PHONE_GESTURE
+ case FEAT_GESTURE:
+ sscanf(p, "%02X ", &info->gesture_enabled);
+ logError(1, "%s fts_feature_enable: Gesture Enabled = %d\n", tag,
+ info->gesture_enabled);
+ break;
+#endif
+ case FEAT_GLOVE:
+ sscanf(p, "%02X ", &info->glove_enabled);
+ logError(1, "%s fts_feature_enable: Glove Enabled = %d\n",
+ tag, info->glove_enabled);
+
+ break;
+
+ default:
+ logError(1, "%s fts_feature_enable: Feature %02X not valid! ERROR %08X\n", tag, temp, ERROR_OP_NOT_ALLOW);
+
+ }
+ feature_feasibility = res;
+ }
+
+ }
+ return count;
+}
+
+static ssize_t fts_feature_enable_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ char buff[CMD_STR_LEN] = {0};
+ int size = 6 * 2;
+ u8 *all_strbuff = NULL;
+ int count = 0, res;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct fts_ts_info *info = i2c_get_clientdata(client);
+
+ if (feature_feasibility >= OK)
+ res = fts_mode_handler(info, 1);
+ else{
+ res = feature_feasibility;
+ logError(1, "%s %s: Call before echo xx xx > feature_enable with a correct feature! ERROR %08X\n", tag, __func__, res);
+ }
+
+ all_strbuff = (u8 *) kmalloc(size, GFP_KERNEL);
+ if (all_strbuff != NULL) {
+ 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);
+
+ snprintf(buff, sizeof(buff), "%02X", 0xBB);
+ strlcat(all_strbuff, buff, size);
+
+ count = snprintf(buf, TSP_BUF_SIZE, "%s\n", all_strbuff);
+ kfree(all_strbuff);
+ } else{
+ logError(1, "%s fts_feature_enable_show: Unable to allocate all_strbuff! ERROR %08X\n", tag, ERROR_ALLOC);
+ }
+
+ feature_feasibility = ERROR_OP_NOT_ALLOW;
+ return count;
+}
+
+#ifdef PHONE_GESTURE
+static ssize_t fts_gesture_mask_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ char buff[CMD_STR_LEN] = {0};
+ int size = 6 * 2;
+ u8 *all_strbuff = NULL;
+ int count = 0, res;
+
+ if (mask[0] == 0) {
+ res = ERROR_OP_NOT_ALLOW;
+ logError(1, "%s %s: Call before echo enable/disable xx xx .... > gesture_mask with a correct number of parameters! ERROR %08X\n", tag, __func__, res);
+
+ } else{
+ res = fts_disableInterrupt();
+ if (res >= OK) {
+ if (mask[1] == FEAT_ENABLE)
+ res = enableGesture(&mask[2], mask[0]);
+ else{
+ if (mask[1] == FEAT_DISABLE)
+ res = disableGesture(&mask[2], mask[0]);
+ else
+ res = ERROR_OP_NOT_ALLOW;
+ }
+ if (res < OK) {
+ logError(1, "%s fts_gesture_mask_store: ERROR %08X\n", tag, res);
+ }
+ }
+ res |= fts_enableInterrupt();
+ }
+
+ all_strbuff = (u8 *) kmalloc(size, GFP_KERNEL);
+ if (all_strbuff != NULL) {
+ 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);
+
+ snprintf(buff, sizeof(buff), "%02X", 0xBB);
+ strlcat(all_strbuff, buff, size);
+
+ count = snprintf(buf, TSP_BUF_SIZE, "%s\n", all_strbuff);
+ kfree(all_strbuff);
+ } else{
+ logError(1, "%s fts_gesture_mask_show: Unable to allocate all_strbuff! ERROR %08X\n", tag, ERROR_ALLOC);
+ }
+
+ mask[0] = 0;
+ return count;
+}
+
+static ssize_t fts_gesture_mask_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ char *p = (char *)buf;
+ int n;
+ unsigned int temp;
+
+ if ((count + 1) / 3 > GESTURE_MASK_SIZE+1) {
+ logError(1, "%s fts_gesture_mask_store: Number of bytes of parameter wrong! %d > (enable/disable + %d )\n", tag, (count + 1) / 3, GESTURE_MASK_SIZE);
+ mask[0] = 0;
+ } else {
+ mask[0] = ((count + 1) / 3) - 1;
+ for (n = 1; n <= (count + 1) / 3; n++) {
+ sscanf(p, "%02X ", &temp);
+ p += 3;
+ mask[n] = (u8)temp;
+ logError(1, "%s mask[%d] = %02X\n", tag, n, mask[n]);
+
+ }
+
+ }
+
+ return count;
+}
+#endif
+
+/************************ PRODUCTION TEST **********************************/
+static ssize_t stm_fts_cmd_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count) {
+ int n;
+ char *p = (char *) buf;
+
+ typeOfComand = (u32 *) kmalloc(8 * sizeof (u32), GFP_KERNEL);
+ if (typeOfComand == NULL) {
+ logError(1, "%s impossible to allocate typeOfComand!\n", tag);
+ return count;
+ }
+ memset(typeOfComand, 0, 8 * sizeof (u32));
+
+ logError(1, "%s\n", tag);
+ for (n = 0; n < (count + 1) / 3; n++) {
+ sscanf(p, "%02X ", &typeOfComand[n]);
+ p += 3;
+ logError(1, "%s typeOfComand[%d] = %02X\n", tag, n, typeOfComand[n]);
+
+ }
+
+ numberParameters = n;
+ logError(1, "%s Number of Parameters = %d\n", tag, numberParameters);
+ return count;
+}
+
+static ssize_t stm_fts_cmd_show(struct device *dev, struct device_attribute *attr,
+ char *buf) {
+ char buff[CMD_STR_LEN] = {0};
+ int res, j, doClean = 0, count;
+
+ int size = 6 * 2;
+ u8 *all_strbuff = NULL;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct fts_ts_info *info = i2c_get_clientdata(client);
+
+ MutualSenseData compData;
+ SelfSenseData comData;
+ MutualSenseFrame frameMS;
+ SelfSenseFrame frameSS;
+
+ /* struct used for defining which test
+ *perform during the production test
+ */
+ TestToDo todoDefault;
+
+ 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 (numberParameters >= 1 && typeOfComand != NULL) {
+ res = fts_disableInterrupt();
+ if (res < 0) {
+ logError(0, "%s fts_disableInterrupt: ERROR %08X\n", tag, res);
+ res = (res | ERROR_DISABLE_INTER);
+ goto END;
+ }
+
+ res = fb_unregister_client(&info->notifier);
+ if (res < 0) {
+ logError(1, "%s ERROR: unregister notifier failed!\n", tag);
+ goto END;
+ }
+
+ switch (typeOfComand[0]) {
+ /*ITO TEST*/
+ case 0x01:
+ res = production_test_ito();
+ break;
+ /*PRODUCTION TEST*/
+ case 0x00:
+ if (ftsInfo.u32_mpPassFlag != INIT_MP) {
+ logError(0, "%s MP Flag not set!\n", tag, res);
+ res = production_test_main(LIMITS_FILE, 1, 1, &todoDefault, INIT_MP);
+ } else{
+ logError(0, "%s MP Flag set!\n", tag, res);
+ res = production_test_main(LIMITS_FILE, 1, 0, &todoDefault, INIT_MP);
+ }
+ break;
+ /*read mutual raw*/
+ case 0x13:
+ logError(0, "%s Get 1 MS Frame\n", tag);
+ /* res = getMSFrame(ADDR_RAW_TOUCH, &frame, 0); */
+ res = getMSFrame2(MS_TOUCH_ACTIVE, &frameMS);
+ if (res < 0) {
+ logError(0, "%s Error while taking the MS 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;
+ /* set res to OK because if getMSFrame is
+ * successful res = number of words read
+ */
+ res = OK;
+ }
+ break;
+ /*read self raw*/
+ case 0x15:
+ logError(0, "%s Get 1 SS Frame\n", tag);
+ res = getSSFrame2(SS_TOUCH, &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;
+ }
+
+ break;
+
+ case 0x14: /*read mutual comp data */
+ logError(0, "%s Get MS Compensation Data\n", tag);
+ res = readMutualSenseCompensationData(MS_TOUCH_ACTIVE, &compData);
+
+ if (res < 0) {
+ logError(0, "%s Error reading MS compensation data ERROR %02X\n", tag, res);
+ } else {
+ logError(0, "%s MS Compensation Data Reading Finished!\n", tag);
+ size = ((compData.node_data_size + 9) * sizeof (u8))*2;
+ }
+ break;
+
+ case 0x16: /* read self comp data */
+ logError(0, "%s Get SS Compensation Data...\n", tag);
+ res = readSelfSenseCompensationData(SS_TOUCH, &comData);
+ if (res < 0) {
+ logError(0, "%s Error reading SS compensation data ERROR %02X\n", tag, res);
+ } else {
+ logError(0, "%s SS Compensation Data Reading Finished!\n", tag);
+ size = ((comData.header.force_node + comData.header.sense_node)*2 + 12) * sizeof (u8)*2;
+ }
+ break;
+
+ case 0x03: /* MS Raw DATA TEST */
+ res = fts_system_reset();
+ if (res >= OK)
+ res = production_test_ms_raw(LIMITS_FILE, 1, &todoDefault);
+ break;
+
+ case 0x04: /* MS CX DATA TEST */
+ res = fts_system_reset();
+ if (res >= OK)
+ res = production_test_ms_cx(LIMITS_FILE, 1, &todoDefault);
+ break;
+
+ case 0x05: /* SS RAW DATA TEST */
+ res = fts_system_reset();
+ if (res >= OK)
+ res = production_test_ss_raw(LIMITS_FILE, 1, &todoDefault);
+ break;
+
+ case 0x06: /* SS IX CX DATA TEST */
+ res = fts_system_reset();
+ if (res >= OK)
+ res = production_test_ss_ix_cx(LIMITS_FILE, 1, &todoDefault);
+ break;
+
+ case 0xF0:
+ case 0xF1: /* TOUCH ENABLE/DISABLE */
+ doClean = (int) (typeOfComand[0]&0x01);
+ res = cleanUp(doClean);
+
+ break;
+
+ default:
+ logError(1, "%s COMMAND NOT VALID!! Insert a proper value ...\n", tag);
+ res = ERROR_OP_NOT_ALLOW;
+ break;
+ }
+
+ doClean = fts_enableInterrupt();
+ if (doClean < 0) {
+ logError(0, "%s fts_enableInterrupt: ERROR %08X\n", tag, (doClean|ERROR_ENABLE_INTER));
+ }
+ } else {
+ logError(1, "%s NO COMMAND SPECIFIED!!! do: 'echo [cmd_code] [args] > stm_fts_cmd' before looking for result!\n", tag);
+ res = ERROR_OP_NOT_ALLOW;
+ typeOfComand = NULL;
+
+ }
+
+ if (fb_register_client(&info->notifier) < 0) {
+ logError(1, "%s ERROR: register notifier failed!\n", tag);
+ }
+
+END: /* here start the reporting phase, assembling the data to send in the file node */
+ all_strbuff = (u8 *) 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 (typeOfComand[0]) {
+ case 0x13:
+ 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 0x15:
+ 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 0x14:
+ 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 0x16:
+ 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;
+
+ default:
+ break;
+
+ }
+ }
+
+ snprintf(buff, sizeof(buff), "%02X", 0xBB);
+ strlcat(all_strbuff, buff, size);
+
+ count = snprintf(buf, TSP_BUF_SIZE, "%s\n", all_strbuff);
+ numberParameters = 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
+ */
+ /* logError(0,"%s numberParameters = %d\n", tag, numberParameters); */
+ kfree(all_strbuff);
+
+ kfree(typeOfComand);
+ return count;
+
+}
+
+static DEVICE_ATTR(fwupdate, (S_IRUGO | S_IWUSR | S_IWGRP), fts_sysfs_fwupdate_show, fts_fw_control_store);
+static DEVICE_ATTR(appid, (S_IRUGO), fts_sysfs_config_id_show, NULL);
+static DEVICE_ATTR(fw_file_test, (S_IRUGO), fts_fw_test_show, NULL);
+static DEVICE_ATTR(stm_fts_cmd, (S_IRUGO | S_IWUSR | S_IWGRP), stm_fts_cmd_show, stm_fts_cmd_store);
+static DEVICE_ATTR(feature_enable, (S_IRUGO | S_IWUSR | S_IWGRP), fts_feature_enable_show, fts_feature_enable_store);
+#ifdef PHONE_GESTURE
+static DEVICE_ATTR(gesture_mask, (S_IRUGO | S_IWUSR | S_IWGRP), fts_gesture_mask_show, fts_gesture_mask_store);
+#endif
+/* /sys/devices/soc.0/f9928000.i2c/i2c-6/6-0049 */
+static struct attribute *fts_attr_group[] = {
+ &dev_attr_fwupdate.attr,
+ &dev_attr_appid.attr,
+ &dev_attr_fw_file_test.attr,
+ /* &dev_attr_touch_debug.attr, */
+ &dev_attr_stm_fts_cmd.attr,
+ &dev_attr_feature_enable.attr,
+#ifdef PHONE_GESTURE
+ &dev_attr_gesture_mask.attr,
+#endif
+ NULL,
+};
+
+static int fts_command(struct fts_ts_info *info, unsigned char cmd)
+{
+ unsigned char regAdd;
+ int ret;
+
+ regAdd = cmd;
+
+ ret = fts_writeCmd(&regAdd, sizeof (regAdd)); /* 0 = ok */
+
+ logError(0, "%s Issued command 0x%02x, return value %08X\n", cmd, ret);
+
+ return ret;
+}
+
+void fts_input_report_key(struct fts_ts_info *info, int key_code)
+{
+ mutex_lock(&info->input_report_mutex);
+ input_report_key(info->input_dev, key_code, 1);
+ input_sync(info->input_dev);
+ input_report_key(info->input_dev, key_code, 0);
+ input_sync(info->input_dev);
+ mutex_unlock(&info->input_report_mutex);
+}
+
+/*
+ * New Interrupt handle implementation
+ */
+
+static inline unsigned char *fts_next_event(unsigned char *evt)
+{
+ /* Nothing to do with this event, moving to the next one */
+ evt += FIFO_EVENT_SIZE;
+
+ /* the previous one was the last event ? */
+ return (evt[-1] & 0x1F) ? evt : NULL;
+}
+
+/* EventId : 0x00 */
+static unsigned char *fts_nop_event_handler(struct fts_ts_info *info,
+ unsigned char *event) {
+ /* logError(1, "%s %s Doing nothing for event = %02X %02X %02X %02X %02X %02X %02X %02X\n",
+ * tag, __func__, event[0], event[1], event[2], event[3], event[4], event[5], event[6], event[7]);
+ */
+ return fts_next_event(event);
+}
+
+/* EventId : 0x03 */
+static unsigned char *fts_enter_pointer_event_handler(struct fts_ts_info *info,
+ unsigned char *event) {
+ unsigned char touchId, touchcount;
+ int x, y, z;
+
+ if (!info->resume_bit)
+ goto no_report;
+
+ touchId = event[1] & 0x0F;
+ touchcount = (event[1] & 0xF0) >> 4;
+
+ __set_bit(touchId, &info->touch_id);
+
+ x = (event[2] << 4) | (event[4] & 0xF0) >> 4;
+ y = (event[3] << 4) | (event[4] & 0x0F);
+ z = (event[5] & 0x3F);
+
+ if (x == X_AXIS_MAX)
+ x--;
+
+ if (y == Y_AXIS_MAX)
+ y--;
+
+ input_mt_slot(info->input_dev, touchId);
+ input_mt_report_slot_state(info->input_dev, MT_TOOL_FINGER, 1);
+ logError(0, "%s %s : TouchID = %d,Touchcount = %d\n", tag, __func__, touchId, touchcount);
+ if (touchcount == 1) {
+ input_report_key(info->input_dev, BTN_TOUCH, 1);
+ input_report_key(info->input_dev, BTN_TOOL_FINGER, 1);
+ }
+ /* input_report_abs(info->input_dev, ABS_MT_TRACKING_ID, touchId); */
+ input_report_abs(info->input_dev, ABS_MT_POSITION_X, x);
+ input_report_abs(info->input_dev, ABS_MT_POSITION_Y, y);
+ input_report_abs(info->input_dev, ABS_MT_TOUCH_MAJOR, z);
+ input_report_abs(info->input_dev, ABS_MT_TOUCH_MINOR, z);
+ input_report_abs(info->input_dev, ABS_MT_PRESSURE, z);
+ logError(0, "%s %s : Event 0x%02x - ID[%d], (x, y, z) = (%3d, %3d, %3d)\n", tag, __func__, *event, touchId, x, y, z);
+
+no_report:
+ return fts_next_event(event);
+}
+
+/* EventId : 0x04 */
+static unsigned char *fts_leave_pointer_event_handler(struct fts_ts_info *info,
+ unsigned char *event) {
+ unsigned char touchId, touchcount;
+
+ touchId = event[1] & 0x0F;
+ touchcount = (event[1] & 0xF0) >> 4;
+
+ __clear_bit(touchId, &info->touch_id);
+
+ input_mt_slot(info->input_dev, touchId);
+ input_mt_report_slot_state(info->input_dev, MT_TOOL_FINGER, 0);
+ logError(0, "%s %s : TouchID = %d, Touchcount = %d\n", tag, __func__, touchId, touchcount);
+ if (touchcount == 0) {
+ input_report_key(info->input_dev, BTN_TOUCH, 0);
+ input_report_key(info->input_dev, BTN_TOOL_FINGER, 0);
+ }
+
+ input_report_abs(info->input_dev, ABS_MT_TRACKING_ID, -1);
+ logError(0, "%s %s : Event 0x%02x - release ID[%d]\n", tag, __func__, event[0], touchId);
+
+ return fts_next_event(event);
+}
+
+/* EventId : 0x05 */
+#define fts_motion_pointer_event_handler fts_enter_pointer_event_handler
+
+#ifdef PHONE_KEY
+/* EventId : 0x0E */
+static unsigned char *fts_key_status_event_handler(struct fts_ts_info *info, unsigned char *event)
+{
+ int value;
+ logError(0, "%s %s Received event %02X %02X %02X %02X %02X %02X %02X %02X\n", tag, __func__, event[0], event[1], event[2], event[3], event[4], event[5], event[6], event[7]);
+ /* TODO: the customer should handle the events coming from the keys according his needs (this is an example that report only the single pressure of one key at time) */
+ if (event[2] != 0) { /* event[2] contain the bitmask of the keys that are actually pressed */
+ switch (event[2]) {
+ case KEY1:
+ value = KEY_HOMEPAGE;
+ logError(0, "%s %s: Button HOME !\n", tag, __func__);
+ break;
+
+ case KEY2:
+ value = KEY_BACK;
+ logError(0, "%s %s: Button Back !\n", tag, __func__);
+ break;
+
+ case KEY3:
+ value = KEY_MENU;
+ logError(0, "%s %s: Button Menu !\n", tag, __func__);
+ break;
+
+ default:
+ logError(0, "%s %s: No valid Button ID or more than one key pressed!\n", tag, __func__);
+ goto done;
+ }
+
+ fts_input_report_key(info, value);
+ } else{
+ logError(0, "%s %s: All buttons released!\n", tag, __func__);
+ }
+done:
+ return fts_next_event(event);
+}
+#endif
+
+/* EventId : 0x0F */
+static unsigned char *fts_error_event_handler(struct fts_ts_info *info,
+ unsigned char *event) {
+ int error = 0, i = 0;
+ logError(0, "%s %s Received event 0x%02x 0x%02x\n", tag, __func__, event[0], event[1]);
+
+ switch (event[1]) {
+ case EVENT_TYPE_ESD_ERROR:
+ {
+ for (i = 0; i < TOUCH_ID_MAX; i++) {
+ input_mt_slot(info->input_dev, i);
+ input_mt_report_slot_state(info->input_dev, (i < FINGER_MAX) ? MT_TOOL_FINGER : MT_TOOL_PEN, 0);
+ }
+ input_sync(info->input_dev);
+
+ fts_chip_powercycle(info);
+
+ error = fts_system_reset();
+ error |= fts_mode_handler(info, 0);
+ error |= fts_enableInterrupt();
+ if (error < OK) {
+ logError(1, "%s %s Cannot restore the device ERROR %08X\n", tag, __func__, error);
+ }
+ }
+ break;
+ case EVENT_TYPE_WATCHDOG_ERROR: /* watch dog timer */
+ {
+ if (event[2] == 0) {
+ /* before reset clear all slot */
+ for (i = 0; i < TOUCH_ID_MAX; i++) {
+ input_mt_slot(info->input_dev, i);
+ input_mt_report_slot_state(info->input_dev,
+ (i < FINGER_MAX) ? MT_TOOL_FINGER : MT_TOOL_PEN, 0);
+ }
+ input_sync(info->input_dev);
+ error = fts_system_reset();
+ error |= fts_mode_handler(info, 0);
+ error |= fts_enableInterrupt();
+ if (error < OK) {
+ logError(1, "%s %s Cannot reset the device ERROR %08X\n", tag, __func__, error);
+ }
+ }
+ }
+ break;
+
+ }
+ return fts_next_event(event);
+}
+
+/* EventId : 0x10 */
+static unsigned char *fts_controller_ready_event_handler(
+ struct fts_ts_info *info, unsigned char *event) {
+ int error;
+ logError(0, "%s %s Received event 0x%02x\n", tag, __func__, event[0]);
+ info->touch_id = 0;
+ input_sync(info->input_dev);
+ setSystemResettedUp(1);
+ setSystemResettedDown(1);
+ error = fts_mode_handler(info, 0);
+ if (error < OK) {
+ logError(1, "%s %s Cannot restore the device status ERROR %08X\n", tag, __func__, error);
+ }
+ return fts_next_event(event);
+}
+
+/* EventId : 0x16 */
+static unsigned char *fts_status_event_handler(
+ struct fts_ts_info *info, unsigned char *event) {
+ /* logError(1, "%s Received event 0x%02x\n", tag, event[0]); */
+
+ switch (event[1]) {
+ case EVENT_TYPE_MS_TUNING_CMPL:
+ case EVENT_TYPE_SS_TUNING_CMPL:
+ case FTS_FORCE_CAL_SELF_MUTUAL:
+ case FTS_FLASH_WRITE_CONFIG:
+ case FTS_FLASH_WRITE_COMP_MEMORY:
+ case FTS_FORCE_CAL_SELF:
+ case FTS_WATER_MODE_ON:
+ case FTS_WATER_MODE_OFF:
+ default:
+ logError(1, "%s %s Received unhandled status event = %02X %02X %02X %02X %02X %02X %02X %02X\n", tag, __func__, event[0], event[1], event[2], event[3], event[4], event[5], event[6], event[7]);
+ break;
+ }
+
+ return fts_next_event(event);
+}
+
+#ifdef PHONE_GESTURE
+static unsigned char *fts_gesture_event_handler(struct fts_ts_info *info, unsigned char *event)
+{
+ unsigned char touchId;
+ int value;
+
+ logError(0, "%s gesture event data: %02X %02X %02X %02X %02X %02X %02X %02X\n", tag, event[0], event[1], event[2], event[3], event[4], event[5], event[6], event[7]);
+
+ if (event[1] == 0x03) {
+
+ logError(1, "%s %s: Gesture ID %02X enable_status = %02X\n", tag, __func__, event[2], event[3]);
+
+ }
+ if (event[1] == EVENT_TYPE_ENB && event[2] == 0x00) {
+ switch (event[3]) {
+ case GESTURE_ENABLE:
+ logError(1, "%s %s: Gesture Enabled! res = %02X\n", tag, __func__, event[4]);
+ break;
+
+ case GESTURE_DISABLE:
+ logError(1, "%s %s: Gesture Disabled! res = %02X\n", tag, __func__, event[4]);
+ break;
+
+ default:
+ logError(1, "%s %s: Event not Valid!\n", tag, __func__);
+
+ }
+
+ }
+
+ /* always use touchId zero */
+ touchId = 0;
+ __set_bit(touchId, &info->touch_id);
+
+ if (event[0] == EVENTID_GESTURE && (event[1] == EVENT_TYPE_GESTURE_DTC1 || event[1] == EVENT_TYPE_GESTURE_DTC2)) {
+
+ switch (event[2]) {
+ case GES_ID_DBLTAP:
+ value = KEY_WAKEUP;
+ logError(0, "%s %s: double tap !\n", tag, __func__);
+ break;
+
+ case GES_ID_AT:
+ value = KEY_WWW;
+ logError(0, "%s %s: @ !\n", tag, __func__);
+ break;
+
+ case GES_ID_C:
+ value = KEY_C;
+ logError(0, "%s %s: C !\n", tag, __func__);
+ break;
+
+ case GES_ID_E:
+ value = KEY_E;
+ logError(0, "%s %s: e !\n", tag, __func__);
+ break;
+
+ case GES_ID_F:
+ value = KEY_F;
+ logError(0, "%s %s: F !\n", tag, __func__);
+ break;
+
+ case GES_ID_L:
+ value = KEY_L;
+ logError(0, "%s %s: L !\n", tag, __func__);
+ break;
+
+ case GES_ID_M:
+ value = KEY_M;
+ logError(0, "%s %s: M !\n", tag, __func__);
+ break;
+
+ case GES_ID_O:
+ value = KEY_O;
+ logError(0, "%s %s: O !\n", tag, __func__);
+ break;
+
+ case GES_ID_S:
+ value = KEY_S;
+ logError(0, "%s %s: S !\n", tag, __func__);
+ break;
+
+ case GES_ID_V:
+ value = KEY_V;
+ logError(0, "%s %s: V !\n", tag, __func__);
+ break;
+
+ case GES_ID_W:
+ value = KEY_W;
+ logError(0, "%s %s: W !\n", tag, __func__);
+ break;
+
+ case GES_ID_Z:
+ value = KEY_Z;
+ logError(0, "%s %s: Z !\n", tag, __func__);
+ break;
+
+ case GES_ID_HFLIP_L2R:
+ value = KEY_RIGHT;
+ logError(0, "%s %s: -> !\n", tag, __func__);
+ break;
+
+ case GES_ID_HFLIP_R2L:
+ value = KEY_LEFT;
+ logError(0, "%s %s: <- !\n", tag, __func__);
+ break;
+
+ case GES_ID_VFLIP_D2T:
+ value = KEY_UP;
+ logError(0, "%s %s: UP !\n", tag, __func__);
+ break;
+
+ case GES_ID_VFLIP_T2D:
+ value = KEY_DOWN;
+ logError(0, "%s %s: DOWN !\n", tag, __func__);
+ break;
+
+ case GES_ID_CUST1:
+ value = KEY_F1;
+ logError(0, "%s %s: F1 !\n", tag, __func__);
+ break;
+
+ case GES_ID_CUST2:
+ value = KEY_F1;
+ logError(0, "%s %s: F2 !\n", tag, __func__);
+ break;
+
+ case GES_ID_CUST3:
+ value = KEY_F3;
+ logError(0, "%s %s: F3 !\n", tag, __func__);
+ break;
+
+ case GES_ID_CUST4:
+ value = KEY_F1;
+ logError(0, "%s %s: F4 !\n", tag, __func__);
+ break;
+
+ case GES_ID_CUST5:
+ value = KEY_F1;
+ logError(0, "%s %s: F5 !\n", tag, __func__);
+ break;
+
+ case GES_ID_LEFTBRACE:
+ value = KEY_LEFTBRACE;
+ logError(0, "%s %s: < !\n", tag, __func__);
+ break;
+
+ case GES_ID_RIGHTBRACE:
+ value = KEY_RIGHTBRACE;
+ logError(0, "%s %s: > !\n", tag, __func__);
+ break;
+ default:
+ logError(0, "%s %s: No valid GestureID!\n", tag, __func__);
+ goto gesture_done;
+
+ }
+
+ fts_input_report_key(info, value);
+
+ gesture_done:
+ /* Done with gesture event, clear bit. */
+ __clear_bit(touchId, &info->touch_id);
+ }
+
+ return fts_next_event(event);
+}
+#endif
+
+/* EventId : 0x05 */
+#define fts_motion_pointer_event_handler fts_enter_pointer_event_handler
+
+/*
+ * This handler is called each time there is at least
+ * one new event in the FIFO
+ */
+static void fts_event_handler(struct work_struct *work)
+{
+ struct fts_ts_info *info;
+ int error, error1;
+ int left_events;
+ unsigned char regAdd;
+ unsigned char data[FIFO_EVENT_SIZE * (FIFO_DEPTH)] = {0};
+ unsigned char *event = NULL;
+ unsigned char eventId;
+ event_dispatch_handler_t event_handler;
+
+ info = container_of(work, struct fts_ts_info, work);
+ /*
+ * to avoid reading all FIFO, we read the first event and
+ * then check how many events left in the FIFO
+ */
+
+
+ regAdd = FIFO_CMD_READONE;
+ error = fts_readCmd(&regAdd,
+ sizeof (regAdd), data, FIFO_EVENT_SIZE);
+
+ if (!error) {
+
+ left_events = data[7] & 0x1F;
+ if ((left_events > 0) && (left_events < FIFO_DEPTH)) {
+ /*
+ * Read remaining events.
+ */
+ regAdd = FIFO_CMD_READALL;
+
+ error1 = fts_readCmd(&regAdd, sizeof (regAdd),
+ &data[FIFO_EVENT_SIZE],
+ left_events * FIFO_EVENT_SIZE);
+ /*
+ * Got an error reading remaining events,
+ * process at least * the first one that was
+ * reading fine.
+ */
+ if (error1)
+ data[7] &= 0xE0;
+ }
+
+ /* At least one event is available */
+ event = data;
+ do {
+ eventId = *event;
+ event_handler = info->event_dispatch_table[eventId];
+
+ if (eventId < EVENTID_LAST) {
+ event = event_handler(info, (event));
+ } else {
+ event = fts_next_event(event);
+ }
+ input_sync(info->input_dev);
+ } while (event);
+ }
+
+ /*
+ * re-enable interrupts
+ */
+ fts_interrupt_enable(info);
+}
+
+static int cx_crc_check(void)
+{
+ unsigned char regAdd1[3] = {FTS_CMD_HW_REG_R, ADDR_CRC_BYTE0, ADDR_CRC_BYTE1};
+ unsigned char val;
+ unsigned char crc_status;
+ unsigned int error;
+
+ error = fts_readCmd(regAdd1, sizeof (regAdd1), &val, 1);
+ if (error < OK) {
+ logError(1, "%s %s Cannot read crc status ERROR %08X\n", tag, __func__, error);
+ return error;
+ }
+
+ crc_status = val & CRC_MASK;
+ if (crc_status != OK) { /* CRC error if crc_status!= 0 */
+ logError(1, "%s %s CRC ERROR = %X\n", tag, __func__, crc_status);
+ }
+
+ return crc_status; /* return OK if no CRC error, or a number >OK if crc error */
+}
+
+static void fts_fw_update_auto(struct work_struct *work)
+{
+ int retval = 0;
+ int retval1 = 0;
+ int ret;
+ struct fts_ts_info *info;
+ struct delayed_work *fwu_work = container_of(work, struct delayed_work, work);
+ int crc_status = 0;
+ int error = 0;
+ info = container_of(fwu_work, struct fts_ts_info, fwu_work);
+
+ logError(1, "%s Fw Auto Update is starting...\n", tag);
+
+ /* check CRC status */
+ ret = cx_crc_check();
+ if (ret > OK && ftsInfo.u16_fwVer == 0x0000) {
+ logError(1, "%s %s: CRC Error or NO FW!\n", tag, __func__);
+ crc_status = 1;
+ } else {
+ crc_status = 0;
+ logError(1, "%s %s: NO CRC Error or Impossible to read CRC register!\n", tag, __func__);
+ }
+#ifdef FTM3_CHIP
+ retval = flashProcedure(PATH_FILE_FW, crc_status, !crc_status);
+#else
+ retval = flashProcedure(PATH_FILE_FW, crc_status, 1);
+#endif
+ if ((retval & 0xFF000000) == ERROR_FLASH_PROCEDURE) {
+ logError(1, "%s %s: firmware update failed and retry! ERROR %08X\n", tag, __func__, retval);
+ fts_chip_powercycle(info); /* power reset */
+#ifdef FTM3_CHIP
+ retval1 = flashProcedure(PATH_FILE_FW, crc_status, !crc_status);
+#else
+ retval1 = flashProcedure(PATH_FILE_FW, crc_status, 1);
+#endif
+ if ((retval1 & 0xFF000000) == ERROR_FLASH_PROCEDURE) {
+ logError(1, "%s %s: firmware update failed again! ERROR %08X\n", tag, __func__, retval1);
+ logError(1, "%s Fw Auto Update Failed!\n", tag);
+ /* return; */
+ }
+ }
+
+ if ((ftsInfo.u32_mpPassFlag != INIT_MP) && (ftsInfo.u32_mpPassFlag != INIT_FIELD))
+ ret = ERROR_GET_INIT_STATUS;
+ else
+ ret = OK;
+
+ if (ret == ERROR_GET_INIT_STATUS) { /* initialization status not correct or after FW complete update, do initialization. */
+ error = fts_chip_initialization(info);
+ if (error < OK) {
+ logError(1, "%s %s Cannot initialize the chip ERROR %08X\n", tag, __func__, error);
+ }
+ }
+ error = fts_init_hw(info);
+ if (error < OK) {
+ logError(1, "%s Cannot initialize the hardware device ERROR %08X\n", tag, error);
+ }
+
+ logError(1, "%s Fw Auto Update Finished!\n", tag);
+}
+
+static int fts_chip_initialization(struct fts_ts_info *info)
+{
+ int ret2 = 0;
+ int retry;
+ int initretrycnt = 0;
+
+ /* initialization error, retry initialization */
+ for (retry = 0; retry <= INIT_FLAG_CNT; retry++) {
+ ret2 = production_test_initialization();
+ if (ret2 == OK) {
+ ret2 = save_mp_flag(INIT_FIELD);
+ if (ret2 == OK)
+ break;
+ }
+ initretrycnt++;
+ logError(1, "%s initialization cycle count = %04d - ERROR %08X\n", tag, initretrycnt, ret2);
+ fts_chip_powercycle(info);
+ }
+ if (ret2 < OK) { /* initialization error */
+ logError(1, "%s fts initialization failed 3 times\n", tag);
+ }
+
+ return ret2;
+}
+
+#ifdef FTS_USE_POLLING_MODE
+
+static enum hrtimer_restart fts_timer_func(struct hrtimer *timer)
+{
+ struct fts_ts_info *info =
+ container_of(timer, struct fts_ts_info, timer);
+
+ queue_work(info->event_wq, &info->work);
+ return HRTIMER_NORESTART;
+}
+#else
+
+static irqreturn_t fts_interrupt_handler(int irq, void *handle)
+{
+ struct fts_ts_info *info = handle;
+ disable_irq_nosync(info->client->irq);
+ queue_work(info->event_wq, &info->work);
+ return IRQ_HANDLED;
+}
+#endif
+
+static int fts_interrupt_install(struct fts_ts_info *info)
+{
+ int i, error = 0;
+
+ info->event_dispatch_table = kzalloc(
+ sizeof (event_dispatch_handler_t) * EVENTID_LAST, GFP_KERNEL);
+
+ if (!info->event_dispatch_table) {
+ logError(1, "%s OOM allocating event dispatch table\n", tag);
+ return -ENOMEM;
+ }
+
+ for (i = 0; i < EVENTID_LAST; i++)
+ info->event_dispatch_table[i] = fts_nop_event_handler;
+
+ install_handler(info, ENTER_POINTER, enter_pointer);
+ install_handler(info, LEAVE_POINTER, leave_pointer);
+ install_handler(info, MOTION_POINTER, motion_pointer);
+ install_handler(info, ERROR_EVENT, error);
+ install_handler(info, CONTROL_READY, controller_ready);
+ install_handler(info, STATUS_UPDATE, status);
+#ifdef PHONE_GESTURE
+ install_handler(info, GESTURE, gesture);
+#endif
+#ifdef PHONE_KEY
+ install_handler(info, KEY_STATUS, key_status);
+#endif
+
+ /* disable interrupts in any case */
+ error = fts_disableInterrupt();
+
+#ifdef FTS_USE_POLLING_MODE
+ logError(1, "%s Polling Mode\n");
+ hrtimer_init(&info->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+ info->timer.function = fts_timer_func;
+ hrtimer_start(&info->timer, ktime_set(1, 0), HRTIMER_MODE_REL);
+#else
+ logError(1, "%s Interrupt Mode\n", tag);
+ if (request_irq(info->client->irq, fts_interrupt_handler,
+ IRQF_TRIGGER_LOW, info->client->name,
+ info)) {
+ logError(1, "%s Request irq failed\n", tag);
+ kfree(info->event_dispatch_table);
+ error = -EBUSY;
+ } /*else {
+ error = fts_enableInterrupt();
+ }*/
+#endif
+
+ return error;
+}
+
+static void fts_interrupt_uninstall(struct fts_ts_info *info)
+{
+
+ fts_disableInterrupt();
+
+ kfree(info->event_dispatch_table);
+#ifdef FTS_USE_POLLING_MODE
+ hrtimer_cancel(&info->timer);
+#else
+ free_irq(info->client->irq, info);
+#endif
+}
+
+static void fts_interrupt_enable(struct fts_ts_info *info)
+{
+#ifdef FTS_USE_POLLING_MODE
+ hrtimer_start(&info->timer,
+ ktime_set(0, 10000000), HRTIMER_MODE_REL);
+#else
+ enable_irq(info->client->irq);
+#endif
+}
+
+/*
+static void fts_interrupt_disable(struct fts_ts_info *info)
+{
+#ifdef FTS_USE_POLLING_MODE
+ hrtimer_cancel(&info->timer);
+#else
+ disable_irq(info->client->irq);
+#endif
+}
+*/
+
+static int fts_init(struct fts_ts_info *info)
+{
+ int error;
+
+ error = fts_system_reset();
+ if (error < OK && error != (ERROR_TIMEOUT | ERROR_SYSTEM_RESET_FAIL)) {
+ logError(1, "%s Cannot reset the device! ERROR %08X\n", tag, error);
+ return error;
+ }
+ if (error == (ERROR_TIMEOUT | ERROR_SYSTEM_RESET_FAIL)) {
+ logError(1, "%s Setting default Chip INFO!\n", tag);
+ defaultChipInfo(0);
+ } else {
+ error = readChipInfo(0); /* system reset OK */
+ if (error < OK) {
+ logError(1, "%s Cannot read Chip Info! ERROR %08X\n", tag, error);
+ }
+ }
+
+ error = fts_interrupt_install(info);
+
+ if (error != OK)
+ logError(1, "%s Init (1) error (ERROR = %08X)\n", error);
+
+ return error;
+}
+
+int fts_chip_powercycle(struct fts_ts_info *info)
+{
+ int error, i;
+
+ logError(1, "%s %s: Power Cycle Starting...\n", tag, __func__);
+ if (info->pwr_reg) {
+ error = regulator_disable(info->pwr_reg);
+ if (error < 0) {
+ logError(1, "%s %s: Failed to disable DVDD regulator\n", tag, __func__);
+ }
+ }
+
+ if (info->bus_reg) {
+ error = regulator_disable(info->bus_reg);
+ if (error < 0) {
+ logError(1, "%s %s: Failed to disable AVDD regulator\n", tag, __func__);
+ }
+ }
+
+ if (info->bdata->reset_gpio != GPIO_NOT_DEFINED)
+ gpio_set_value(info->bdata->reset_gpio, 0);
+
+ msleep(300);
+ if (info->pwr_reg) {
+ error = regulator_enable(info->bus_reg);
+ if (error < 0) {
+ logError(1, "%s %s: Failed to enable AVDD regulator\n", tag, __func__);
+ }
+ }
+
+ if (info->bus_reg) {
+ error = regulator_enable(info->pwr_reg);
+ if (error < 0) {
+ logError(1, "%s %s: Failed to enable DVDD regulator\n", tag, __func__);
+ }
+ }
+ msleep(300); /* time needed by the regulators for reaching the regime values */
+
+ if (info->bdata->reset_gpio != GPIO_NOT_DEFINED) {
+ msleep(10); /* time to wait before bring up the reset gpio after the power up of the regulators */
+ gpio_set_value(info->bdata->reset_gpio, 1);
+ /* msleep(300); */
+ }
+
+ /* before reset clear all slot */
+ for (i = 0; i < TOUCH_ID_MAX; i++) {
+ input_mt_slot(info->input_dev, i);
+ input_mt_report_slot_state(info->input_dev,
+ (i < FINGER_MAX) ? MT_TOOL_FINGER : MT_TOOL_PEN, 0);
+ }
+ input_sync(info->input_dev);
+
+ logError(1, "%s %s: Power Cycle Finished! ERROR CODE = %08x\n", tag, __func__, error);
+ setSystemResettedUp(1);
+ setSystemResettedDown(1);
+ return error;
+}
+
+int fts_chip_powercycle2(struct fts_ts_info *info, unsigned long sleep)
+{
+ int error, i;
+
+ logError(1, "%s %s: Power Cycle Starting...\n", tag, __func__);
+ if (info->pwr_reg) {
+ error = regulator_disable(info->pwr_reg);
+ if (error < 0) {
+ logError(1, "%s %s: Failed to disable DVDD regulator\n", tag, __func__);
+ }
+ }
+
+ if (info->bus_reg) {
+ error = regulator_disable(info->bus_reg);
+ if (error < 0) {
+ logError(1, "%s %s: Failed to disable AVDD regulator\n", tag, __func__);
+ }
+ }
+
+ if (info->bdata->reset_gpio != GPIO_NOT_DEFINED)
+ gpio_set_value(info->bdata->reset_gpio, 0);
+
+ msleep(sleep);
+ if (info->pwr_reg) {
+ error = regulator_enable(info->bus_reg);
+ if (error < 0) {
+ logError(1, "%s %s: Failed to enable AVDD regulator\n", tag, __func__);
+ }
+ }
+
+ if (info->bus_reg) {
+ error = regulator_enable(info->pwr_reg);
+ if (error < 0) {
+ logError(1, "%s %s: Failed to enable DVDD regulator\n", tag, __func__);
+ }
+ }
+ msleep(500); /*time needed by the regulators for reaching the regime values */
+
+ if (info->bdata->reset_gpio != GPIO_NOT_DEFINED) {
+ msleep(10); /*time to wait before bring up the reset gpio after the power up of the regulators */
+ gpio_set_value(info->bdata->reset_gpio, 1);
+ /* msleep(300); */
+ }
+
+ /* before reset clear all slot */
+ for (i = 0; i < TOUCH_ID_MAX; i++) {
+ input_mt_slot(info->input_dev, i);
+ input_mt_report_slot_state(info->input_dev,
+ (i < FINGER_MAX) ? MT_TOOL_FINGER : MT_TOOL_PEN, 0);
+ }
+ input_sync(info->input_dev);
+
+ logError(1, "%s %s: Power Cycle Finished! ERROR CODE = %08x\n", tag, __func__, error);
+ setSystemResettedUp(1);
+ setSystemResettedDown(1);
+ return error;
+}
+
+static int fts_init_hw(struct fts_ts_info *info)
+{
+ int error = 0;
+
+ error = cleanUp(1);
+ if (error < OK)
+ logError(1, "%s Init (2) error (ERROR = %08X)\n", tag, error);
+
+ info->mode = MODE_NORMAL;
+
+ return error;
+}
+
+ /*
+ * TODO: change this function according with the needs of
+ *customer in temrs of feature to enable/disable
+ */
+static int fts_mode_handler(struct fts_ts_info *info, int force)
+{
+ int res = OK;
+ int ret = OK;
+
+ logError(0, "%s %s: Mode Handler starting...\n", tag, __func__);
+ switch (info->resume_bit) {
+ case 0:/* screen down */
+ logError(0, "%s %s: Screen OFF...\n", tag, __func__);
+#ifdef PHONE_GESTURE
+ if (info->gesture_enabled == 1) {
+ logError(0, "%s %s: enter in gesture mode !\n", tag, __func__);
+ res = enterGestureMode(isSystemResettedDown());
+ if (res >= OK) {
+
+ info->mode = MODE_GESTURE;
+ /* return OK; */
+ } else {
+ logError(1, "%s %s: enterGestureMode failed! ERROR %08X recovery in senseOff...\n", tag, __func__, res);
+ }
+ }
+#endif
+ if (info->mode != MODE_GESTURE || info->gesture_enabled == 0) {
+ logError(0, "%s %s: Sense OFF!\n", tag, __func__);
+ res |= fts_command(info, FTS_CMD_MS_MT_SENSE_OFF); /* we need to use fts_command for speed reason (no need to check echo in this case and interrupt can be enabled) */
+#ifdef PHONE_KEY
+ logError(0, "%s %s: Key OFF!\n", tag, __func__);
+ res |= fts_command(info, FTS_CMD_MS_KEY_OFF);
+#endif
+
+ info->mode = MODE_SENSEOFF;
+
+ }
+ setSystemResettedDown(0);
+ break;
+
+ case 1: /* screen up */
+ logError(0, "%s %s: Screen ON...\n", tag, __func__);
+ logError(0, "%s %s: Sense ON!\n", tag, __func__);
+ res |= fts_command(info, FTS_CMD_MS_MT_SENSE_ON);
+#ifdef PHONE_KEY
+ logError(0, "%s %s: Key ON!\n", tag, __func__);
+ res |= fts_command(info, FTS_CMD_MS_KEY_ON);
+#endif
+ info->mode = MODE_NORMAL;
+
+ if (info->glove_enabled == FEAT_ENABLE || force == 1) {
+ if (isSystemResettedUp() || force == 1) {
+ logError(0, "%s %s: Glove Mode setting...\n", tag, __func__);
+ ret = featureEnableDisable(info->glove_enabled, FEAT_GLOVE);
+ if (ret < OK) {
+ logError(1, "%s %s: error during setting GLOVE_MODE! ERROR %08X\n", tag, __func__, ret);
+ }
+ res |= ret;
+ }
+ if (ret >= OK && info->glove_enabled == FEAT_ENABLE) {
+ info->mode = MODE_GLOVE;
+ logError(1, "%s %s: GLOVE_MODE Enabled!\n", tag, __func__);
+ } else{
+ logError(1, "%s %s: GLOVE_MODE Disabled!\n", tag, __func__);
+ }
+ }
+
+ setSystemResettedUp(0);
+ break;
+
+ default:
+ logError(1, "%s %s: invalid resume_bit value = %d! ERROR %08X\n", tag, __func__, info->resume_bit, ERROR_OP_NOT_ALLOW);
+ res = ERROR_OP_NOT_ALLOW;
+ }
+
+ logError(0, "%s %s: Mode Handler finished! res = %08X\n", tag, __func__, res);
+ return res;
+
+}
+
+static int fts_fb_state_chg_callback(struct notifier_block *nb, unsigned long val, void *data)
+{
+ struct fts_ts_info *info = container_of(nb, struct fts_ts_info, notifier);
+ struct fb_event *evdata = data;
+ int i;
+ unsigned int blank;
+
+ if (val != FB_EVENT_BLANK)
+ return 0;
+
+ logError(0, "%s %s: fts notifier begin!\n", tag, __func__);
+
+ if (evdata && evdata->data && val == FB_EVENT_BLANK && info) {
+
+ blank = *(int *) (evdata->data);
+
+ switch (blank) {
+ case FB_BLANK_POWERDOWN:
+ if (info->sensor_sleep)
+ break;
+
+ logError(0, "%s %s: FB_BLANK_POWERDOWN\n", tag, __func__);
+
+ /* Release all slots */
+ for (i = 0; i < TOUCH_ID_MAX; i++) {
+ input_mt_slot(info->input_dev, i);
+ input_mt_report_slot_state(info->input_dev,
+ (i < FINGER_MAX) ? MT_TOOL_FINGER : MT_TOOL_PEN, 0);
+ }
+ input_sync(info->input_dev);
+
+ info->resume_bit = 0;
+
+ fts_mode_handler(info, 0);
+
+ info->sensor_sleep = true;
+
+ fts_disableInterrupt();
+
+ break;
+
+ case FB_BLANK_UNBLANK:
+ if (!info->sensor_sleep)
+ break;
+
+ logError(0, "%s %s: FB_BLANK_UNBLANK\n", tag, __func__);
+
+ for (i = 0; i < TOUCH_ID_MAX; i++) {
+ input_mt_slot(info->input_dev, i);
+ input_mt_report_slot_state(info->input_dev,
+ (i < FINGER_MAX) ? MT_TOOL_FINGER : MT_TOOL_PEN, 0);
+ }
+ input_sync(info->input_dev);
+
+ info->resume_bit = 1;
+
+ fts_system_reset();
+
+ fts_mode_handler(info, 0);
+
+ info->sensor_sleep = false;
+
+ fts_enableInterrupt();
+ break;
+ default:
+ break;
+
+ }
+ }
+ return NOTIFY_OK;
+
+}
+
+static struct notifier_block fts_noti_block = {
+ .notifier_call = fts_fb_state_chg_callback,
+};
+
+static int fts_get_reg(struct fts_ts_info *rmi4_data,
+ bool get) {
+ int retval;
+ const struct fts_i2c_platform_data *bdata =
+ rmi4_data->bdata;
+
+ if (!get) {
+ retval = 0;
+ goto regulator_put;
+ }
+
+ if ((bdata->pwr_reg_name != NULL) && (*bdata->pwr_reg_name != 0)) {
+ rmi4_data->pwr_reg = regulator_get(rmi4_data->dev,
+ bdata->pwr_reg_name);
+ if (IS_ERR(rmi4_data->pwr_reg)) {
+ logError(1, "%s %s: Failed to get power regulator\n", tag,
+ __func__);
+ retval = PTR_ERR(rmi4_data->pwr_reg);
+ goto regulator_put;
+ }
+ }
+
+ if ((bdata->bus_reg_name != NULL) && (*bdata->bus_reg_name != 0)) {
+ rmi4_data->bus_reg = regulator_get(rmi4_data->dev,
+ bdata->bus_reg_name);
+ if (IS_ERR(rmi4_data->bus_reg)) {
+ logError(1, "%s %s: Failed to get bus pullup regulator\n", tag,
+ __func__);
+ retval = PTR_ERR(rmi4_data->bus_reg);
+ goto regulator_put;
+ }
+ }
+
+ return 0;
+
+regulator_put:
+ if (rmi4_data->pwr_reg) {
+ regulator_put(rmi4_data->pwr_reg);
+ rmi4_data->pwr_reg = NULL;
+ }
+
+ if (rmi4_data->bus_reg) {
+ regulator_put(rmi4_data->bus_reg);
+ rmi4_data->bus_reg = NULL;
+ }
+
+ return retval;
+}
+
+static int fts_enable_reg(struct fts_ts_info *rmi4_data,
+ bool enable) {
+ int retval;
+
+ if (!enable) {
+ retval = 0;
+ goto disable_pwr_reg;
+ }
+
+ if (rmi4_data->bus_reg) {
+ retval = regulator_enable(rmi4_data->bus_reg);
+ if (retval < 0) {
+ logError(1, "%s %s: Failed to enable bus regulator\n", tag,
+ __func__);
+ goto exit;
+ }
+ }
+
+ if (rmi4_data->pwr_reg) {
+ retval = regulator_enable(rmi4_data->pwr_reg);
+ if (retval < 0) {
+ logError(1, "%s %s: Failed to enable power regulator\n", tag,
+ __func__);
+ goto disable_bus_reg;
+ }
+ }
+
+ return OK;
+
+disable_pwr_reg:
+ if (rmi4_data->pwr_reg)
+ regulator_disable(rmi4_data->pwr_reg);
+
+disable_bus_reg:
+ if (rmi4_data->bus_reg)
+ regulator_disable(rmi4_data->bus_reg);
+
+exit:
+ return retval;
+}
+
+static int fts_gpio_setup(int gpio, bool config, int dir, int state)
+{
+ int retval = 0;
+ unsigned char buf[16];
+
+ if (config) {
+ snprintf(buf, 16, "fts_gpio_%u\n", gpio);
+
+ retval = gpio_request(gpio, buf);
+ if (retval) {
+ logError(1, "%s %s: Failed to get gpio %d (code: %d)", tag,
+ __func__, gpio, retval);
+ return retval;
+ }
+
+ if (dir == 0)
+ retval = gpio_direction_input(gpio);
+ else
+ retval = gpio_direction_output(gpio, state);
+ if (retval) {
+ logError(1, "%s %s: Failed to set gpio %d direction", tag,
+ __func__, gpio);
+ return retval;
+ }
+ } else {
+ gpio_free(gpio);
+ }
+
+ return retval;
+}
+
+static int fts_set_gpio(struct fts_ts_info *rmi4_data)
+{
+ int retval;
+ const struct fts_i2c_platform_data *bdata =
+ rmi4_data->bdata;
+
+ retval = fts_gpio_setup(bdata->irq_gpio, true, 0, 0);
+ if (retval < 0) {
+ logError(1, "%s %s: Failed to configure irq GPIO\n", tag, __func__);
+ goto err_gpio_irq;
+ }
+
+ if (bdata->reset_gpio >= 0) {
+ retval = fts_gpio_setup(bdata->reset_gpio, true, 1, 0);
+ if (retval < 0) {
+ logError(1, "%s %s: Failed to configure reset GPIO\n", tag, __func__);
+ goto err_gpio_reset;
+ }
+ }
+ if (bdata->reset_gpio >= 0) {
+ gpio_set_value(bdata->reset_gpio, 0);
+ msleep(10);
+ gpio_set_value(bdata->reset_gpio, 1);
+ }
+
+ setResetGpio(bdata->reset_gpio);
+ return OK;
+
+err_gpio_reset:
+ fts_gpio_setup(bdata->irq_gpio, false, 0, 0);
+ setResetGpio(GPIO_NOT_DEFINED);
+err_gpio_irq:
+ return retval;
+}
+
+static int parse_dt(struct device *dev, struct fts_i2c_platform_data *bdata)
+{
+ int retval;
+ const char *name;
+ struct device_node *np = dev->of_node;
+
+ bdata->irq_gpio = of_get_named_gpio_flags(np,
+ "st,irq-gpio", 0, NULL);
+
+ logError(0, "%s irq_gpio = %d\n", tag, bdata->irq_gpio);
+
+ retval = of_property_read_string(np, "st,regulator_dvdd", &name);
+ if (retval == -EINVAL)
+ bdata->pwr_reg_name = NULL;
+ else if (retval < 0)
+ return retval;
+ bdata->pwr_reg_name = name;
+ logError(0, "%s pwr_reg_name = %s\n", tag, name);
+
+ retval = of_property_read_string(np, "st,regulator_avdd", &name);
+ if (retval == -EINVAL)
+ bdata->bus_reg_name = NULL;
+ else if (retval < 0)
+ return retval;
+ bdata->bus_reg_name = name;
+ logError(0, "%s bus_reg_name = %s\n", tag, name);
+
+ if (of_property_read_bool(np, "st, reset-gpio")) {
+ bdata->reset_gpio = of_get_named_gpio_flags(np,
+ "st, reset-gpio", 0, NULL);
+ logError(0, "%s reset_gpio =%d\n", tag, bdata->reset_gpio);
+ } else {
+ bdata->reset_gpio = GPIO_NOT_DEFINED;
+ }
+
+ return OK;
+}
+
+static int fts_probe(struct i2c_client *client,
+ const struct i2c_device_id *idp) {
+ struct fts_ts_info *info = NULL;
+ char fts_ts_phys[64];
+ int error = 0;
+ struct device_node *dp = client->dev.of_node;
+ int retval;
+
+ logError(1, "%s %s: driver probe begin!\n", tag, __func__);
+
+ logError(1, "%s SET I2C Functionality and Dev INFO:\n", tag);
+ openChannel(client);
+
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+ logError(1, "%s Unsupported I2C functionality\n", tag);
+ error = -EIO;
+ goto ProbeErrorExit_0;
+ }
+
+ info = kzalloc(sizeof (struct fts_ts_info), GFP_KERNEL);
+ if (!info) {
+ logError(1, "%s Out of memory... Impossible to allocate struct info!\n", tag);
+ error = -ENOMEM;
+ goto ProbeErrorExit_0;
+ }
+
+ info->client = client;
+
+ i2c_set_clientdata(client, info);
+ logError(1, "%s i2c address: %x\n", tag, client->addr);
+ info->dev = &info->client->dev;
+ if (dp) {
+ info->bdata = devm_kzalloc(&client->dev, sizeof (struct fts_i2c_platform_data), GFP_KERNEL);
+ if (!info->bdata) {
+ logError(1, "%s ERROR:info.bdata kzalloc failed\n", tag);
+ goto ProbeErrorExit_1;
+ }
+ parse_dt(&client->dev, info->bdata);
+ }
+
+ logError(1, "%s SET Regulators:\n", tag);
+ retval = fts_get_reg(info, true);
+ if (retval < 0) {
+ logError(1, "%s ERROR: %s: Failed to get regulators\n", tag, __func__);
+ goto ProbeErrorExit_1;
+ }
+
+ retval = fts_enable_reg(info, true);
+ if (retval < 0) {
+ logError(1, "%s %s: ERROR Failed to enable regulators\n", tag, __func__);
+ goto ProbeErrorExit_2;
+ }
+
+ logError(1, "%s SET GPIOS:\n", tag);
+ retval = fts_set_gpio(info);
+ if (retval < 0) {
+ logError(1, "%s %s: ERROR Failed to set up GPIO's\n", tag, __func__);
+ goto ProbeErrorExit_2;
+ }
+ info->client->irq = gpio_to_irq(info->bdata->irq_gpio);
+
+ logError(1, "%s SET Auto Fw Update:\n", tag);
+ info->fwu_workqueue = create_singlethread_workqueue("fts-fwu-queue");
+ if (!info->fwu_workqueue) {
+ logError(1, "%s ERROR: Cannot create fwu work thread\n", tag);
+ goto ProbeErrorExit_3;
+ }
+ INIT_DELAYED_WORK(&info->fwu_work, fts_fw_update_auto);
+
+ logError(1, "%s SET Event Handler:\n", tag);
+ info->event_wq = create_singlethread_workqueue("fts-event-queue");
+ if (!info->event_wq) {
+ logError(1, "%s ERROR: Cannot create work thread\n", tag);
+ error = -ENOMEM;
+ goto ProbeErrorExit_4;
+ }
+
+ INIT_WORK(&info->work, fts_event_handler);
+
+ logError(1, "%s SET Input Device Property:\n", tag);
+ info->dev = &info->client->dev;
+ info->input_dev = input_allocate_device();
+ if (!info->input_dev) {
+ logError(1, "%s ERROR: No such input device defined!\n", tag);
+ error = -ENODEV;
+ goto ProbeErrorExit_5;
+ }
+ info->input_dev->dev.parent = &client->dev;
+ info->input_dev->name = FTS_TS_DRV_NAME;
+ snprintf(fts_ts_phys, sizeof (fts_ts_phys), "%s/input0",
+ info->input_dev->name);
+ info->input_dev->phys = fts_ts_phys;
+ info->input_dev->id.bustype = BUS_I2C;
+ info->input_dev->id.vendor = 0x0001;
+ info->input_dev->id.product = 0x0002;
+ info->input_dev->id.version = 0x0100;
+
+ __set_bit(EV_SYN, info->input_dev->evbit);
+ __set_bit(EV_KEY, info->input_dev->evbit);
+ __set_bit(EV_ABS, info->input_dev->evbit);
+ __set_bit(BTN_TOUCH, info->input_dev->keybit);
+ __set_bit(BTN_TOOL_FINGER, info->input_dev->keybit);
+
+ input_mt_init_slots(info->input_dev, TOUCH_ID_MAX, INPUT_MT_DIRECT);
+
+ /* input_mt_init_slots(info->input_dev, TOUCH_ID_MAX); */
+
+ /* input_set_abs_params(info->input_dev, ABS_MT_TRACKING_ID, 0, FINGER_MAX, 0, 0); */
+ input_set_abs_params(info->input_dev, ABS_MT_POSITION_X,
+ X_AXIS_MIN, X_AXIS_MAX, 0, 0);
+ input_set_abs_params(info->input_dev, ABS_MT_POSITION_Y,
+ Y_AXIS_MIN, Y_AXIS_MAX, 0, 0);
+ input_set_abs_params(info->input_dev, ABS_MT_TOUCH_MAJOR,
+ AREA_MIN, AREA_MAX, 0, 0);
+ input_set_abs_params(info->input_dev, ABS_MT_TOUCH_MINOR,
+ AREA_MIN, AREA_MAX, 0, 0);
+ input_set_abs_params(info->input_dev, ABS_MT_PRESSURE,
+ PRESSURE_MIN, PRESSURE_MAX, 0, 0);
+
+#ifdef PHONE_GESTURE
+ input_set_capability(info->input_dev, EV_KEY, KEY_WAKEUP);
+
+ input_set_capability(info->input_dev, EV_KEY, KEY_M);
+ input_set_capability(info->input_dev, EV_KEY, KEY_O);
+ input_set_capability(info->input_dev, EV_KEY, KEY_E);
+ input_set_capability(info->input_dev, EV_KEY, KEY_W);
+ input_set_capability(info->input_dev, EV_KEY, KEY_C);
+ input_set_capability(info->input_dev, EV_KEY, KEY_L);
+ input_set_capability(info->input_dev, EV_KEY, KEY_F);
+ input_set_capability(info->input_dev, EV_KEY, KEY_V);
+ input_set_capability(info->input_dev, EV_KEY, KEY_S);
+ input_set_capability(info->input_dev, EV_KEY, KEY_Z);
+ input_set_capability(info->input_dev, EV_KEY, KEY_WWW);
+
+ input_set_capability(info->input_dev, EV_KEY, KEY_LEFT);
+ input_set_capability(info->input_dev, EV_KEY, KEY_RIGHT);
+ input_set_capability(info->input_dev, EV_KEY, KEY_UP);
+ input_set_capability(info->input_dev, EV_KEY, KEY_DOWN);
+
+ input_set_capability(info->input_dev, EV_KEY, KEY_F1);
+ input_set_capability(info->input_dev, EV_KEY, KEY_F2);
+ input_set_capability(info->input_dev, EV_KEY, KEY_F3);
+ input_set_capability(info->input_dev, EV_KEY, KEY_F4);
+ input_set_capability(info->input_dev, EV_KEY, KEY_F5);
+
+ input_set_capability(info->input_dev, EV_KEY, KEY_LEFTBRACE);
+ input_set_capability(info->input_dev, EV_KEY, KEY_RIGHTBRACE);
+#endif
+
+#ifdef PHONE_KEY
+ /* KEY associated to the touch screen buttons */
+ input_set_capability(info->input_dev, EV_KEY, KEY_HOMEPAGE);
+ input_set_capability(info->input_dev, EV_KEY, KEY_BACK);
+ input_set_capability(info->input_dev, EV_KEY, KEY_MENU);
+#endif
+
+ mutex_init(&(info->input_report_mutex));
+
+ /* register the multi-touch input device */
+ error = input_register_device(info->input_dev);
+ if (error) {
+ logError(1, "%s ERROR: No such input device\n", tag);
+ error = -ENODEV;
+ goto ProbeErrorExit_5_1;
+ }
+
+ /* track slots */
+ info->touch_id = 0;
+
+ /* init hardware device */
+ logError(1, "%s Device Initialization:\n", tag);
+ error = fts_init(info);
+ if (error < OK) {
+ logError(1, "%s Cannot initialize the device ERROR %08X\n", tag, error);
+ error = -ENODEV;
+ goto ProbeErrorExit_6;
+ }
+
+ info->gesture_enabled = 0;
+ info->glove_enabled = 0;
+ info->resume_bit = 1;
+ info->notifier = fts_noti_block;
+ error = fb_register_client(&info->notifier);
+ if (error) {
+ logError(1, "%s ERROR: register notifier failed!\n", tag);
+ goto ProbeErrorExit_6;
+ }
+
+ logError(1, "%s SET Device File Nodes:\n", tag);
+ /* sysfs stuff */
+ info->attrs.attrs = fts_attr_group;
+ error = sysfs_create_group(&client->dev.kobj, &info->attrs);
+ if (error) {
+ logError(1, "%s ERROR: Cannot create sysfs structure!\n", tag);
+ error = -ENODEV;
+ goto ProbeErrorExit_7;
+ }
+
+#ifdef SCRIPTLESS
+ /*I2C cmd*/
+ if (fts_cmd_class == NULL)
+ fts_cmd_class = class_create(THIS_MODULE, FTS_TS_DRV_NAME);
+ info->i2c_cmd_dev = device_create(fts_cmd_class,
+ NULL, DCHIP_ID_0, info, "fts_i2c");
+ if (IS_ERR(info->i2c_cmd_dev)) {
+ logError(1, "%s ERROR: Failed to create device for the sysfs!\n", tag);
+ goto ProbeErrorExit_8;
+ }
+
+ dev_set_drvdata(info->i2c_cmd_dev, info);
+
+ error = sysfs_create_group(&info->i2c_cmd_dev->kobj,
+ &i2c_cmd_attr_group);
+ if (error) {
+ logError(1, "%s ERROR: Failed to create sysfs group!\n", tag);
+ goto ProbeErrorExit_9;
+ }
+
+#endif
+
+#ifdef DRIVER_TEST
+ if (fts_cmd_class == NULL)
+ fts_cmd_class = class_create(THIS_MODULE, FTS_TS_DRV_NAME);
+ info->test_cmd_dev = device_create(fts_cmd_class,
+ NULL, DCHIP_ID_0, info, "fts_driver_test");
+ if (IS_ERR(info->test_cmd_dev)) {
+ logError(1, "%s ERROR: Failed to create device for the sysfs!\n", tag);
+ goto ProbeErrorExit_10;
+ }
+
+ dev_set_drvdata(info->test_cmd_dev, info);
+
+ error = sysfs_create_group(&info->test_cmd_dev->kobj,
+ &test_cmd_attr_group);
+ if (error) {
+ logError(1, "%s ERROR: Failed to create sysfs group!\n", tag);
+ goto ProbeErrorExit_11;
+ }
+
+#endif
+ queue_delayed_work(info->fwu_workqueue, &info->fwu_work, msecs_to_jiffies(EXP_FN_WORK_DELAY_MS));
+ logError(1, "%s Probe Finished!\n", tag);
+ return OK;
+
+ /* error exit path */
+#ifdef DRIVER_TEST
+ProbeErrorExit_11:
+#ifndef SCRIPTLESS
+ device_destroy(fts_cmd_class, DCHIP_ID_0);
+#endif
+
+ProbeErrorExit_10:
+#ifndef SCRIPTLESS
+ sysfs_remove_group(&client->dev.kobj, &info->attrs);
+#endif
+#endif
+
+#ifdef SCRIPTLESS
+ProbeErrorExit_9:
+ device_destroy(fts_cmd_class, DCHIP_ID_0);
+
+ProbeErrorExit_8:
+ sysfs_remove_group(&client->dev.kobj, &info->attrs);
+#endif
+
+ProbeErrorExit_7:
+ fb_unregister_client(&info->notifier);
+
+ProbeErrorExit_6:
+ input_unregister_device(info->input_dev);
+
+ProbeErrorExit_5_1:
+ /* intput_free_device(info->input_dev ); */
+
+ ProbeErrorExit_5:
+ destroy_workqueue(info->event_wq);
+
+ProbeErrorExit_4:
+ destroy_workqueue(info->fwu_workqueue);
+
+ProbeErrorExit_3:
+ fts_enable_reg(info, false);
+
+ProbeErrorExit_2:
+ fts_get_reg(info, false);
+
+ProbeErrorExit_1:
+ kfree(info);
+
+ProbeErrorExit_0:
+ logError(1, "%s Probe Failed!\n", tag);
+
+ return error;
+}
+
+static int fts_remove(struct i2c_client *client)
+{
+ struct fts_ts_info *info = i2c_get_clientdata(client);
+
+#ifdef DRIVER_TEST
+ sysfs_remove_group(&info->test_cmd_dev->kobj,
+ &test_cmd_attr_group);
+#endif
+
+#ifdef SCRIPTLESS
+ /*I2C cmd*/
+ sysfs_remove_group(&info->i2c_cmd_dev->kobj,
+ &i2c_cmd_attr_group);
+
+#endif
+
+#if defined(SCRIPTLESS) || defined(DRIVER_TEST)
+ device_destroy(fts_cmd_class, DCHIP_ID_0);
+#endif
+
+ /* sysfs stuff */
+ sysfs_remove_group(&client->dev.kobj, &info->attrs);
+
+ /* remove interrupt and event handlers */
+ fts_interrupt_uninstall(info);
+
+ fb_unregister_client(&info->notifier);
+
+ /* unregister the device */
+ input_unregister_device(info->input_dev);
+
+ /* intput_free_device(info->input_dev ); */
+
+ /* Empty the FIFO buffer */
+ fts_command(info, FIFO_CMD_FLUSH);
+ /* flushFIFO(); */
+
+ /* Remove the work thread */
+ destroy_workqueue(info->event_wq);
+ destroy_workqueue(info->fwu_workqueue);
+
+ fts_enable_reg(info, false);
+ fts_get_reg(info, false);
+
+ /* free all */
+ kfree(info);
+
+ return OK;
+}
+
+static struct of_device_id fts_of_match_table[] = {
+ {
+ .compatible = "st,fts",
+ },
+ {},
+};
+static const struct i2c_device_id fts_device_id[] = {
+ {FTS_TS_DRV_NAME, 0},
+ {}
+};
+
+static struct i2c_driver fts_i2c_driver = {
+ .driver = {
+ .name = FTS_TS_DRV_NAME,
+ .of_match_table = fts_of_match_table,
+ },
+ .probe = fts_probe,
+ .remove = fts_remove,
+ .id_table = fts_device_id,
+};
+
+static int __init fts_driver_init(void)
+{
+ return i2c_add_driver(&fts_i2c_driver);
+}
+
+static void __exit fts_driver_exit(void)
+{
+ i2c_del_driver(&fts_i2c_driver);
+}
+
+MODULE_DESCRIPTION("STMicroelectronics MultiTouch IC Driver");
+MODULE_AUTHOR("STMicroelectronics, Inc.");
+MODULE_LICENSE("GPL");
+
+late_initcall(fts_driver_init);
+module_exit(fts_driver_exit);
diff --git a/drivers/input/touchscreen/st/fts.h b/drivers/input/touchscreen/st/fts.h
new file mode 100644
index 000000000000..7d72d226349f
--- /dev/null
+++ b/drivers/input/touchscreen/st/fts.h
@@ -0,0 +1,249 @@
+/*
+ * fts.c
+ *
+ * FTS Capacitive touch screen controller (FingerTipS)
+ *
+ * Copyright (C) 2016, 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.
+ *
+ */
+
+#ifndef _LINUX_FTS_I2C_H_
+#define _LINUX_FTS_I2C_H_
+
+#include "fts_lib/ftsSoftware.h"
+#include "fts_lib/ftsHardware.h"
+
+#define FTS_POWER_ON 1
+#define FTS_POWER_OFF 0
+
+/****************** CONFIGURATION SECTION ******************/
+/* #define PHONE_KEY */
+
+/* #define PHONE_GESTURE */
+
+#define SCRIPTLESS
+#ifdef SCRIPTLESS
+#define SCRIPTLESS_DEBUG
+/* uncomment this macro definition to print debug
+* message for script less support
+*/
+#endif
+
+#define DRIVER_TEST
+
+#define FW_H_FILE
+#ifdef FW_H_FILE
+#define FW_SIZE_NAME myArray_size
+#define FW_ARRAY_NAME myArray
+#endif
+
+#define LIMITS_H_FILE
+#ifdef LIMITS_H_FILE
+#define LIMITS_SIZE_NAME myArray2_size
+#define LIMITS_ARRAY_NAME myArray2
+#endif
+
+#define FTS_TS_DRV_NAME "fts"
+#define FTS_TS_DRV_VERSION "4.1.0"
+
+#define X_AXIS_MAX 1440
+#define X_AXIS_MIN 0
+#define Y_AXIS_MAX 2560
+#define Y_AXIS_MIN 0
+
+#define PRESSURE_MIN 0
+#define PRESSURE_MAX 127
+
+#define FINGER_MAX 10
+#define STYLUS_MAX 1
+#define TOUCH_ID_MAX (FINGER_MAX + STYLUS_MAX)
+
+#define AREA_MIN PRESSURE_MIN
+#define AREA_MAX PRESSURE_MAX
+
+/*********************************************************/
+
+/* Flash programming */
+
+#define INIT_FLAG_CNT 3
+
+/* KEYS */
+#define KEY1 0x02
+#define KEY2 0x01
+#define KEY3 0x04
+
+/*
+ * Configuration mode
+ */
+#define MODE_NORMAL 0
+#define MODE_GESTURE 1
+#define MODE_GLOVE 2
+#define MODE_SENSEOFF 3
+
+/*
+ * Status Event Field:
+ * id of command that triggered the event
+ */
+
+#define FTS_FLASH_WRITE_CONFIG 0x03
+#define FTS_FLASH_WRITE_COMP_MEMORY 0x04
+#define FTS_FORCE_CAL_SELF_MUTUAL 0x05
+#define FTS_FORCE_CAL_SELF 0x06
+#define FTS_WATER_MODE_ON 0x07
+#define FTS_WATER_MODE_OFF 0x08
+
+#define EXP_FN_WORK_DELAY_MS 1000
+
+#define CMD_STR_LEN 32
+
+#ifdef SCRIPTLESS
+/*
+ * I2C Command Read/Write Function
+ */
+
+#define CMD_RESULT_STR_LEN 2048
+#endif
+
+#define TSP_BUF_SIZE 4096
+
+struct fts_i2c_platform_data {
+ int (*power)(bool on);
+ int irq_gpio;
+ int reset_gpio;
+ const char *pwr_reg_name;
+ const char *bus_reg_name;
+
+};
+
+/*
+ * Forward declaration
+ */
+struct fts_ts_info;
+extern char tag[8];
+
+/*
+ * Dispatch event handler
+ */
+typedef unsigned char * (*event_dispatch_handler_t)
+(struct fts_ts_info *info, unsigned char *data);
+
+/*
+ * struct fts_ts_info - FTS capacitive touch screen device information
+ * @dev: Pointer to the structure device
+ * @client: I2C client structure
+ * @input_dev Input device structure
+ * @work Work thread
+ * @event_wq Event queue for work thread
+ * @cmd_done Asyncronous command notification
+ * @event_dispatch_table Event dispatch table handlers
+ * @fw_version Firmware version
+ * @attrs SysFS attributes
+ * @mode Device operating mode
+ * @touch_id Bitmask for touch id (mapped to input slots)
+ * @buttons Bitmask for buttons status
+ * @timer Timer when operating in polling mode
+ * @early_suspend Structure for early suspend functions
+ * @power Power on/off routine
+ */
+
+struct fts_ts_info {
+ struct device *dev;
+ struct i2c_client *client;
+ struct input_dev *input_dev;
+
+ struct work_struct work;
+ struct workqueue_struct *event_wq;
+
+ struct delayed_work fwu_work;
+ struct workqueue_struct *fwu_workqueue;
+ struct completion cmd_done;
+
+ event_dispatch_handler_t *event_dispatch_table;
+
+ unsigned int fw_version;
+ unsigned int config_id;
+
+ struct attribute_group attrs;
+
+ unsigned int mode;
+ unsigned long touch_id;
+ unsigned int buttons;
+
+#ifdef FTS_USE_POLLING_MODE
+ struct hrtimer timer;
+#endif
+
+#ifdef SCRIPTLESS
+ /*I2C cmd*/
+ struct device *i2c_cmd_dev;
+ char cmd_read_result[CMD_RESULT_STR_LEN];
+ char cmd_wr_result[CMD_RESULT_STR_LEN];
+ char cmd_write_result[20];
+#endif
+
+#ifdef DRIVER_TEST
+ struct device *test_cmd_dev;
+#endif
+
+ int (*power)(bool on);
+
+ struct fts_i2c_platform_data *bdata;
+ struct regulator *pwr_reg;
+ struct regulator *bus_reg;
+
+ bool fw_force;
+ int debug_enable;
+
+ int resume_bit;
+ int fwupdate_stat;
+ int touch_debug;
+
+ struct notifier_block notifier;
+ bool sensor_sleep;
+ bool stay_awake;
+
+ /* input lock */
+ struct mutex input_report_mutex;
+
+ /* switches */
+ int gesture_enabled;
+ int glove_enabled;
+
+};
+
+typedef enum {
+ ERR_ITO_NO_ERR, /* < 0 No ITO Error */
+ ERR_ITO_PANEL_OPEN_FORCE, /* < 1 Panel Open Force */
+ ERR_ITO_PANEL_OPEN_SENSE, /* < 2 Panel Open Sense */
+ ERR_ITO_F2G, /* < 3 Force short to ground */
+ ERR_ITO_S2G, /* < 4 Sense short to ground */
+ ERR_ITO_F2VDD, /* < 5 Force short to VDD */
+ ERR_ITO_S2VDD, /* < 6 Sense short to VDD */
+ ERR_ITO_P2P_FORCE, /* < 7 Pin to Pin short (Force) */
+ ERR_ITO_P2P_SENSE, /* < 8 Pin to Pin short (Sense) */
+} errItoSubTypes_t;
+
+int fts_chip_powercycle(struct fts_ts_info *info);
+int fts_chip_powercycle2(struct fts_ts_info *info, unsigned long sleep);
+int fts_get_fw_version(struct fts_ts_info *info);
+extern unsigned int le_to_uint(const unsigned char *ptr);
+extern unsigned int be_to_uint(const unsigned char *ptr);
+extern int input_register_notifier_client(struct notifier_block *nb);
+extern int input_unregister_notifier_client(struct notifier_block *nb);
+
+#ifdef SCRIPTLESS
+extern struct attribute_group i2c_cmd_attr_group;
+#endif
+
+#ifdef DRIVER_TEST
+extern struct attribute_group test_cmd_attr_group;
+#endif
+
+#endif
diff --git a/drivers/input/touchscreen/st/fts_driver_test.c b/drivers/input/touchscreen/st/fts_driver_test.c
new file mode 100644
index 000000000000..5c55d8e4ac88
--- /dev/null
+++ b/drivers/input/touchscreen/st/fts_driver_test.c
@@ -0,0 +1,871 @@
+/*
+
+**************************************************************************
+** STMicroelectronics **
+**************************************************************************
+** marco.cali@st.com **
+**************************************************************************
+* *
+* API used by Driver Test Apk *
+* *
+**************************************************************************
+**************************************************************************
+
+*/
+
+#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/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 10
+
+/* 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
+
+u32 *functionToTest;
+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;
+
+ functionToTest = (u32 *) kmalloc(MAX_PARAMS * sizeof (u32), GFP_KERNEL);
+ if (functionToTest == NULL) {
+ logError(1, "%s impossible to allocate functionToTest!\n", tag);
+ return count;
+ }
+ memset(functionToTest, 0, MAX_PARAMS * sizeof (u32));
+
+ for (n = 0; n < (count + 1) / 3 && n < MAX_PARAMS; n++) {
+ sscanf(p, "%02X ", &functionToTest[n]);
+ 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 res2; */
+ int size = 6 * 2;
+ int temp, i, byteToRead;
+ u8 *readData = NULL;
+ u8 *all_strbuff = NULL;
+ u8 *cmd;
+
+ MutualSenseFrame frameMS;
+ SelfSenseFrame frameSS;
+
+ DataHeader dataHead;
+ MutualSenseData compData;
+ SelfSenseData comData;
+ GeneralData gnData;
+
+ u16 address;
+ u16 fw_version;
+ u16 config_id;
+
+ Firmware fw;
+
+ /* struct used for defining which test perform during the MP test */
+
+ 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 && functionToTest != NULL) {
+ res = fts_disableInterrupt();
+ if (res < 0) {
+ logError(0, "%s stm_driver_test_show: ERROR %08X\n", tag, res);
+ res = (res | ERROR_DISABLE_INTER);
+ goto END;
+ }
+ switch (functionToTest[0]) {
+ case CMD_READ:
+ if (numberParam >= 4) {
+ temp = (int) functionToTest[1];
+ if (numberParam == 4 + (temp - 1) && temp != 0) {
+ cmd = (u8 *) kmalloc(temp * sizeof (u8), GFP_KERNEL);
+ for (i = 0; i < temp; i++) {
+ cmd[i] = functionToTest[i + 2];
+ }
+ byteToRead = functionToTest[i + 2];
+ readData = (u8 *) kmalloc(byteToRead * sizeof (u8), GFP_KERNEL);
+ res = fts_readCmd(cmd, temp, readData, byteToRead);
+ size += (byteToRead * sizeof (u8))*2;
+ } else {
+ logError(1, "%s Wrong parameters!\n", tag);
+ res = ERROR_OP_NOT_ALLOW;
+ }
+
+ } else {
+ logError(1, "%s Wrong number of parameters!\n", tag);
+ res = ERROR_OP_NOT_ALLOW;
+ }
+ break;
+
+ case CMD_WRITE:
+ if (numberParam >= 3) { /* 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(temp * sizeof (u8), GFP_KERNEL);
+ for (i = 0; i < temp; i++) {
+ cmd[i] = functionToTest[i + 2];
+ }
+ res = fts_writeCmd(cmd, temp);
+ } else {
+ logError(1, "%s Wrong parameters!\n", tag);
+ res = ERROR_OP_NOT_ALLOW;
+ }
+
+ } else {
+ logError(1, "%s Wrong number of parameters!\n", tag);
+ res = ERROR_OP_NOT_ALLOW;
+ }
+ break;
+
+ case CMD_FWWRITE:
+ if (numberParam >= 3) { /* 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(temp * sizeof (u8), GFP_KERNEL);
+ for (i = 0; i < temp; i++) {
+ cmd[i] = functionToTest[i + 2];
+ }
+ res = fts_writeFwCmd(cmd, temp);
+ } else {
+ logError(1, "%s Wrong parameters!\n", tag);
+ res = ERROR_OP_NOT_ALLOW;
+ }
+
+ } else {
+ logError(1, "%s Wrong number of parameters!\n", tag);
+ res = ERROR_OP_NOT_ALLOW;
+ }
+ break;
+
+ case CMD_READU16:
+ if (numberParam == 6) { /* need to pass: cmd addr[0] addr[1] byteToRead hasDummyByte */
+ byteToRead = functionToTest[4];
+ readData = (u8 *) kmalloc(byteToRead * sizeof (u8), GFP_KERNEL);
+ res = readCmdU16((u8) functionToTest[1], (u16) ((((u8) functionToTest[2] & 0x00FF) << 8) + ((u8) functionToTest[3] & 0x00FF)), readData, byteToRead, functionToTest[5]);
+ size += (byteToRead * sizeof (u8))*2;
+ } else {
+ logError(1, "%s Wrong number of parameters!\n", tag);
+ res = ERROR_OP_NOT_ALLOW;
+ }
+ break;
+
+ case CMD_READB2:
+ if (numberParam == 4) { /* need to pass: addr[0] addr[1] byteToRead */
+ byteToRead = functionToTest[3];
+ readData = (u8 *) kmalloc(byteToRead * sizeof (u8), GFP_KERNEL);
+ res = readB2((u16) ((((u8) functionToTest[1] & 0x00FF) << 8) + ((u8) functionToTest[2] & 0x00FF)), readData, byteToRead);
+ size += (byteToRead * sizeof (u8))*2;
+ } else {
+ logError(1, "%s Wrong number of parameters!\n", tag);
+ res = ERROR_OP_NOT_ALLOW;
+ }
+ break;
+
+ case CMD_READB2U16:
+ if (numberParam == 4) { /* need to pass: addr[0] addr[1] byteToRead */
+ byteToRead = functionToTest[3];
+ readData = (u8 *) kmalloc(byteToRead * sizeof (u8), GFP_KERNEL);
+ res = readB2U16((u16) ((((u8) functionToTest[1] & 0x00FF) << 8) + ((u8) functionToTest[2] & 0x00FF)), readData, byteToRead);
+ size += (byteToRead * sizeof (u8))*2;
+ } else {
+ logError(1, "%s Wrong number of parameters!\n", tag);
+ res = ERROR_OP_NOT_ALLOW;
+ }
+ break;
+
+ case CMD_POLLFOREVENT:
+ if (numberParam >= 5) { /* 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(FIFO_EVENT_SIZE * sizeof (u8), GFP_KERNEL);
+ res = pollForEvent((int *) &functionToTest[2], temp, readData, ((functionToTest[temp + 2] & 0x00FF) << 8)+(functionToTest[temp + 3] & 0x00FF));
+ if (res >= OK)
+ res = OK; /* pollForEvent return the number of error found */
+ size += (FIFO_EVENT_SIZE * sizeof (u8))*2;
+ byteToRead = FIFO_EVENT_SIZE;
+ } else {
+ logError(1, "%s Wrong parameters!\n", tag);
+ res = ERROR_OP_NOT_ALLOW;
+ }
+
+ } else {
+ logError(1, "%s Wrong number of parameters!\n", tag);
+ res = ERROR_OP_NOT_ALLOW;
+ }
+ break;
+
+ case CMD_SYSTEMRESET:
+ res = fts_system_reset();
+
+ break;
+
+ case CMD_READCHIPINFO:
+ if (numberParam == 2) { /* need to pass: doRequest */
+ res = readChipInfo(functionToTest[1]);
+ } else {
+ logError(1, "%s Wrong number of parameters!\n", tag);
+ res = ERROR_OP_NOT_ALLOW;
+ }
+
+ break;
+
+ case CMD_CLEANUP: /* TOUCH ENABLE/DISABLE */
+ if (numberParam == 2) { /* need to pass: enableTouch */
+ res = cleanUp(functionToTest[1]);
+ } else {
+ logError(1, "%s Wrong number of parameters!\n", tag);
+ res = ERROR_OP_NOT_ALLOW;
+ }
+
+ 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(0, "%s Requesting Frame\n", tag);
+ res = requestFrame((u16) ((((u8) functionToTest[1] & 0x00FF) << 8) + ((u8) functionToTest[2] & 0x00FF)));
+
+ if (res < OK) {
+ logError(0, "%s Error requesting frame ERROR %02X\n", tag, res);
+ } else {
+ logError(0, "%s Requesting Frame Finished!\n", tag);
+ }
+ } else {
+ logError(1, "%s Wrong number of parameters!\n", tag);
+ res = ERROR_OP_NOT_ALLOW;
+ }
+ break;
+
+ case CMD_GETMSFRAME:
+ if (numberParam == 3) {
+ 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 Error while taking the MS 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;
+ /* 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);
+ }
+ } else {
+ logError(1, "%s Wrong number of parameters!\n", tag);
+ res = ERROR_OP_NOT_ALLOW;
+ }
+ break;
+
+ /*read self raw*/
+ case CMD_GETSSFRAME:
+ if (numberParam == 3) {
+ 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);
+ }
+ } else {
+ logError(1, "%s Wrong number of parameters!\n", tag);
+ res = ERROR_OP_NOT_ALLOW;
+ }
+ break;
+
+ case CMD_REQCOMPDATA: /* request comp data */
+ if (numberParam == 3) {
+ 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);
+ }
+ } else {
+ logError(1, "%s Wrong number of parameters!\n", tag);
+ res = ERROR_OP_NOT_ALLOW;
+ }
+ break;
+
+ case CMD_READCOMPDATAHEAD: /* read comp data header */
+ if (numberParam == 3) {
+ 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);
+ res = readCompensationDataHeader((u16) ((((u8) functionToTest[1] & 0x00FF) << 8) + ((u8) functionToTest[2] & 0x00FF)), &dataHead, &address);
+ if (res < OK) {
+ logError(0, "%s Read Compensation Data Header ERROR %02X\n", tag, res);
+ } else {
+ logError(0, "%s Read Compensation Data Header OK!\n", tag);
+ size += (2 * sizeof (u8))*2;
+ }
+ }
+ } else {
+ logError(1, "%s Wrong number of parameters!\n", tag);
+ res = ERROR_OP_NOT_ALLOW;
+ }
+ break;
+
+ case CMD_READMSCOMPDATA: /* read mutual comp data */
+ if (numberParam == 3) {
+ 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 compensation data ERROR %02X\n", tag, res);
+ } else {
+ logError(0, "%s MS Compensation Data 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);
+ }
+ } else {
+ logError(1, "%s Wrong number of parameters!\n", tag);
+ res = ERROR_OP_NOT_ALLOW;
+ }
+ break;
+
+ case CMD_READSSCOMPDATA:
+ if (numberParam == 3) { /* 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 compensation data ERROR %02X\n", tag, res);
+ } else {
+ logError(0, "%s SS Compensation Data Reading Finished!\n", tag);
+ size = ((comData.header.force_node + comData.header.sense_node)*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);
+ }
+ } else {
+ logError(1, "%s Wrong number of parameters!\n", tag);
+ res = ERROR_OP_NOT_ALLOW;
+ }
+ break;
+
+ case CMD_READGNCOMPDATA:
+ if (numberParam == 3) { /* 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 Error reading General compensation data ERROR %02X\n", tag, res);
+ } else {
+ logError(0, "%s General Compensation Data Reading Finished!\n", tag);
+ size = (14) * sizeof (u8)*2;
+ }
+ } else {
+ logError(1, "%s Wrong number of parameters!\n", tag);
+ res = ERROR_OP_NOT_ALLOW;
+ }
+ break;
+
+ case CMD_GETFWVER:
+ res = getFirmwareVersion(&fw_version, &config_id);
+ if (res < OK) {
+ logError(1, "%s Error reading firmware version and config id ERROR %02X\n", tag, res);
+ } else {
+ logError(0, "%s getFirmwareVersion 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 Error reading flash status ERROR %02X\n", tag, res);
+ } else {
+ logError(0, "%s Flash Status: %d\n", tag, res);
+ size += (1 * sizeof (u8))*2;
+ temp = res; /* need to store the value for further display */
+ res = OK; /* set res =ok for returning code */
+ }
+ 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) { /* 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 ERROR %02X\n", tag, res);
+ } else {
+ logError(0, "%s Read FW File Finished!\n", tag);
+ }
+ kfree(fw.data);
+ } else {
+ logError(1, "%s Wrong number of parameters!\n", tag);
+ res = ERROR_OP_NOT_ALLOW;
+ }
+ break;
+
+ case CMD_FLASHPROCEDURE:
+ if (numberParam == 3) { /* 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 Error during flash procedure ERROR %02X\n", tag, res);
+ } else {
+ logError(0, "%s Flash Procedure Finished!\n", tag);
+ }
+ } else {
+ logError(1, "%s Wrong number of parameters!\n", tag);
+ res = ERROR_OP_NOT_ALLOW;
+ }
+ break;
+
+ /*ITO TEST*/
+ case CMD_ITOTEST:
+ res = production_test_ito();
+ break;
+
+ /*Initialization*/
+ case CMD_INITTEST:
+ if (numberParam == 2) { /* need to specify if if save value on Flash */
+ if (functionToTest[1] == 0x01)
+ res = production_test_initialization();
+ else
+ res = production_test_splited_initialization(false);
+ } else {
+ logError(1, "%s Wrong number of parameters!\n", tag);
+ res = ERROR_OP_NOT_ALLOW;
+ }
+ break;
+
+ case CMD_MSRAWTEST: /* MS Raw DATA TEST */
+ if (numberParam == 2) /* need to specify if stopOnFail */
+ res = production_test_ms_raw(LIMITS_FILE, functionToTest[1], &todoDefault);
+ else {
+ logError(1, "%s Wrong number of parameters!\n", tag);
+ res = ERROR_OP_NOT_ALLOW;
+ }
+ break;
+
+ case CMD_MSINITDATATEST: /* MS CX DATA TEST */
+ if (numberParam == 2) /* need to specify if stopOnFail */
+ res = production_test_ms_cx(LIMITS_FILE, functionToTest[1], &todoDefault);
+ else {
+ logError(1, "%s Wrong number of parameters!\n", tag);
+ res = ERROR_OP_NOT_ALLOW;
+ }
+ break;
+
+ case CMD_SSRAWTEST: /* SS RAW DATA TEST */
+ if (numberParam == 2) /* need to specify if stopOnFail */
+ res = production_test_ss_raw(LIMITS_FILE, functionToTest[1], &todoDefault);
+ else {
+ logError(1, "%s Wrong number of parameters!\n", tag);
+ res = ERROR_OP_NOT_ALLOW;
+ }
+ break;
+
+ case CMD_SSINITDATATEST: /* SS IX CX DATA TEST */
+ if (numberParam == 2) /* need to specify if stopOnFail */
+ res = production_test_ss_ix_cx(LIMITS_FILE, functionToTest[1], &todoDefault);
+ else {
+ logError(1, "%s Wrong number of parameters!\n", tag);
+ res = ERROR_OP_NOT_ALLOW;
+ }
+ break;
+
+ /*PRODUCTION TEST*/
+ case CMD_MAINTEST:
+ if (numberParam == 3) /* need to specify if stopOnFail and saveInit */
+ res = production_test_main(LIMITS_FILE, functionToTest[1], functionToTest[2], &todoDefault, INIT_FIELD);
+ else {
+ logError(1, "%s Wrong number of parameters!\n", tag);
+ res = ERROR_OP_NOT_ALLOW;
+ }
+ break;
+
+ case CMD_POWERCYCLE:
+ res = fts_chip_powercycle(info);
+ break;
+
+ default:
+ logError(1, "%s COMMAND ID NOT VALID!! Inset a value between 00 and 1E..\n", tag);
+ res = ERROR_OP_NOT_ALLOW;
+ break;
+ }
+
+ /*res2 = fts_enableInterrupt(); enabling the interrupt was disabled on purpose in this node because it can be used for testing procedure and between one step and another the interrupt wan to be kept disabled
+ if (res2 < 0) {
+ logError(0, "%s stm_driver_test_show: ERROR %08X\n", tag, (res2 | ERROR_ENABLE_INTER));
+ }*/
+ } else {
+ logError(1, "%s NO COMMAND SPECIFIED!!! do: 'echo [cmd_code] [args] > stm_fts_cmd' before looking for result!\n", tag);
+ res = ERROR_OP_NOT_ALLOW;
+ functionToTest = NULL;
+ }
+
+END: /* here start the reporting phase, assembling the data to send in the file node */
+ all_strbuff = (u8 *) 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 comand, comment if you want to repeat the last comand sent just doing a cat */
+ /* logError(0,"%s numberParameters = %d\n",tag, numberParam); */
+ kfree(all_strbuff);
+ kfree(functionToTest);
+ return count;
+
+}
+
+/*static DEVICE_ATTR(stm_driver_test, (S_IRWXU|S_IRWXG), stm_driver_test_show, stm_driver_test_store);*/
+static DEVICE_ATTR(stm_driver_test, (S_IRUGO | S_IWUSR | S_IWGRP), stm_driver_test_show, stm_driver_test_store);
+
+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
diff --git a/drivers/input/touchscreen/st/fts_fw.h b/drivers/input/touchscreen/st/fts_fw.h
new file mode 100644
index 000000000000..d928a06951ea
--- /dev/null
+++ b/drivers/input/touchscreen/st/fts_fw.h
@@ -0,0 +1,10 @@
+#ifndef FTS_FW_H
+#define FTS_FW_H
+/* This is an auto generated header file
+* --->Remember to change the name of the two variables!<--- */
+const uint32_t myArray_size;
+
+const uint8_t myArray[] = {
+};
+
+#endif
diff --git a/drivers/input/touchscreen/st/fts_gui.c b/drivers/input/touchscreen/st/fts_gui.c
new file mode 100644
index 000000000000..f695137ada09
--- /dev/null
+++ b/drivers/input/touchscreen/st/fts_gui.c
@@ -0,0 +1,359 @@
+#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/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/ftsTest.h"
+#include "fts_lib/ftsTime.h"
+#include "fts_lib/ftsTool.h"
+
+#ifdef SCRIPTLESS
+
+unsigned int data[CMD_RESULT_STR_LEN] = {0};
+unsigned char pAddress_i2c[CMD_RESULT_STR_LEN] = {0};
+int byte_count_read;
+char Out_buff[TSP_BUF_SIZE];
+
+/*I2C CMd functions: functions to interface with GUI without script */
+
+ssize_t fts_i2c_wr_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct fts_ts_info *info = i2c_get_clientdata(client);
+ int i;
+ char buff[16];
+ memset(Out_buff, 0x00, ARRAY_SIZE(Out_buff));
+ if (byte_count_read == 0) {
+ snprintf(Out_buff, sizeof(Out_buff), "{FAILED}");
+ return snprintf(buf, TSP_BUF_SIZE, "{%s}\n", Out_buff);
+ }
+#ifdef SCRIPTLESS_DEBUG
+ printk("%s:DATA READ {", __func__);
+ for (i = 0; i < byte_count_read; i++) {
+ printk(" %02X", (unsigned int)info->cmd_wr_result[i]);
+ if (i < (byte_count_read-1)) {
+ printk(" ");
+ }
+ }
+ printk("}\n");
+#endif
+ snprintf(buff, sizeof(buff), "{");
+ strlcat(Out_buff, buff, ARRAY_SIZE(Out_buff));
+ for (i = 0; i < (byte_count_read+2); i++) {
+ if ((i == 0)) {
+ char temp_byte_count_read = (byte_count_read >> 8) & 0xFF;
+ snprintf(buff, sizeof(buff), "%02X", temp_byte_count_read);
+ } else if (i == 1) {
+ char temp_byte_count_read = (byte_count_read) & 0xFF;
+ snprintf(buff, sizeof(buff), "%02X", temp_byte_count_read);
+
+ } else {
+ snprintf(buff, sizeof(buff), "%02X", info->cmd_wr_result[i-2]);
+ }
+ /* snprintf(buff, sizeof(buff), "%02X", info->cmd_wr_result[i]); */
+ strlcat(Out_buff, buff, ARRAY_SIZE(Out_buff));
+ if (i < (byte_count_read+1)) {
+ snprintf(buff, sizeof(buff), " ");
+ strlcat(Out_buff, buff, ARRAY_SIZE(Out_buff));
+ }
+ }
+ snprintf(buff, sizeof(buff), "}");
+ strlcat(Out_buff, buff, ARRAY_SIZE(Out_buff));
+ return snprintf(buf, TSP_BUF_SIZE, "%s\n", Out_buff);
+}
+
+ssize_t fts_i2c_wr_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int ret;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct fts_ts_info *info = i2c_get_clientdata(client);
+ unsigned char pAddress[8] = {0};
+ unsigned int byte_count = 0 ;
+ int i ;
+
+ unsigned int data[8] = {0};
+ memset(data, 0x00, ARRAY_SIZE(data));
+ memset(info->cmd_wr_result, 0x00, ARRAY_SIZE(info->cmd_wr_result));
+ sscanf(buf, "%x %x %x %x %x %x %x %x ", (data+7), (data), (data+1),
+ (data+2), (data+3), (data+4), (data+5), (data+6));
+
+ byte_count = data[7];
+
+ /*if (sizeof(buf) != byte_count )
+ {
+ printk("%s : Byte count is wrong\n",__func__);
+ return count;
+ }*/
+#ifdef SCRIPTLESS_DEBUG
+ printk("\n");
+ printk("%s: Input Data 1:", __func__);
+
+ for (i = 0 ; i < 7; i++) {
+ printk(" %02X", data[i]);
+ pAddress[i] = (unsigned char)data[i];
+ }
+ printk("\n");
+#else
+ for (i = 0 ; i < 7; i++) {
+ pAddress[i] = (unsigned char)data[i];
+ }
+#endif
+ byte_count_read = data[byte_count-1];
+ ret = fts_writeCmd(pAddress, 3);
+ msleep(20);
+ ret = fts_readCmd(&pAddress[3], (byte_count-4), info->cmd_wr_result,
+ byte_count_read);
+#ifdef SCRIPTLESS_DEBUG
+ printk("%s:DATA READ\n{", __func__);
+ for (i = 0; i < (2+byte_count_read); i++) {
+ if ((i == 0)) {
+ char temp_byte_count_read = (byte_count_read >> 8) & 0xFF;
+ printk("%02X", (unsigned int)temp_byte_count_read);
+ } else if (i == 1) {
+ char temp_byte_count_read = (byte_count_read) & 0xFF;
+ printk("%02X", (unsigned int)temp_byte_count_read);
+
+ } else {
+ printk("%02X", (unsigned int)info->cmd_read_result[i-2]);
+ }
+ if (i < (byte_count_read+1)) {
+ printk(" ");
+ }
+
+ }
+ printk("}\n");
+#endif
+ if (ret)
+ dev_err(dev, "Unable to read register\n");
+ return count;
+}
+
+ssize_t fts_i2c_read_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct fts_ts_info *info = i2c_get_clientdata(client);
+ int i ;
+ char buff[16];
+
+ memset(Out_buff, 0x00, ARRAY_SIZE(Out_buff));
+ if (byte_count_read == 0) {
+ snprintf(Out_buff, sizeof(Out_buff), "{FAILED}");
+ return snprintf(buf, TSP_BUF_SIZE, "{%s}\n", Out_buff);
+ }
+#ifdef SCRIPTLESS_DEBUG
+ printk("%s:DATA READ {", __func__);
+ for (i = 0; i < byte_count_read; i++) {
+ printk("%02X", (unsigned int)info->cmd_read_result[i]);
+ if (i < (byte_count_read-1)) {
+ printk(" ");
+ }
+ }
+ printk("}\n");
+#endif
+ snprintf(buff, sizeof(buff), "{");
+ strlcat(Out_buff, buff, ARRAY_SIZE(Out_buff));
+ for (i = 0; i < (byte_count_read+2); i++) {
+ if ((i == 0)) {
+ char temp_byte_count_read = (byte_count_read >> 8) & 0xFF;
+ snprintf(buff, sizeof(buff), "%02X", temp_byte_count_read);
+ } else if (i == 1) {
+ char temp_byte_count_read = (byte_count_read) & 0xFF;
+ snprintf(buff, sizeof(buff), "%02X", temp_byte_count_read);
+
+ } else {
+ snprintf(buff, sizeof(buff), "%02X", info->cmd_read_result[i-2]);
+ }
+ strlcat(Out_buff, buff, ARRAY_SIZE(Out_buff));
+ if (i < (byte_count_read+1)) {
+ snprintf(buff, sizeof(buff), " ");
+ strlcat(Out_buff, buff, ARRAY_SIZE(Out_buff));
+ }
+ }
+ snprintf(buff, sizeof(buff), "}");
+ strlcat(Out_buff, buff, ARRAY_SIZE(Out_buff));
+
+ return snprintf(buf, TSP_BUF_SIZE, "%s\n", Out_buff);
+}
+
+ssize_t fts_i2c_read_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int ret;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct fts_ts_info *info = i2c_get_clientdata(client);
+ unsigned char pAddress[8] = {0};
+ unsigned int byte_count = 0;
+ int i ;
+ unsigned int data[8] = {0};
+
+ byte_count_read = 0;
+ memset(data, 0x00, ARRAY_SIZE(data));
+ memset(info->cmd_read_result, 0x00, ARRAY_SIZE(info->cmd_read_result));
+ sscanf(buf, "%x %x %x %x %x %x %x %x ", (data+7), (data), (data+1), (data+2), (data+3), (data+4), (data+5), (data+6));
+ byte_count = data[7];
+
+ if (byte_count > 7) {
+#ifdef SCRIPTLESS_DEBUG
+ printk("%s : Byte count is more than 7\n", __func__);
+#endif
+ return count;
+ }
+ /*if (sizeof(buf) != byte_count )
+ {
+ printk("%s : Byte count is wrong\n",__func__);
+ return count;
+ }*/
+#ifdef SCRIPTLESS_DEBUG
+ printk("\n");
+ printk("%s: Input Data 1:", __func__);
+ for (i = 0 ; i < byte_count; i++) {
+ printk(" %02X", data[i]);
+ pAddress[i] = (unsigned char)data[i];
+ }
+ printk("\n");
+#else
+ for (i = 0 ; i < byte_count; i++) {
+ pAddress[i] = (unsigned char)data[i];
+ }
+#endif
+ byte_count_read = data[byte_count-1];
+ ret = fts_readCmd(pAddress, (byte_count-1), info->cmd_read_result, byte_count_read);
+#ifdef SCRIPTLESS_DEBUG
+ printk("%s:DATA READ\n{", __func__);
+ for (i = 0; i < (byte_count_read+2); i++) {
+ if ((i == 0)) {
+ char temp_byte_count_read = (byte_count_read >> 8) & 0xFF;
+ printk("%02X", (unsigned int)temp_byte_count_read);
+ } else if (i == 1) {
+ char temp_byte_count_read = (byte_count_read) & 0xFF;
+ printk("%02X", (unsigned int)temp_byte_count_read);
+
+ } else {
+ printk("%02X", (unsigned int)info->cmd_read_result[i-2]);
+ }
+ if (i < (byte_count_read+1)) {
+ printk(" ");
+ }
+ }
+ printk("}\n");
+#endif
+ if (ret)
+ dev_err(dev, "Unable to read register\n");
+ return count;
+}
+
+ssize_t fts_i2c_write_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct fts_ts_info *info = i2c_get_clientdata(client);
+ return snprintf(buf, TSP_BUF_SIZE, "%s", info->cmd_write_result);
+
+}
+
+ssize_t fts_i2c_write_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int ret;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct fts_ts_info *info = i2c_get_clientdata(client);
+ unsigned int byte_count = 0;
+ int i ;
+ memset(data, 0x00, ARRAY_SIZE(data));
+ memset(pAddress_i2c, 0x00, ARRAY_SIZE(pAddress_i2c));
+ memset(info->cmd_write_result, 0x00, ARRAY_SIZE(info->cmd_write_result));
+ sscanf(buf, "%x %x", data, (data + 1));
+ byte_count = data[0] << 8 | data[1];
+
+ if (byte_count <= ARRAY_SIZE(pAddress_i2c)) {
+ for (i = 0; i < (byte_count); i++) {
+ sscanf(&buf[3*(i+2)], "%x ", (data+i));
+ } } else {
+#ifdef SCRIPTLESS_DEBUG
+ printk("%s : message size is more than allowed limit of 512 bytes\n", __func__);
+#endif
+ snprintf(info->cmd_write_result, sizeof(info->cmd_write_result), "{Write NOT OK}\n");
+ }
+#ifdef SCRIPTLESS_DEBUG
+ printk("\n");
+ printk("%s: Byte_count= %02d | Count = %02d | size of buf:%02d\n", __func__, byte_count, (int)count, (int)sizeof(buf));
+ printk("%s: Input Data 1:", __func__);
+ for (i = 0 ; i < byte_count; i++) {
+ printk("%02X", data[i]);
+ pAddress_i2c[i] = (unsigned char)data[i];
+ }
+ printk("\n");
+#else
+ for (i = 0; i < byte_count; i++) {
+ pAddress_i2c[i] = (unsigned char)data[i];
+ }
+#endif
+ if ((pAddress_i2c[0] == 0xb3) && (pAddress_i2c[3] == 0xb1)) {
+ ret = fts_writeCmd(pAddress_i2c, 3);
+ msleep(20);
+ ret = fts_writeCmd(&pAddress_i2c[3], byte_count-3);
+ } else {
+ ret = fts_writeCmd(pAddress_i2c, byte_count);
+ }
+
+#ifdef SCRIPTLESS_DEBUG
+ printk("%s:DATA :", __func__);
+ for (i = 0; i < byte_count; i++) {
+ printk(" %02X", (unsigned int)pAddress_i2c[i]);
+ }
+ printk(" byte_count: %02X\n", byte_count);
+#endif
+ if (ret < 0) {
+ dev_err(dev, "{Write NOT OK}\n");
+ snprintf(info->cmd_write_result, sizeof(info->cmd_write_result), "{Write NOT OK}\n");
+ } else {
+ snprintf(info->cmd_write_result, sizeof(info->cmd_write_result), "{Write OK}\n");
+#ifdef SCRIPTLESS_DEBUG
+ printk("%s : {Write OK}\n", __func__);
+#endif
+ }
+ return count;
+}
+
+static DEVICE_ATTR(iread, (S_IWUSR|S_IWGRP), NULL, fts_i2c_read_store);
+static DEVICE_ATTR(iread_result, (S_IRUSR|S_IRGRP), fts_i2c_read_show, NULL);
+static DEVICE_ATTR(iwr, (S_IWUSR|S_IWGRP), NULL, fts_i2c_wr_store);
+static DEVICE_ATTR(iwr_result, (S_IRUSR|S_IRGRP), fts_i2c_wr_show, NULL);
+static DEVICE_ATTR(iwrite, (S_IWUSR|S_IWGRP), NULL, fts_i2c_write_store);
+static DEVICE_ATTR(iwrite_result, (S_IRUSR|S_IRGRP), fts_i2c_write_show, NULL);
+
+static struct attribute *i2c_cmd_attributes[] = {
+ &dev_attr_iread.attr,
+ &dev_attr_iread_result.attr,
+ &dev_attr_iwr.attr,
+ &dev_attr_iwr_result.attr,
+ &dev_attr_iwrite.attr,
+ &dev_attr_iwrite_result.attr,
+ NULL,
+};
+
+struct attribute_group i2c_cmd_attr_group = {
+ .attrs = i2c_cmd_attributes,
+};
+
+#endif
diff --git a/drivers/input/touchscreen/st/fts_lib/Makefile b/drivers/input/touchscreen/st/fts_lib/Makefile
new file mode 100644
index 000000000000..24eca48fc3cd
--- /dev/null
+++ b/drivers/input/touchscreen/st/fts_lib/Makefile
@@ -0,0 +1,7 @@
+#
+# Makefile for the FTS touchscreen driver.
+#
+
+obj-$(CONFIG_TOUCHSCREEN_ST_I2C) += ftsCompensation.o \
+ ftsCrossCompile.o ftsError.o ftsFrame.o ftsIO.o ftsTest.o \
+ ftsTime.o ftsTool.o ftsFlash.o ftsGesture.o
diff --git a/drivers/input/touchscreen/st/fts_lib/ftsCompensation.c b/drivers/input/touchscreen/st/fts_lib/ftsCompensation.c
new file mode 100644
index 000000000000..2ca0067f34b0
--- /dev/null
+++ b/drivers/input/touchscreen/st/fts_lib/ftsCompensation.c
@@ -0,0 +1,591 @@
+/*
+**************************************************************************
+** STMicroelectronics **
+**************************************************************************
+** marco.cali@st.com **
+**************************************************************************
+* *
+* FTS functions for getting Initialization Data *
+* *
+**************************************************************************
+**************************************************************************
+*/
+
+#include "ftsCrossCompile.h"
+#include "ftsCompensation.h"
+#include "ftsError.h"
+#include "ftsFrame.h"
+#include "ftsHardware.h"
+#include "ftsIO.h"
+#include "ftsSoftware.h"
+#include "ftsTool.h"
+
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/platform_device.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <stdarg.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/serio.h>
+#include <linux/time.h>
+#include <linux/pm.h>
+#include <linux/delay.h>
+#include <linux/ctype.h>
+#include <linux/gpio.h>
+#include <linux/i2c.h>
+#include <linux/i2c-dev.h>
+#include <linux/fs.h>
+#include <linux/uaccess.h>
+#include <linux/power_supply.h>
+#include <linux/firmware.h>
+#include <linux/regulator/consumer.h>
+#include <linux/of_gpio.h>
+/* #include <linux/sec_sysfs.h> */
+
+static char tag[8] = "[ FTS ]\0";
+
+chipInfo ftsInfo;
+
+int requestCompensationData(u16 type)
+{
+ int retry = 0;
+ int ret;
+ u16 answer;
+
+ int event_to_search[3];
+ u8 readEvent[FIFO_EVENT_SIZE];
+
+ u8 cmd[3] = { FTS_CMD_REQU_COMP_DATA, 0x00, 0x00 };
+ /* B8 is the command for asking compensation data */
+ u16ToU8(type, &cmd[1]);
+
+ event_to_search[0] = (int)EVENTID_COMP_DATA_READ;
+ event_to_search[1] = cmd[1];
+ event_to_search[2] = cmd[2];
+
+ while (retry < COMP_DATA_READ_RETRY) {
+ logError(0, "%s %s", tag, printHex("Command = ", cmd, 3));
+ ret = fts_writeFwCmd(cmd, 3);
+ /* send the request to the chip to load in memory the Compensation Data */
+ if (ret < OK) {
+ logError(1, "%s requestCompensationData: ERROR %02X\n", tag, ERROR_I2C_W);
+ return ERROR_I2C_W;
+ }
+ ret = pollForEvent(event_to_search, 3, readEvent, TIMEOUT_REQU_COMP_DATA);
+ if (ret < OK) {
+ logError(0, "%s Event did not Found at %d attemp! \n", tag, retry+1);
+ retry += 1;
+ } else {
+ retry = 0;
+ break;
+ }
+ }
+
+ if (retry == COMP_DATA_READ_RETRY) {
+ logError(1, "%s requestCompensationData: ERROR %02X\n", tag, ERROR_TIMEOUT);
+ return ERROR_TIMEOUT;
+ }
+
+ u8ToU16_le(&readEvent[1], &answer);
+
+ if (answer == type)
+ return OK;
+ logError(1, "%s The event found has a different type of Compensation data ERROR %02X \n", tag, ERROR_DIFF_COMP_TYPE);
+ return ERROR_DIFF_COMP_TYPE;
+
+}
+
+int readCompensationDataHeader(u16 type, DataHeader *header, u16 *address)
+{
+
+ u16 offset = ADDR_FRAMEBUFFER_DATA;
+ u16 answer;
+ u8 data[COMP_DATA_HEADER];
+
+ if (readCmdU16(FTS_CMD_FRAMEBUFFER_R, offset, data, COMP_DATA_HEADER, DUMMY_FRAMEBUFFER) < 0) {
+ logError(1, "%s readCompensationDataHeader: ERROR %02X \n", tag, ERROR_I2C_R);
+ return ERROR_I2C_R;
+ }
+ logError(0, "%s Read Data Header done! \n", tag);
+
+ if (data[0] != HEADER_SIGNATURE) {
+ logError(1, "%s readCompensationDataHeader: ERROR %02X The Header Signature was wrong! %02X != %02X \n", tag, ERROR_WRONG_COMP_SIGN, data[0], HEADER_SIGNATURE);
+ return ERROR_WRONG_COMP_SIGN;
+ }
+
+ u8ToU16_le(&data[1], &answer);
+
+ if (answer != type) {
+ logError(1, "%s readCompensationDataHeader: ERROR %02X\n", tag, ERROR_DIFF_COMP_TYPE);
+ return ERROR_DIFF_COMP_TYPE;
+ }
+
+ logError(0, "%s Type of Compensation data OK! \n", tag);
+
+ header->type = type;
+ header->force_node = (int)data[4];
+ header->sense_node = (int)data[5];
+
+ *address = offset + COMP_DATA_HEADER;
+
+ return OK;
+
+}
+
+int readMutualSenseGlobalData(u16 *address, MutualSenseData *global)
+{
+
+ u8 data[COMP_DATA_GLOBAL];
+
+ logError(0, "%s Address for Global data= %02X \n", tag, *address);
+
+ if (readCmdU16(FTS_CMD_FRAMEBUFFER_R, *address, data, COMP_DATA_GLOBAL, DUMMY_FRAMEBUFFER) < 0) {
+ logError(1, "%s readMutualSenseGlobalData: ERROR %02X\n", tag, ERROR_I2C_R);
+ return ERROR_I2C_R;
+ }
+ logError(0, "%s Global data Read !\n", tag);
+
+ global->tuning_ver = data[0];
+ global->cx1 = data[1];
+
+ logError(0, "%s tuning_ver = %d CX1 = %d \n", tag, global->tuning_ver, global->cx1);
+
+ *address += COMP_DATA_GLOBAL;
+ return OK;
+
+}
+
+int readMutualSenseNodeData(u16 address, MutualSenseData *node)
+{
+
+ int size = node->header.force_node*node->header.sense_node;
+
+ logError(0, "%s Address for Node data = %02X \n", tag, address);
+
+ node->node_data = (u8 *)kmalloc(size*(sizeof(u8)), GFP_KERNEL);
+
+ if (node->node_data == NULL) {
+ logError(1, "%s readMutualSenseNodeData: ERROR %02X", tag, ERROR_ALLOC);
+ return ERROR_ALLOC;
+ }
+
+ logError(0, "%s Node Data to read %d bytes \n", tag, size);
+
+ if (readCmdU16(FTS_CMD_FRAMEBUFFER_R, address, node->node_data, size, DUMMY_FRAMEBUFFER) < 0) {
+ logError(1, "%s readMutualSenseNodeData: ERROR %02X \n", tag, ERROR_I2C_R);
+ return ERROR_I2C_R;
+ }
+ node->node_data_size = size;
+
+ logError(0, "%s Read node data ok! \n", tag);
+
+ return size;
+
+}
+
+int readMutualSenseCompensationData(u16 type, MutualSenseData *data)
+{
+
+ int ret;
+ u16 address;
+
+ if (!(type == MS_TOUCH_ACTIVE || type == MS_TOUCH_LOW_POWER ||
+ type == MS_TOUCH_ULTRA_LOW_POWER || type == MS_KEY)) {
+ logError(1, "%s readMutualSenseCompensationData: Choose a MS type of compensation data ERROR %02X\n", tag, ERROR_OP_NOT_ALLOW);
+ return ERROR_OP_NOT_ALLOW;
+ }
+
+ ret = requestCompensationData(type);
+ if (ret < 0) {
+ logError(1, "%s readMutualSenseCompensationData: ERROR %02X\n", tag, ERROR_REQU_COMP_DATA);
+ return (ret|ERROR_REQU_COMP_DATA);
+ }
+
+ ret = readCompensationDataHeader(type, &(data->header), &address);
+ if (ret < 0) {
+ logError(1, "%s readMutualSenseCompensationData: ERROR %02X\n", tag, ERROR_COMP_DATA_HEADER);
+ return (ret|ERROR_COMP_DATA_HEADER);
+ }
+
+ ret = readMutualSenseGlobalData(&address, data);
+ if (ret < 0) {
+ logError(1, "%s readMutualSenseCompensationData: ERROR %02X \n", tag, ERROR_COMP_DATA_GLOBAL);
+ return (ret|ERROR_COMP_DATA_GLOBAL);
+ }
+
+ ret = readMutualSenseNodeData(address, data);
+ if (ret < 0) {
+ logError(1, "%s readMutualSenseCompensationData: ERROR %02X\n", tag, ERROR_COMP_DATA_NODE);
+ return (ret|ERROR_COMP_DATA_NODE);
+ }
+
+ return OK;
+
+}
+
+int readSelfSenseGlobalData(u16 *address, SelfSenseData *global)
+{
+
+ u8 data[COMP_DATA_GLOBAL];
+
+ logError(0, "%s Address for Global data= %02X \n", tag, *address);
+
+ if (readCmdU16(FTS_CMD_FRAMEBUFFER_R, *address, data, COMP_DATA_GLOBAL, DUMMY_FRAMEBUFFER) < 0) {
+ logError(1, "%s readSelfSenseGlobalData: ERROR %02X \n", tag, ERROR_I2C_R);
+ return ERROR_I2C_R;
+ }
+
+ logError(0, "%s Global data Read !\n", tag);
+
+ global->tuning_ver = data[0];
+ global->f_ix1 = data[1];
+ global->s_ix1 = data[2];
+ global->f_cx1 = data[3];
+ global->s_cx1 = data[4];
+ global->f_max_n = data[5];
+ global->s_max_n = data[6];
+
+ logError(0, "%s tuning_ver = %d f_ix1 = %d s_ix1 = %d f_cx1 = %d s_cx1 = %d \n", tag, global->tuning_ver, global->f_ix1, global->s_ix1, global->f_cx1, global->s_cx1);
+ logError(0, "%s max_n = %d s_max_n = %d \n", tag, global->f_max_n, global->s_max_n);
+
+ *address += COMP_DATA_GLOBAL;
+
+ return OK;
+
+}
+
+int readSelfSenseNodeData(u16 address, SelfSenseData *node)
+{
+
+ int size = node->header.force_node*2+node->header.sense_node*2;
+ u8 data[size];
+
+ node->ix2_fm = (u8 *)kmalloc(node->header.force_node*(sizeof(u8)), GFP_KERNEL);
+ node->cx2_fm = (u8 *)kmalloc(node->header.force_node*(sizeof(u8)), GFP_KERNEL);
+ node->ix2_sn = (u8 *)kmalloc(node->header.sense_node*(sizeof(u8)), GFP_KERNEL);
+ node->cx2_sn = (u8 *)kmalloc(node->header.sense_node*(sizeof(u8)), GFP_KERNEL);
+
+ if (node->ix2_fm == NULL || node->cx2_fm == NULL || node->ix2_sn == NULL
+ || node->cx2_sn == NULL) {
+ logError(1, "%s readSelfSenseNodeData: ERROR %02X", tag, ERROR_ALLOC);
+ return ERROR_ALLOC;
+ }
+
+ logError(0, "%s Address for Node data = %02X \n", tag, address);
+
+ logError(0, "%s Node Data to read %d bytes \n", tag, size);
+
+ if (readCmdU16(FTS_CMD_FRAMEBUFFER_R, address, data, size, DUMMY_FRAMEBUFFER) < 0) {
+ logError(1, "%s readSelfSenseNodeData: ERROR %02X\n", tag, ERROR_I2C_R);
+ return ERROR_I2C_R;
+ }
+
+ logError(0, "%s Read node data ok! \n", tag);
+
+ memcpy(node->ix2_fm, data, node->header.force_node);
+ memcpy(node->ix2_sn, &data[node->header.force_node], node->header.sense_node);
+ memcpy(node->cx2_fm, &data[node->header.force_node + node->header.sense_node], node->header.force_node);
+ memcpy(node->cx2_sn, &data[node->header.force_node*2 + node->header.sense_node], node->header.sense_node);
+
+ return OK;
+
+}
+
+int readSelfSenseCompensationData(u16 type, SelfSenseData *data)
+{
+
+ int ret;
+ u16 address;
+
+ if (!(type == SS_TOUCH || type == SS_KEY || type == SS_HOVER || type == SS_PROXIMITY)) {
+ logError(1, "%s readSelfSenseCompensationData: Choose a SS type of compensation data ERROR %02X\n", tag, ERROR_OP_NOT_ALLOW);
+ return ERROR_OP_NOT_ALLOW;
+ }
+
+ ret = requestCompensationData(type);
+ if (ret < 0) {
+ logError(1, "%s readSelfSenseCompensationData: ERROR %02X\n", tag, ERROR_REQU_COMP_DATA);
+ return (ret|ERROR_REQU_COMP_DATA);
+ }
+
+ ret = readCompensationDataHeader(type, &(data->header), &address);
+ if (ret < 0) {
+ logError(1, "%s readSelfSenseCompensationData: ERROR %02X\n", tag, ERROR_COMP_DATA_HEADER);
+ return (ret|ERROR_COMP_DATA_HEADER);
+ }
+
+ ret = readSelfSenseGlobalData(&address, data);
+ if (ret < 0) {
+ logError(1, "%s readSelfSenseCompensationData: ERROR %02X\n", tag, ERROR_COMP_DATA_GLOBAL);
+ return (ret|ERROR_COMP_DATA_GLOBAL);
+ }
+
+ ret = readSelfSenseNodeData(address, data);
+ if (ret < 0) {
+ logError(1, "%s readSelfSenseCompensationData: ERROR %02X\n", tag, ERROR_COMP_DATA_NODE);
+ return (ret|ERROR_COMP_DATA_NODE);
+ }
+
+ return OK;
+
+}
+
+int readGeneralGlobalData(u16 address, GeneralData *global)
+{
+ u8 data[COMP_DATA_GLOBAL];
+
+ if (readCmdU16(FTS_CMD_FRAMEBUFFER_R, address, data, COMP_DATA_GLOBAL, DUMMY_FRAMEBUFFER) < 0) {
+ logError(1, "%s readGeneralGlobalData: ERROR %02X \n", tag, ERROR_I2C_R);
+ return ERROR_I2C_R;
+ }
+
+ global->ftsd_lp_timer_cal0 = data[0];
+ global->ftsd_lp_timer_cal1 = data[1];
+ global->ftsd_lp_timer_cal2 = data[2];
+ global->ftsd_lp_timer_cal3 = data[3];
+ global->ftsa_lp_timer_cal0 = data[4];
+ global->ftsa_lp_timer_cal1 = data[5];
+
+ return OK;
+
+}
+
+int readGeneralCompensationData(u16 type, GeneralData *data)
+{
+
+ int ret;
+ u16 address;
+
+ if (!(type == GENERAL_TUNING)) {
+ logError(1, "%s readGeneralCompensationData: Choose a GENERAL type of compensation data ERROR %02X\n", tag, ERROR_OP_NOT_ALLOW);
+ return ERROR_OP_NOT_ALLOW;
+ }
+
+ ret = requestCompensationData(type);
+ if (ret < 0) {
+ logError(1, "%s readGeneralCompensationData: ERROR %02X \n", tag, ERROR_REQU_COMP_DATA);
+ return ERROR_REQU_COMP_DATA;
+ }
+
+ ret = readCompensationDataHeader(type, &(data->header), &address);
+ if (ret < 0) {
+ logError(1, "%s readGeneralCompensationData: ERROR %02X\n", tag, ERROR_COMP_DATA_HEADER);
+ return ERROR_COMP_DATA_HEADER;
+ }
+
+ ret = readGeneralGlobalData(address, data);
+ if (ret < 0) {
+ logError(1, "%s readGeneralCompensationData: ERROR %02X\n", tag, ERROR_COMP_DATA_GLOBAL);
+ return ERROR_COMP_DATA_GLOBAL;
+ }
+
+ return OK;
+
+}
+
+int defaultChipInfo(int i2cError)
+{
+ int i;
+ logError(0, "%s Setting default Chip Info... \n", tag);
+ ftsInfo.u32_echoEn = 0x00000000;
+ ftsInfo.u8_msScrConfigTuneVer = 0;
+ ftsInfo.u8_ssTchConfigTuneVer = 0;
+ ftsInfo.u8_msScrCxmemTuneVer = 0;
+ ftsInfo.u8_ssTchCxmemTuneVer = 0;
+ if (i2cError == 1) {
+ ftsInfo.u16_fwVer = 0xFFFF;
+ ftsInfo.u16_cfgId = 0xFFFF;
+ for (i = 0; i < EXTERNAL_RELEASE_INFO_SIZE; i++) {
+ ftsInfo.u8_extReleaseInfo[i] = 0xFF;
+ }
+ } else {
+ ftsInfo.u16_fwVer = 0x0000;
+ ftsInfo.u16_cfgId = 0x0000;
+ for (i = 0; i < EXTERNAL_RELEASE_INFO_SIZE; i++) {
+ ftsInfo.u8_extReleaseInfo[i] = 0x00;
+ }
+ }
+ ftsInfo.u32_mpPassFlag = INIT_FIELD;
+ logError(0, "%s default Chip Info DONE! \n", tag);
+ return OK;
+
+}
+
+int readChipInfo(int doRequest)
+{
+ int ret, i;
+ u16 answer;
+ u8 data[CHIP_INFO_SIZE+3];
+ /* +3 because need to read all the field of the struct plus the signature and 2 address bytes */
+ int index = 0;
+
+ logError(0, "%s Starting Read Chip Info... \n", tag);
+ if (doRequest == 1) {
+ ret = requestCompensationData(CHIP_INFO);
+ if (ret < 0) {
+ logError(1, "%s readChipInfo: ERROR %02X\n", tag, ERROR_REQU_COMP_DATA);
+ ret = (ret | ERROR_REQU_COMP_DATA);
+ goto FAIL;
+ }
+ }
+
+ logError(0, "%s Byte to read = %d bytes \n", tag, CHIP_INFO_SIZE+3);
+
+ if (readCmdU16(FTS_CMD_FRAMEBUFFER_R, ADDR_FRAMEBUFFER_DATA, data, CHIP_INFO_SIZE+3, DUMMY_FRAMEBUFFER) < 0) {
+ logError(1, "%s readChipInfo: ERROR %02X\n", tag, ERROR_I2C_R);
+ ret = ERROR_I2C_R;
+ goto FAIL;
+ }
+
+ logError(0, "%s Read data ok! \n", tag);
+
+ logError(0, "%s Starting parsing of data... \n", tag);
+
+ if (data[0] != HEADER_SIGNATURE) {
+ logError(1, "%s readChipInfo: ERROR %02X The Header Signature was wrong! %02X != %02X \n", tag, ERROR_WRONG_COMP_SIGN, data[0], HEADER_SIGNATURE);
+ ret = ERROR_WRONG_COMP_SIGN;
+ goto FAIL;
+ }
+
+ u8ToU16_le(&data[1], &answer);
+
+ if (answer != CHIP_INFO) {
+ logError(1, "%s readChipInfo: ERROR %02X\n", tag, ERROR_DIFF_COMP_TYPE);
+ ret = ERROR_DIFF_COMP_TYPE;
+ goto FAIL;
+ }
+
+ index += 3;
+ ftsInfo.u8_loadCnt = data[index++];
+ ftsInfo.u8_infoVer = data[index++];
+ u8ToU16(&data[index], &ftsInfo.u16_ftsdId);
+ index += 2;
+ ftsInfo.u8_ftsdVer = data[index++];
+ ftsInfo.u8_ftsaId = data[index++];
+ ftsInfo.u8_ftsaVer = data[index++];
+ ftsInfo.u8_tchRptVer = data[index++];
+
+ logError(1, "%s External Release = ", tag);
+ for (i = 0; i < EXTERNAL_RELEASE_INFO_SIZE; i++) {
+ ftsInfo.u8_extReleaseInfo[i] = data[index++];
+ logError(1, "%02X ", ftsInfo.u8_extReleaseInfo[i]);
+ }
+ logError(1, "\n");
+
+ for (i = 0; i < sizeof(ftsInfo.u8_custInfo); i++) {
+ ftsInfo.u8_custInfo[i] = data[index++];
+ }
+
+ u8ToU16(&data[index], &ftsInfo.u16_fwVer);
+ index += 2;
+ logError(1, "%s FW VERSION = %04X \n", tag, ftsInfo.u16_fwVer);
+
+ u8ToU16(&data[index], &ftsInfo.u16_cfgId);
+ index += 2;
+ logError(1, "%s CONFIG ID = %04X \n", tag, ftsInfo.u16_cfgId);
+
+ ftsInfo.u32_projId = ((data[index + 3] & 0x000000FF) << 24) + ((data[index + 2] & 0x000000FF) << 16) + ((data[index + 1] & 0x000000FF) << 8) + (data[index] & 0x000000FF);
+ index += 4;
+
+ u8ToU16(&data[index], &ftsInfo.u16_scrXRes);
+ index += 2;
+
+ u8ToU16(&data[index], &ftsInfo.u16_scrYRes);
+ index += 2;
+
+ ftsInfo.u8_scrForceLen = data[index++];
+ logError(1, "%s Force Len = %d \n", tag, ftsInfo.u8_scrForceLen);
+
+ ftsInfo.u8_scrSenseLen = data[index++];
+ logError(1, "%s Sense Len = %d \n", tag, ftsInfo.u8_scrSenseLen);
+
+ for (i = 0; i < 8; i++) {
+ ftsInfo.u64_scrForceEn[i] = data[index++];
+ }
+
+ for (i = 0; i < 8; i++) {
+ ftsInfo.u64_scrSenseEn[i] = data[index++];
+ }
+
+ ftsInfo.u8_msKeyLen = data[index++];
+ logError(1, "%s MS Key Len = %d \n", tag, ftsInfo.u8_msKeyLen);
+
+ for (i = 0; i < 8; i++) {
+ ftsInfo.u64_msKeyForceEn[i] = data[index++];
+ }
+
+ for (i = 0; i < 8; i++) {
+ ftsInfo.u64_msKeySenseEn[i] = data[index++];
+ }
+
+ ftsInfo.u8_ssKeyLen = data[index++];
+ logError(1, "%s SS Key Len = %d \n", tag, ftsInfo.u8_ssKeyLen);
+
+ for (i = 0; i < 8; i++) {
+ ftsInfo.u64_ssKeyForceEn[i] = data[index++];
+ }
+
+ for (i = 0; i < 8; i++) {
+ ftsInfo.u64_ssKeySenseEn[i] = data[index++];
+ }
+
+ ftsInfo.u8_frcTchXLen = data[index++];
+
+ ftsInfo.u8_frcTchYLen = data[index++];
+
+ for (i = 0; i < 8; i++) {
+ ftsInfo.u64_frcTchForceEn[i] = data[index++];
+ }
+
+ for (i = 0; i < 8; i++) {
+ ftsInfo.u64_frcTchSenseEn[i] = data[index++];
+ }
+
+ ftsInfo.u8_msScrConfigTuneVer = data[index++];
+ logError(1, "%s CFG MS TUNING VERSION = %02X \n", tag, ftsInfo.u8_msScrConfigTuneVer);
+ ftsInfo.u8_msScrLpConfigTuneVer = data[index++];
+ ftsInfo.u8_msScrHwulpConfigTuneVer = data[index++];
+ ftsInfo.u8_msKeyConfigTuneVer = data[index++];
+ ftsInfo.u8_ssTchConfigTuneVer = data[index++];
+ logError(1, "%s CFG SS TUNING VERSION = %02X \n", tag, ftsInfo.u8_ssTchConfigTuneVer);
+ ftsInfo.u8_ssKeyConfigTuneVer = data[index++];
+ ftsInfo.u8_ssHvrConfigTuneVer = data[index++];
+ ftsInfo.u8_frcTchConfigTuneVer = data[index++];
+ ftsInfo.u8_msScrCxmemTuneVer = data[index++];
+ logError(1, "%s CX MS TUNING VERSION = %02X \n", tag, ftsInfo.u8_msScrCxmemTuneVer);
+ ftsInfo.u8_msScrLpCxmemTuneVer = data[index++];
+ ftsInfo.u8_msScrHwulpCxmemTuneVer = data[index++];
+ ftsInfo.u8_msKeyCxmemTuneVer = data[index++];
+ ftsInfo.u8_ssTchCxmemTuneVer = data[index++];
+ logError(1, "%s CX SS TUNING VERSION = %02X \n", tag, ftsInfo.u8_ssTchCxmemTuneVer);
+ ftsInfo.u8_ssKeyCxmemTuneVer = data[index++];
+ ftsInfo.u8_ssHvrCxmemTuneVer = data[index++];
+ ftsInfo.u8_frcTchCxmemTuneVer = data[index++];
+ ftsInfo.u32_mpPassFlag = ((data[index + 3] & 0x000000FF) << 24) + ((data[index + 2] & 0x000000FF) << 16) + ((data[index + 1] & 0x000000FF) << 8) + (data[index] & 0x000000FF);
+ index += 4;
+ logError(1, "%s MP SIGNATURE = %08X \n", tag, ftsInfo.u32_mpPassFlag);
+ ftsInfo.u32_featEn = ((data[index + 3] & 0x000000FF) << 24) + ((data[index + 2] & 0x000000FF) << 16) + ((data[index + 1] & 0x000000FF) << 8) + (data[index] & 0x000000FF);
+ index += 4;
+ ftsInfo.u32_echoEn = ((data[index + 3] & 0x000000FF) << 24) + ((data[index + 2] & 0x000000FF) << 16) + ((data[index + 1] & 0x000000FF) << 8) + (data[index] & 0x000000FF);
+ index += 4;
+ logError(1, "%s FEATURES = %08X \n", tag, ftsInfo.u32_echoEn);
+
+ logError(1, "%s Parsed %d bytes! \n", tag, index);
+
+ if (index != CHIP_INFO_SIZE + 3) {
+ logError(1, "%s readChipInfo: index = %d different from %d ERROR %02X\n", tag, index, CHIP_INFO_SIZE+3, ERROR_OP_NOT_ALLOW);
+ return ERROR_OP_NOT_ALLOW;
+ }
+
+ logError(1, "%s Chip Info Read DONE!\n", tag);
+ return OK;
+
+FAIL:
+ defaultChipInfo(isI2cError(ret));
+ return ret;
+
+}
diff --git a/drivers/input/touchscreen/st/fts_lib/ftsCompensation.h b/drivers/input/touchscreen/st/fts_lib/ftsCompensation.h
new file mode 100644
index 000000000000..c4cc5913fc18
--- /dev/null
+++ b/drivers/input/touchscreen/st/fts_lib/ftsCompensation.h
@@ -0,0 +1,146 @@
+/*
+
+**************************************************************************
+** STMicroelectronics **
+**************************************************************************
+** marco.cali@st.com **
+**************************************************************************
+* *
+* FTS functions for getting Initialization Data *
+* *
+**************************************************************************
+**************************************************************************
+
+*/
+
+#include "ftsCrossCompile.h"
+#include "ftsSoftware.h"
+
+#define COMP_DATA_READ_RETRY 2
+
+/* Bytes dimension of Compensation Data Format */
+
+#define COMP_DATA_HEADER 8
+#define COMP_DATA_GLOBAL 8
+
+#define HEADER_SIGNATURE 0xA5
+
+/* Possible Compensation/Frame Data Type */
+#define GENERAL_TUNING 0x0100
+#define MS_TOUCH_ACTIVE 0x0200
+#define MS_TOUCH_LOW_POWER 0x0400
+#define MS_TOUCH_ULTRA_LOW_POWER 0x0800
+#define MS_KEY 0x1000
+#define SS_TOUCH 0x2000
+#define SS_KEY 0x4000
+#define SS_HOVER 0x8000
+#define SS_PROXIMITY 0x0001
+#define CHIP_INFO 0xFFFF
+
+#define TIMEOUT_REQU_COMP_DATA 1000 /* ms */
+
+/* CHIP INFO */
+#define CHIP_INFO_SIZE 138/* bytes to read from framebuffer (exclude the signature and the type because already checked during the reading) */
+#define EXTERNAL_RELEASE_INFO_SIZE 8/* bytes */
+
+typedef struct {
+ int force_node, sense_node;
+ u16 type;
+} DataHeader;
+
+typedef struct {
+ DataHeader header;
+ u8 tuning_ver;
+ u8 cx1;
+ u8 *node_data;
+ int node_data_size;
+} MutualSenseData;
+
+typedef struct {
+ DataHeader header;
+ u8 tuning_ver;
+ u8 f_ix1, s_ix1;
+ u8 f_cx1, s_cx1;
+ u8 f_max_n, s_max_n;
+
+ u8 *ix2_fm;
+ u8 *ix2_sn;
+ u8 *cx2_fm;
+ u8 *cx2_sn;
+
+} SelfSenseData;
+
+typedef struct {
+ DataHeader header;
+ u8 ftsd_lp_timer_cal0;
+ u8 ftsd_lp_timer_cal1;
+ u8 ftsd_lp_timer_cal2;
+
+ u8 ftsd_lp_timer_cal3;
+ u8 ftsa_lp_timer_cal0;
+ u8 ftsa_lp_timer_cal1;
+
+} GeneralData;
+
+typedef struct {
+ u8 u8_loadCnt; /* 03 - Load Counter */
+ u8 u8_infoVer; /* 04 - New chip info version */
+ u16 u16_ftsdId; /* 05 - FTSD ID */
+ u8 u8_ftsdVer; /* 07 - FTSD version */
+ u8 u8_ftsaId; /* 08 - FTSA ID */
+ u8 u8_ftsaVer; /* 09 - FTSA version */
+ u8 u8_tchRptVer; /* 0A - Touch report version (e.g. ST, Samsung etc) */
+ u8 u8_extReleaseInfo[EXTERNAL_RELEASE_INFO_SIZE]; /* 0B - External release information */
+ u8 u8_custInfo[12]; /* 13 - Customer information */
+ u16 u16_fwVer; /* 1F - Firmware version */
+ u16 u16_cfgId; /* 21 - Configuration ID */
+ u32 u32_projId; /* 23 - Project ID */
+ u16 u16_scrXRes; /* 27 - X resolution on main screen */
+ u16 u16_scrYRes; /* 29 - Y resolution on main screen */
+ u8 u8_scrForceLen; /* 2B - Number of force channel on main screen */
+ u8 u8_scrSenseLen; /* 2C - Number of sense channel on main screen */
+ u8 u64_scrForceEn[8]; /* 2D - Force channel enabled on main screen */
+ u8 u64_scrSenseEn[8]; /* 35 - Sense channel enabled on main screen */
+ u8 u8_msKeyLen; /* 3D - Number of MS Key channel */
+ u8 u64_msKeyForceEn[8]; /* 3E - MS Key force channel enable */
+ u8 u64_msKeySenseEn[8]; /* 46 - MS Key sense channel enable */
+ u8 u8_ssKeyLen; /* 4E - Number of SS Key channel */
+ u8 u64_ssKeyForceEn[8]; /* 4F - SS Key force channel enable */
+ u8 u64_ssKeySenseEn[8]; /* 57 - SS Key sense channel enable */
+ u8 u8_frcTchXLen; /* 5F - Number of force touch force channel */
+ u8 u8_frcTchYLen; /* 60 - Number of force touch sense channel */
+ u8 u64_frcTchForceEn[8]; /* 61 - Force touch force channel enable */
+ u8 u64_frcTchSenseEn[8]; /* 69 - Force touch sense channel enable */
+ u8 u8_msScrConfigTuneVer; /* 71 - MS screen tuning version in config */
+ u8 u8_msScrLpConfigTuneVer; /* 72 - MS screen LP mode tuning version in config */
+ u8 u8_msScrHwulpConfigTuneVer; /* 73 - MS screen ultra low power mode tuning version in config */
+ u8 u8_msKeyConfigTuneVer; /* 74 - MS Key tuning version in config */
+ u8 u8_ssTchConfigTuneVer; /* 75 - SS touch tuning version in config */
+ u8 u8_ssKeyConfigTuneVer; /* 76 - SS Key tuning version in config */
+ u8 u8_ssHvrConfigTuneVer; /* 77 - SS hover tuning version in config */
+ u8 u8_frcTchConfigTuneVer; /* 78 - Force touch tuning version in config */
+ u8 u8_msScrCxmemTuneVer; /* 79 - MS screen tuning version in cxmem */
+ u8 u8_msScrLpCxmemTuneVer; /* 7A - MS screen LP mode tuning version in cxmem */
+ u8 u8_msScrHwulpCxmemTuneVer; /* 7B - MS screen ultra low power mode tuning version in cxmem */
+ u8 u8_msKeyCxmemTuneVer; /* 7C - MS Key tuning version in cxmem */
+ u8 u8_ssTchCxmemTuneVer; /* 7D - SS touch tuning version in cxmem */
+ u8 u8_ssKeyCxmemTuneVer; /* 7E - SS Key tuning version in cxmem */
+ u8 u8_ssHvrCxmemTuneVer; /* 7F - SS hover tuning version in cxmem */
+ u8 u8_frcTchCxmemTuneVer; /* 80 - Force touch tuning version in cxmem */
+ u32 u32_mpPassFlag; /* 81 - Mass production pass flag */
+ u32 u32_featEn; /* 85 - Supported features */
+ u32 u32_echoEn; /* 89 - enable of particular features: first bit is Echo Enables */
+} chipInfo;
+
+int requestCompensationData(u16 type);
+int readCompensationDataHeader(u16 type, DataHeader *header, u16 *address);
+int readMutualSenseGlobalData(u16 *address, MutualSenseData *global);
+int readMutualSenseNodeData(u16 address, MutualSenseData *node);
+int readMutualSenseCompensationData(u16 type, MutualSenseData *data);
+int readSelfSenseGlobalData(u16 *address, SelfSenseData *global);
+int readSelfSenseNodeData(u16 address, SelfSenseData *node);
+int readSelfSenseCompensationData(u16 type, SelfSenseData *data);
+int readGeneralGlobalData(u16 address, GeneralData *global);
+int readGeneralCompensationData(u16 type, GeneralData *data);
+int defaultChipInfo(int i2cError);
+int readChipInfo(int doRequest);
diff --git a/drivers/input/touchscreen/st/fts_lib/ftsCrossCompile.c b/drivers/input/touchscreen/st/fts_lib/ftsCrossCompile.c
new file mode 100644
index 000000000000..502dace75e4f
--- /dev/null
+++ b/drivers/input/touchscreen/st/fts_lib/ftsCrossCompile.c
@@ -0,0 +1,43 @@
+#include "ftsCrossCompile.h"
+#include "ftsError.h"
+
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/platform_device.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/serio.h>
+#include <linux/init.h>
+#include <linux/pm.h>
+#include <linux/delay.h>
+#include <linux/ctype.h>
+#include <linux/gpio.h>
+#include <linux/i2c.h>
+#include <linux/i2c-dev.h>
+#include <linux/fs.h>
+#include <linux/uaccess.h>
+#include <linux/power_supply.h>
+#include <linux/firmware.h>
+#include <linux/regulator/consumer.h>
+#include <linux/of_gpio.h>
+/* #include <linux/sec_sysfs.h> */
+#include <linux/i2c.h>
+#include <linux/i2c-dev.h>
+#include <linux/spi/spidev.h>
+#include <linux/fcntl.h>
+#include <linux/syscalls.h>
+
+/* static char tag[8]="[ FTS ]\0"; */
+void *stmalloc(size_t size)
+{
+ return kmalloc(size, GFP_KERNEL);
+
+}
+
+void stfree(void *ptr)
+{
+ kfree(ptr);
+}
diff --git a/drivers/input/touchscreen/st/fts_lib/ftsCrossCompile.h b/drivers/input/touchscreen/st/fts_lib/ftsCrossCompile.h
new file mode 100644
index 000000000000..8b287dd342f8
--- /dev/null
+++ b/drivers/input/touchscreen/st/fts_lib/ftsCrossCompile.h
@@ -0,0 +1,34 @@
+/* #define NDK */
+/* #define DEBUG */
+
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/platform_device.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/serio.h>
+#include <linux/init.h>
+#include <linux/pm.h>
+#include <linux/delay.h>
+#include <linux/ctype.h>
+#include <linux/gpio.h>
+#include <linux/i2c.h>
+#include <linux/i2c-dev.h>
+#include <linux/fs.h>
+#include <linux/uaccess.h>
+#include <linux/power_supply.h>
+#include <linux/firmware.h>
+#include <linux/regulator/consumer.h>
+#include <linux/of_gpio.h>
+/* #include <linux/sec_sysfs.h> */
+#include <linux/i2c.h>
+#include <linux/i2c-dev.h>
+#include <linux/spi/spidev.h>
+#include <linux/fcntl.h>
+#include <linux/syscalls.h>
+
+void *stmalloc(size_t size);
+void stfree(void *ptr);
diff --git a/drivers/input/touchscreen/st/fts_lib/ftsError.c b/drivers/input/touchscreen/st/fts_lib/ftsError.c
new file mode 100644
index 000000000000..844e5019fec6
--- /dev/null
+++ b/drivers/input/touchscreen/st/fts_lib/ftsError.c
@@ -0,0 +1,105 @@
+/*
+***************************************************************************
+* STMicroelectronics
+**************************************************************************
+* marco.cali@st.com
+**************************************************************************
+*
+* FTS error/info kernel log reporting
+*
+**************************************************************************
+**************************************************************************
+*/
+
+#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/gpio.h>
+#include <linux/of_gpio.h>
+#include <linux/regulator/consumer.h>
+
+#include "../fts.h"
+#include "ftsCrossCompile.h"
+#include "ftsError.h"
+#include "ftsIO.h"
+#include "ftsTool.h"
+
+void logError(int force, const char *msg, ...)
+{
+ if (force == 1
+#ifdef DEBUG
+ || 1
+#endif
+ ) {
+ va_list args;
+ va_start(args, msg);
+ vprintk(msg, args);
+ va_end(args);
+ }
+}
+
+int isI2cError(int error)
+{
+ if (((error & 0x000000FF) >= (ERROR_I2C_R & 0x000000FF)) && ((error & 0x000000FF) <= (ERROR_I2C_O & 0x000000FF)))
+ return 1;
+ else
+ return 0;
+}
+
+int errorHandler(u8 *event, int size)
+{
+ int res = OK;
+ struct fts_ts_info *info = NULL;
+
+ if (getClient() != NULL)
+ info = i2c_get_clientdata(getClient());
+
+ if (info != NULL && event != NULL && size > 1 && event[0] == EVENTID_ERROR_EVENT) {
+ logError(1, "%s errorHandler: Starting handling...\n", tag);
+ switch (event[1])
+ /* TODO: write an error log for undefinied command subtype 0xBA*/
+ {
+ case EVENT_TYPE_ESD_ERROR: /* esd */
+ res = fts_chip_powercycle(info);
+ if (res < OK) {
+ logError(1, "%s errorHandler: Error performing powercycle ERROR %08X\n", tag, res);
+ }
+
+ res = fts_system_reset();
+ if (res < OK) {
+ logError(1, "%s errorHandler: Cannot reset the device ERROR %08X\n", tag, res);
+ }
+ res = (ERROR_HANDLER_STOP_PROC|res);
+ break;
+
+ case EVENT_TYPE_WATCHDOG_ERROR: /* watchdog */
+ res = fts_system_reset();
+ if (res < OK) {
+ logError(1, "%s errorHandler: Cannot reset the device ERROR %08X\n", tag, res);
+ }
+ res = (ERROR_HANDLER_STOP_PROC|res);
+ break;
+
+ default:
+ logError(1, "%s errorHandler: No Action taken! \n", tag);
+ break;
+
+ }
+ logError(1, "%s errorHandler: handling Finished! res = %08X\n", tag, res);
+ return res;
+ }
+ logError(1, "%s errorHandler: event Null or not correct size! ERROR %08X \n", tag, ERROR_OP_NOT_ALLOW);
+ return ERROR_OP_NOT_ALLOW;
+}
diff --git a/drivers/input/touchscreen/st/fts_lib/ftsError.h b/drivers/input/touchscreen/st/fts_lib/ftsError.h
new file mode 100644
index 000000000000..fc8fa5003158
--- /dev/null
+++ b/drivers/input/touchscreen/st/fts_lib/ftsError.h
@@ -0,0 +1,75 @@
+/*
+**************************************************************************
+** STMicroelectronics
+**************************************************************************
+** marco.cali@st.com
+**************************************************************************
+*
+* FTS error/info kernel log reporting
+*
+**************************************************************************
+**************************************************************************
+*/
+
+
+/*FIRST LEVEL ERROR CODE*/
+#define OK ((int)0x00000000) /*No ERROR*/
+#define ERROR_ALLOC ((int)0x80000001) /*allocation of memory failed*/
+#define ERROR_I2C_R ((int)0x80000002) /*i2c read failed*/
+#define ERROR_I2C_W ((int)0x80000003) /*i2c write failed*/
+#define ERROR_I2C_WR ((int)0x80000004) /*i2c write/read failed*/
+#define ERROR_I2C_O ((int)0x80000005) /*error during opening a i2c device*/
+#define ERROR_OP_NOT_ALLOW ((int)0x80000006) /*operation not allowed*/
+#define ERROR_TIMEOUT ((int)0x80000007) /*timeout expired! exceed the max number of retries or the max waiting time*/
+#define ERROR_FILE_NOT_FOUND ((int)0x80000008) /*the file that i want to open is not found*/
+#define ERROR_FILE_PARSE ((int)0x80000009) /*error during parsing the file*/
+#define ERROR_FILE_READ ((int)0x8000000A) /*error during reading the file*/
+#define ERROR_LABEL_NOT_FOUND ((int)0x8000000B) /*label not found*/
+#define ERROR_FW_NO_UPDATE ((int)0x8000000C) /*fw in the chip newer than the one in the memmh*/
+#define ERROR_FLASH_UNKNOWN ((int)0x8000000D) /*flash status busy or unknown*/
+
+/*SECOND LEVEL ERROR CODE*/
+#define ERROR_DISABLE_INTER ((int)0x80000200) /*unable to disable the interrupt*/
+#define ERROR_ENABLE_INTER ((int)0x80000300) /*unable to activate the interrup*/
+#define ERROR_READ_B2 ((int)0x80000400) /*B2 command failed*/
+#define ERROR_GET_OFFSET ((int)0x80000500) /*unable to read an offset from memory*/
+#define ERROR_GET_FRAME_DATA ((int)0x80000600) /*unable to retrieve the data of a required frame*/
+#define ERROR_DIFF_COMP_TYPE ((int)0x80000700) /*FW answers with an event that has a different address respect the request done*/
+#define ERROR_WRONG_COMP_SIGN ((int)0x80000800) /*the signature of the compensation data is not A5*/
+#define ERROR_SENSE_ON_FAIL ((int)0x80000900) /*the command Sense On failed*/
+#define ERROR_SENSE_OFF_FAIL ((int)0x80000A00) /*the command Sense Off failed*/
+#define ERROR_SYSTEM_RESET_FAIL ((int)0x80000B00) /*the command SYSTEM RESET failed*/
+#define ERROR_FLASH_NOT_READY ((int)0x80000C00) /*flash status not ready within a timeout*/
+#define ERROR_FW_VER_READ ((int)0x80000D00) /*unable to retrieve fw_vers or the config_id*/
+#define ERROR_GESTURE_ENABLE_FAIL ((int)0x80000E00) /*unable to enable/disable the gesture*/
+#define ERROR_GESTURE_START_ADD ((int)0x80000F00) /*unable to start to add custom gesture*/
+#define ERROR_GESTURE_FINISH_ADD ((int)0x80001000) /*unable to finish to add custom gesture*/
+#define ERROR_GESTURE_DATA_ADD ((int)0x80001100) /*unable to add custom gesture data*/
+#define ERROR_GESTURE_REMOVE ((int)0x80001200) /*unable to remove custom gesture data*/
+#define ERROR_FEATURE_ENABLE_DISABLE ((int)0x80001300) /*unable to enable/disable a feature mode in the IC*/
+/*THIRD LEVEL ERROR CODE*/
+#define ERROR_CH_LEN ((int)0x80010000) /*unable to retrieve the force and/or sense length*/
+#define ERROR_REQU_COMP_DATA ((int)0x80020000) /*compensation data request failed*/
+#define ERROR_COMP_DATA_HEADER ((int)0x80030000) /*unable to retrieve the compensation data header*/
+#define ERROR_COMP_DATA_GLOBAL ((int)0x80040000) /*unable to retrieve the global compensation data*/
+#define ERROR_COMP_DATA_NODE ((int)0x80050000) /*unable to retrieve the compensation data for each node*/
+#define ERROR_TEST_CHECK_FAIL ((int)0x80060000) /*check of production limits or of fw answers failed*/
+#define ERROR_MEMH_READ ((int)0x80070000) /*memh reading failed*/
+#define ERROR_FLASH_BURN_FAILED ((int)0x80080000) /*flash burn failed*/
+#define ERROR_MS_TUNING ((int)0x80090000) /*ms tuning failed*/
+#define ERROR_SS_TUNING ((int)0x800A0000) /*ss tuning failed*/
+#define ERROR_LP_TIMER_TUNING ((int)0x800B0000) /*lp timer calibration failed*/
+#define ERROR_SAVE_CX_TUNING ((int)0x800C0000) /*save cx data to flash failed*/
+#define ERROR_HANDLER_STOP_PROC ((int)0x800D0000) /*stop the poll of the FIFO if particular errors are found*/
+#define ERROR_CHECK_ECHO_FAIL ((int)0x800E0000) /*unable to retrieve echo event*/
+
+/*FOURTH LEVEL ERROR CODE*/
+#define ERROR_PROD_TEST_DATA ((int)0x81000000) /*production data test failed*/
+#define ERROR_FLASH_PROCEDURE ((int)0x82000000) /*complete flash procedure failed*/
+#define ERROR_PROD_TEST_ITO ((int)0x83000000) /*production ito test failed*/
+#define ERROR_PROD_TEST_INITIALIZATION ((int)0x84000000) /*production initialization test failed*/
+#define ERROR_GET_INIT_STATUS ((int)0x85000000) /*mismatch of the MS or SS tuning_version*/
+
+void logError(int force, const char *msg, ...);
+int isI2cError(int error);
+int errorHandler(u8 *event, int size);
diff --git a/drivers/input/touchscreen/st/fts_lib/ftsFlash.c b/drivers/input/touchscreen/st/fts_lib/ftsFlash.c
new file mode 100644
index 000000000000..59c73f4c4edb
--- /dev/null
+++ b/drivers/input/touchscreen/st/fts_lib/ftsFlash.c
@@ -0,0 +1,1071 @@
+/*
+
+ **************************************************************************
+ ** STMicroelectronics **
+ **************************************************************************
+ ** marco.cali@st.com **
+ **************************************************************************
+ * *
+ * FTS API for Flashing the IC *
+ * *
+ **************************************************************************
+ **************************************************************************
+
+ */
+
+#include "ftsCrossCompile.h"
+#include "ftsCompensation.h"
+#include "ftsError.h"
+#include "ftsFlash.h"
+#include "ftsFrame.h"
+#include "ftsIO.h"
+#include "ftsSoftware.h"
+#include "ftsTest.h"
+#include "ftsTime.h"
+#include "ftsTool.h"
+#include "../fts.h" /* needed for the FW_H_FILE define */
+
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/platform_device.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <stdarg.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/serio.h>
+#include <linux/time.h>
+#include <linux/pm.h>
+#include <linux/delay.h>
+#include <linux/ctype.h>
+#include <linux/gpio.h>
+#include <linux/i2c.h>
+#include <linux/i2c-dev.h>
+#include <linux/fs.h>
+#include <linux/uaccess.h>
+#include <linux/power_supply.h>
+#include <linux/firmware.h>
+#include <linux/regulator/consumer.h>
+#include <linux/of_gpio.h>
+/* #include <linux/sec_sysfs.h> */
+
+#ifdef FW_H_FILE
+#include <../fts_fw.h>
+#endif
+
+/* static char tag[8] = "[ FTS ]\0"; */
+extern chipInfo ftsInfo;
+
+int getFirmwareVersion(u16 *fw_vers, u16 *config_id)
+{
+ u8 fwvers[DCHIP_FW_VER_BYTE];
+ u8 confid[CONFIG_ID_BYTE];
+ int res;
+
+ res = readCmdU16(FTS_CMD_HW_REG_R, DCHIP_FW_VER_ADDR, fwvers, DCHIP_FW_VER_BYTE, DUMMY_HW_REG);
+ if (res < OK) {
+ logError(1, "%s getFirmwareVersion: unable to read fw_version ERROR %02X\n", tag, ERROR_FW_VER_READ);
+ return (res | ERROR_FW_VER_READ);
+ }
+
+ u8ToU16(fwvers, fw_vers); /* fw version use big endian */
+ if (*fw_vers != 0) { /* if fw_version is 00 00 means that there is no firmware running in the chip therefore will be impossible find the config_id */
+ res = readB2(CONFIG_ID_ADDR, confid, CONFIG_ID_BYTE);
+ if (res < OK) {
+ logError(1, "%s getFirmwareVersion: unable to read config_id ERROR %02X\n", tag, ERROR_FW_VER_READ);
+ return (res | ERROR_FW_VER_READ);
+ }
+ u8ToU16(confid, config_id); /* config id use little endian */
+ } else {
+ *config_id = 0x0000;
+ }
+
+ logError(0, "%s FW VERS = %04X\n", tag, *fw_vers);
+ logError(0, "%s CONFIG ID = %04X\n", tag, *config_id);
+ return OK;
+
+}
+
+#ifdef FTM3_CHIP
+
+int flash_status(void)
+{
+ u8 cmd[2] = {FLASH_CMD_READSTATUS, 0x00};
+ u8 readData;
+
+ logError(0, "%s Reading flash_status...\n", tag);
+ if (fts_readCmd(cmd, 2, &readData, FLASH_STATUS_BYTES) < 0) {
+ logError(1, "%s flash_status: ERROR % 02X\n", tag, ERROR_I2C_R);
+ return ERROR_I2C_R;
+ }
+
+ readData &= 0x01;
+ /* logError(0, "%s flash_status = %d\n", tag,readData); */
+ return (int) readData;
+
+}
+
+int flash_status_ready(void)
+{
+
+ int status = flash_status();
+
+ if (status == ERROR_I2C_R) {
+ logError(1, "%s flash_status_ready: ERROR % 02X\n", tag, ERROR_I2C_R);
+ return ERROR_I2C_R;
+ }
+
+ if (status != FLASH_READY) {
+ logError(1, "%s flash_status_ready: flash busy or unknown STATUS = % 02X\n", tag, status);
+ return ERROR_FLASH_UNKNOWN;
+ }
+
+ return FLASH_READY;
+
+}
+
+int wait_for_flash_ready(void)
+{
+ int status;
+ int(*code)(void);
+
+ code = flash_status_ready;
+
+ logError(0, "%s Waiting for flash ready...\n", tag);
+ status = attempt_function(code, FLASH_WAIT_BEFORE_RETRY, FLASH_RETRY_COUNT);
+
+ if (status != FLASH_READY) {
+ logError(1, "%s wait_for_flash_ready: ERROR % 02X\n", tag, ERROR_FLASH_NOT_READY);
+ return (status | ERROR_FLASH_NOT_READY);
+ }
+
+ logError(0, "%s Flash ready!\n", tag);
+ return OK;
+}
+
+int flash_unlock(void)
+{
+
+ int status;
+ u8 cmd[3] = {FLASH_CMD_UNLOCK, FLASH_UNLOCK_CODE0, FLASH_UNLOCK_CODE1}; /* write the comand to perform the unlock */
+
+ logError(0, "%s Try to unlock flash...\n", tag);
+ status = wait_for_flash_ready();
+
+ if (status != OK) {
+ logError(1, "%s flash_unlock: ERROR % 02X\n", tag, ERROR_FLASH_NOT_READY);
+ return (status | ERROR_FLASH_NOT_READY); /* Flash not ready within the choosen time, better exit! */
+ }
+
+ logError(0, "%s Command unlock ...\n", tag);
+ if (fts_writeCmd(cmd, sizeof (cmd)) < 0) {
+ logError(1, "%s flash_unlock: ERROR % 02X\n", tag, ERROR_I2C_W);
+ return ERROR_I2C_W;
+ }
+
+ status = wait_for_flash_ready();
+
+ if (status != OK) {
+ logError(1, "%s flash_unlock: ERROR % 02X\n", tag, ERROR_FLASH_NOT_READY);
+ return (status | ERROR_FLASH_NOT_READY); /* Flash not ready within the choosen time, better exit! */
+ }
+
+ logError(0, "%s Unlock flash DONE!\n", tag);
+
+ return OK;
+
+}
+
+/*int parseMemhFile(const char *pathToFile, u8** data, int* length, int dimension)
+{
+
+ int i = 0;
+ unsigned long ul;
+ u8* buff = NULL;
+ int fd = -1;
+ int n, size, pointer = 0;
+ char *data_file, *line;
+ const struct firmware *fw = NULL;
+ struct device *dev = NULL;
+
+ line = (char *) kmalloc(11 * sizeof (char), GFP_KERNEL);
+ if (line == NULL) {
+ logError(1, "%s parseMemhFile: ERROR %02X\n", tag, ERROR_ALLOC);
+ return ERROR_ALLOC;
+ }
+
+ logError(0, "%s parseMemhFile: allocating %d bytes\n", tag, dimension);
+ buff = (u8*) kmalloc(dimension * sizeof (u8), GFP_KERNEL);
+ if (buff == NULL) {
+ logError(1, "%s parseMemhFile: ERROR %02X\n", tag, ERROR_ALLOC);
+ return ERROR_ALLOC;
+ }
+
+ dev = getDev();
+ if (dev != NULL)
+ fd = request_firmware(&fw, pathToFile, dev);
+
+ if (fd == 0) {
+ size = fw->size;
+ logError(0, "%s The size of the firmware file is %d bytes...\n", tag, size);
+ data_file = (char *) fw->data;
+ logError(0, "%s Start to reading %s...\n", tag, pathToFile);
+
+ while (size - pointer > 0 && (i * 4 + 4) <= dimension) {
+ if (readLine(&data_file[pointer], &line, size - pointer, &n) < 0) {
+ break;
+ }
+ pointer += n;
+ logError(0, "%s Pointer= %d riga = %s\n", tag, pointer, line);
+ ul = simple_strtoul(line, NULL, 16);
+
+ buff[i * 4] = (u8) ((ul & 0x000000FF) >> 0);
+ buff[i * 4 + 1] = (u8) ((ul & 0x0000FF00) >> 8);
+ buff[i * 4 + 2] = (u8) ((ul & 0x00FF0000) >> 16);
+ buff[i * 4 + 3] = (u8) ((ul & 0xFF000000) >> 24);
+ i++;
+ }
+
+ kfree(line);
+
+ *length = i * 4;
+ if (*length < dimension) {
+ logError(1, "%s parseMemhFile: Read only %d instead of %d... ERROR %02X\n", tag, *length, dimension, ERROR_FILE_PARSE);
+ release_firmware(fw);
+ return ERROR_FILE_PARSE;
+ }
+ *data = buff;
+
+ logError(0, "%s READ DONE %d bytes!\n", tag, *length);
+ release_firmware(fw);
+ return OK;
+ } else {
+ logError(1, "%s parseProductionTestLimits: ERROR %02X\n", tag, ERROR_FILE_NOT_FOUND);
+ return ERROR_FILE_NOT_FOUND;
+ }
+
+}*/
+
+int parseBinFile(const char *pathToFile, u8 **data, int *length, int dimension)
+{
+
+ int fd = -1;
+ int fw_size = 0;
+ u8 *fw_data = NULL;
+
+#ifndef FW_H_FILE
+ const struct firmware *fw = NULL;
+ struct device *dev = NULL;
+ dev = getDev();
+
+ if (dev != NULL)
+ fd = request_firmware(&fw, pathToFile, dev);
+ else {
+ logError(1, "%s parseBinFile: No device found! ERROR %02X\n", ERROR_FILE_PARSE);
+ return ERROR_FILE_PARSE;
+ }
+#else
+ fd = 0;
+#endif
+
+ if (fd == 0) {
+#ifndef FW_H_FILE
+ fw_size = fw->size;
+ fw_data = (u8 *) (fw->data);
+#else
+ fw_size = FW_SIZE_NAME;
+ fw_data = (u8 *) FW_ARRAY_NAME;
+#endif
+ if (fw_size - FW_HEADER_SIZE != FW_SIZE) {
+ logError(1, "%s parseBinFile: Read only %d instead of %d... ERROR %02X\n", tag, fw_size, FW_SIZE, ERROR_FILE_PARSE);
+#ifndef FW_H_FILE
+ release_firmware(fw);
+#endif
+ return ERROR_FILE_PARSE;
+ }
+ *data = (u8 *) kmalloc(dimension * sizeof (u8), GFP_KERNEL);
+ if (*data == NULL) {
+ logError(1, "%s parseBinFile: ERROR %02X\n", tag, ERROR_ALLOC);
+#ifndef FW_H_FILE
+ release_firmware(fw);
+#endif
+ return ERROR_ALLOC;
+ }
+
+ memcpy(*data, ((u8 *) (fw_data) + FW_HEADER_SIZE), dimension);
+ *length = dimension;
+
+ logError(0, "%s READ FW DONE %d bytes!\n", tag, *length);
+#ifndef FW_H_FILE
+ release_firmware(fw);
+#endif
+ return OK;
+ }
+ logError(1, "%s parseBinFile: File Not Found! ERROR %02X\n", tag, ERROR_FILE_NOT_FOUND);
+ return ERROR_FILE_NOT_FOUND;
+}
+
+int readFwFile(const char *path, Firmware *fw, int keep_cx)
+{
+ int res;
+ int size;
+
+ if (keep_cx) {
+ size = FW_SIZE - FW_CX_SIZE;
+ logError(1, "%s readFwFile: Selected 124k Configuration!\n", tag);
+ } else {
+ size = FW_SIZE;
+ logError(1, "%s readFwFile: Selected 128k Configuration!\n", tag);
+ }
+
+ /* res = parseMemhFile(path, &(fw->data), &(fw->data_size), size); */
+ res = parseBinFile(path, &(fw->data), &(fw->data_size), size);
+ if (res < OK) {
+ logError(1, "%s readFwFile: ERROR %02X\n", tag, ERROR_MEMH_READ);
+ return (res | ERROR_MEMH_READ);
+ }
+
+ fw->fw_ver = (u16) (((fw->data[FW_VER_MEMH_BYTE1] & 0x00FF) << 8) + (fw->data[FW_VER_MEMH_BYTE0] & 0x00FF));
+ fw->config_id = (u16) (((fw->data[(FW_CODE_SIZE) + FW_OFF_CONFID_MEMH_BYTE1] & 0x00FF) << 8) + (fw->data[(FW_CODE_SIZE) + FW_OFF_CONFID_MEMH_BYTE0] & 0x00FF));
+
+ logError(0, "%s FW VERS File = %04X\n", tag, fw->fw_ver);
+ logError(0, "%s CONFIG ID File = %04X\n", tag, fw->config_id);
+ return OK;
+
+}
+
+int fillMemory(u32 address, u8 *data, int size)
+{
+
+ int remaining = size;
+ int toWrite = 0;
+
+ u8 *buff = (u8 *) kmalloc((MEMORY_CHUNK + 3) * sizeof (u8), GFP_KERNEL);
+ if (buff == NULL) {
+ logError(1, "%s fillMemory: ERROR %02X\n", tag, ERROR_ALLOC);
+ return ERROR_ALLOC;
+ }
+
+ while (remaining > 0) {
+ if (remaining >= MEMORY_CHUNK) {
+ if ((address + MEMORY_CHUNK) < FLASH_ADDR_SWITCH_CMD) {
+ buff[0] = FLASH_CMD_WRITE_LOWER_64;
+ toWrite = MEMORY_CHUNK;
+ remaining -= MEMORY_CHUNK;
+ } else {
+ if (address < FLASH_ADDR_SWITCH_CMD) {
+ int delta = FLASH_ADDR_SWITCH_CMD - address;
+ buff[0] = FLASH_CMD_WRITE_LOWER_64;
+ toWrite = delta;
+ remaining -= delta;
+ } else {
+ buff[0] = FLASH_CMD_WRITE_UPPER_64;
+ toWrite = MEMORY_CHUNK;
+ remaining -= MEMORY_CHUNK;
+ }
+ }
+ } else {
+ if ((address + remaining) < FLASH_ADDR_SWITCH_CMD) {
+ buff[0] = FLASH_CMD_WRITE_LOWER_64;
+ toWrite = remaining;
+ remaining = 0;
+ } else {
+ if (address < FLASH_ADDR_SWITCH_CMD) {
+ int delta = FLASH_ADDR_SWITCH_CMD - address;
+ buff[0] = FLASH_CMD_WRITE_LOWER_64;
+ toWrite = delta;
+ remaining -= delta;
+ } else {
+ buff[0] = FLASH_CMD_WRITE_UPPER_64;
+ toWrite = remaining;
+ remaining = 0;
+ }
+ }
+ }
+
+ buff[1] = (u8) ((address & 0x0000FF00) >> 8);
+ buff[2] = (u8) (address & 0x000000FF);
+ memcpy(buff + 3, data, toWrite);
+ logError(0, "%s Command = %02X , address = %02X %02X, bytes = %d\n", tag, buff[0], buff[1], buff[2], toWrite);
+ if (fts_writeCmd(buff, 3 + toWrite) < 0) {
+ logError(1, "%s fillMemory: ERROR %02X\n", tag, ERROR_I2C_W);
+ return ERROR_I2C_W;
+ }
+
+ address += toWrite;
+ data += toWrite;
+
+ }
+ return OK;
+}
+
+int flash_burn(Firmware fw, int force_burn)
+{
+ u8 cmd;
+ int res;
+
+ if (!force_burn && (ftsInfo.u16_fwVer >= fw.fw_ver) && (ftsInfo.u16_cfgId >= fw.config_id)) {
+ logError(1, "%s flash_burn: Firmware in the chip newer or equal to the one to burn! NO UPDATE ERROR %02X\n", tag, ERROR_FW_NO_UPDATE);
+ return (ERROR_FW_NO_UPDATE | ERROR_FLASH_BURN_FAILED);
+ }
+
+ /* programming procedure start */
+
+ logError(0, "%s Programming Procedure for flashing started:\n\n", tag);
+
+ logError(0, "%s 1) SYSTEM RESET:\n", tag);
+ res = fts_system_reset();
+ if (res < 0) {
+ logError(1, "%s system reset FAILED!\n", tag);
+ if (res != (ERROR_SYSTEM_RESET_FAIL | ERROR_TIMEOUT)) /* if there is no firmware i will not get the controller ready event and there will be a timeout but i can keep going, but if there is an I2C error i have to exit */
+ return (res | ERROR_FLASH_BURN_FAILED);
+ } else
+ logError(0, "%s system reset COMPLETED!\n\n", tag);
+
+ logError(0, "%s 2) FLASH UNLOCK:\n", tag);
+ res = flash_unlock();
+ if (res < 0) {
+ logError(1, "%s flash unlock FAILED! ERROR %02X\n", tag, ERROR_FLASH_BURN_FAILED);
+ return (res | ERROR_FLASH_BURN_FAILED);
+ }
+ logError(0, "%s flash unlock COMPLETED!\n\n", tag);
+
+ /* Write the lower part of the Program RAM */
+ logError(0, "%s 3) PREPARING DATA FOR FLASH BURN:\n", tag);
+
+ res = fillMemory(FLASH_ADDR_CODE, fw.data, fw.data_size);
+ if (res < 0) {
+ logError(1, "%s Error During filling the memory! ERROR %02X\n", tag, ERROR_FLASH_BURN_FAILED);
+ return (res | ERROR_FLASH_BURN_FAILED);
+ }
+ logError(0, "%s Data copy COMPLETED!\n\n", tag);
+
+ logError(0, "%s 4) ERASE FLASH:\n", tag);
+ res = wait_for_flash_ready();
+ if (res < 0) {
+ logError(1, "%s Flash not ready! ERROR %02X\n", tag, ERROR_FLASH_BURN_FAILED);
+ return (res | ERROR_FLASH_BURN_FAILED);
+ }
+
+ logError(0, "%s Command erase ...\n", tag);
+ cmd = FLASH_CMD_ERASE;
+ if (fts_writeCmd(&cmd, 1) < 0) {
+ logError(1, "%s Error during erasing flash! ERROR %02X\n", tag, ERROR_FLASH_BURN_FAILED);
+ return (ERROR_I2C_W | ERROR_FLASH_BURN_FAILED);
+ }
+
+ res = wait_for_flash_ready();
+ if (res < 0) {
+ logError(1, "%s Flash not ready 2! ERROR %02X\n", tag, ERROR_FLASH_BURN_FAILED);
+ return (res | ERROR_FLASH_BURN_FAILED);
+ }
+
+ logError(0, "%s Flash erase COMPLETED!\n\n", tag);
+
+ logError(0, "%s 5) BURN FLASH:\n", tag);
+ logError(0, "%s Command burn ...\n", tag);
+ cmd = FLASH_CMD_BURN;
+ if (fts_writeCmd(&cmd, 1) < 0) {
+ logError(1, "%s Error during burning data! ERROR %02X\n", tag, ERROR_FLASH_BURN_FAILED);
+ return (ERROR_I2C_W | ERROR_FLASH_BURN_FAILED);
+ }
+
+ res = wait_for_flash_ready();
+ if (res < 0) {
+ logError(1, "%s Flash not ready! ERROR %02X\n", tag, ERROR_FLASH_BURN_FAILED);
+ return (res | ERROR_FLASH_BURN_FAILED);
+ }
+
+ logError(0, "%s Flash burn COMPLETED!\n\n", tag);
+
+ logError(0, "%s 6) SYSTEM RESET:\n", tag);
+ res = fts_system_reset();
+ if (res < 0) {
+ logError(1, "%s system reset FAILED! ERROR %02X\n", tag, ERROR_FLASH_BURN_FAILED);
+ return (res | ERROR_FLASH_BURN_FAILED);
+ }
+ logError(0, "%s system reset COMPLETED!\n\n", tag);
+
+ logError(0, "%s 7) FINAL CHECK:\n", tag);
+ res = readChipInfo(0);
+ if (res < 0) {
+ logError(1, "%s flash_burn: Unable to retrieve Chip INFO! ERROR %02X\n", tag, ERROR_FLASH_BURN_FAILED);
+ return (res | ERROR_FLASH_BURN_FAILED);
+ }
+
+ if ((ftsInfo.u16_fwVer != fw.fw_ver) && (ftsInfo.u16_cfgId != fw.config_id)) {
+ logError(1, "%s Firmware in the chip different from the one that was burn! fw: %x != %x , conf: %x != %x\n", tag, ftsInfo.u16_fwVer, fw.fw_ver, ftsInfo.u16_cfgId, fw.config_id);
+ return ERROR_FLASH_BURN_FAILED;
+ }
+
+ logError(0, "%s Final check OK! fw: %02X , conf: %02X\n", tag, ftsInfo.u16_fwVer, ftsInfo.u16_cfgId);
+
+ return OK;
+}
+
+int flashProcedure(const char *path, int force, int keep_cx)
+{
+ Firmware fw;
+ int res;
+
+ fw.data = NULL;
+ logError(0, "%s Reading Fw file...\n", tag);
+ res = readFwFile(path, &fw, keep_cx);
+ if (res < OK) {
+ logError(1, "%s flashProcedure: ERROR %02X\n", tag, (res | ERROR_FLASH_PROCEDURE));
+ kfree(fw.data);
+ return (res | ERROR_FLASH_PROCEDURE);
+ }
+ logError(0, "%s Fw file read COMPLETED!\n", tag);
+
+ logError(0, "%s Starting flashing procedure...\n", tag);
+ res = flash_burn(fw, force);
+ if (res < OK && res != (ERROR_FW_NO_UPDATE | ERROR_FLASH_BURN_FAILED)) {
+ logError(1, "%s flashProcedure: ERROR %02X\n", tag, ERROR_FLASH_PROCEDURE);
+ kfree(fw.data);
+ return (res | ERROR_FLASH_PROCEDURE);
+ }
+ logError(0, "%s flashing procedure Finished!\n", tag);
+ kfree(fw.data);
+
+ /* cleanUp(0); //after talking with Kusuma, the SenseOn should be issued only at the very end of the initialization process, if senso on here it can trigger autotune protection */
+ return res;
+}
+
+#else
+
+int wait_for_flash_ready(u8 type)
+{
+ u8 cmd[2] = {FLASH_CMD_READ_REGISTER, type};
+ u8 readData;
+ int i, res = -1;
+
+ logError(0, "%s Waiting for flash ready ...\n", tag);
+ for (i = 0; i < FLASH_RETRY_COUNT && res != 0; i++) {
+ if (fts_readCmd(cmd, sizeof (cmd), &readData, 1) < 0) {
+ logError(1, "%s wait_for_flash_ready: ERROR % 02X\n", tag, ERROR_I2C_W);
+ } else{
+ res = readData & 0x80;
+ /* logError(0, "%s flash status = %d \n", tag, res); */
+ }
+ msleep(FLASH_WAIT_BEFORE_RETRY);
+ }
+
+ if (i == FLASH_RETRY_COUNT && res != 0) {
+ logError(1, "%s Wait for flash TIMEOUT! ERROR %02X\n", tag, ERROR_TIMEOUT);
+ return ERROR_TIMEOUT;
+ }
+
+ logError(0, "%s Flash READY!\n", tag);
+ return OK;
+}
+
+int fts_warm_boot(void)
+{
+
+ u8 cmd[4] = {FTS_CMD_HW_REG_W, 0x00, 0x00, WARM_BOOT_VALUE}; /* write the command to perform the warm boot */
+ u16ToU8_be(ADDR_WARM_BOOT, &cmd[1]);
+
+ logError(0, "%s Command warm boot ...\n", tag);
+ if (fts_writeCmd(cmd, sizeof (cmd)) < 0) {
+ logError(1, "%s flash_unlock: ERROR % 02X\n", tag, ERROR_I2C_W);
+ return ERROR_I2C_W;
+ }
+
+ logError(0, "%s Warm boot DONE!\n", tag);
+
+ return OK;
+}
+
+int parseBinFile(const char *pathToFile, Firmware *fwData, int keep_cx)
+{
+
+ int fd = -1;
+ int dimension, index = 0;
+ u32 temp;
+ u8 *data;
+ int res, i, fw_size;
+
+#ifndef FW_H_FILE
+ const struct firmware *fw = NULL;
+ struct device *dev = NULL;
+ dev = getDev();
+
+ if (dev != NULL)
+ fd = request_firmware(&fw, pathToFile, dev);
+ else {
+ logError(1, "%s parseBinFile: No device found! ERROR %02X\n", ERROR_FILE_PARSE);
+ return ERROR_FILE_PARSE;
+ }
+
+ fw_size = fw->size;
+#else
+fd = 0;
+fw_size = SIZE_NAME;
+#endif
+
+ if (fd == 0 && fw_size > 0) { /* the file should contain at least the header plus the content_crc */
+ if (fw_size < FW_HEADER_SIZE+FW_BYTES_ALIGN) {
+ logError(1, "%s parseBinFile: Read only %d instead of %d... ERROR %02X\n", tag, fw_size, FW_HEADER_SIZE+FW_BYTES_ALIGN, ERROR_FILE_PARSE);
+ res = ERROR_FILE_PARSE;
+ goto END;
+ } else {
+ /* start parsing of bytes */
+#ifndef FW_H_FILE
+ data = (u8 *) (fw->data);
+#else
+ data = (u8 *) (ARRAY_NAME);
+#endif
+ u8ToU32(&data[index], &temp);
+ if (temp != FW_HEADER_SIGNATURE) {
+ logError(1, "%s parseBinFile: Wrong Signature %08X ... ERROR %02X\n", tag, temp, ERROR_FILE_PARSE);
+ res = ERROR_FILE_PARSE;
+ goto END;
+ }
+ logError(0, "%s parseBinFile: Fw Signature OK!\n", tag);
+ index += FW_BYTES_ALIGN;
+ u8ToU32(&data[index], &temp);
+ if (temp != FW_FTB_VER) {
+ logError(1, "%s parseBinFile: Wrong ftb_version %08X ... ERROR %02X\n", tag, temp, ERROR_FILE_PARSE);
+ res = ERROR_FILE_PARSE;
+ goto END;
+ }
+ logError(0, "%s parseBinFile: ftb_version OK!\n", tag);
+ index += FW_BYTES_ALIGN;
+ if (data[index] != DCHIP_ID_0 || data[index+1] != DCHIP_ID_1) {
+ logError(1, "%s parseBinFile: Wrong target %02X != %02X %02X != %02X ... ERROR %08X\n", tag, data[index], DCHIP_ID_0, data[index+1], DCHIP_ID_1, ERROR_FILE_PARSE);
+ res = ERROR_FILE_PARSE;
+ goto END;
+ }
+ index += FW_BYTES_ALIGN;
+ u8ToU32(&data[index], &temp);
+ logError(1, "%s parseBinFile: Fw ID = %08X\n", tag, temp);
+
+ index += FW_BYTES_ALIGN;
+ u8ToU32(&data[index], &temp);
+ fwData->fw_ver = temp;
+ logError(1, "%s parseBinFile: FILE Fw Version = %04X\n", tag, fwData->fw_ver);
+
+ index += FW_BYTES_ALIGN;
+ u8ToU32(&data[index], &temp);
+ fwData->config_id = temp;
+ logError(1, "%s parseBinFile: FILE Config ID = %08X\n", tag, temp);
+
+ index += FW_BYTES_ALIGN;
+ u8ToU32(&data[index], &temp);
+ logError(1, "%s parseBinFile: Config Version = %08X\n", tag, temp);
+
+ index += FW_BYTES_ALIGN*2; /* skip reserved data */
+
+ index += FW_BYTES_ALIGN;
+ logError(1, "%s parseBinFile: File External Release = ", tag);
+ for (i = 0; i < EXTERNAL_RELEASE_INFO_SIZE; i++) {
+ fwData->externalRelease[i] = data[index++];
+ logError(1, "%02X ", fwData->externalRelease[i]);
+ }
+ logError(1, "\n");
+
+ /* index += FW_BYTES_ALIGN; */
+ u8ToU32(&data[index], &temp);
+ fwData->sec0_size = temp;
+ logError(1, "%s parseBinFile: sec0_size = %08X (%d bytes)\n", tag, fwData->sec0_size, fwData->sec0_size);
+
+ index += FW_BYTES_ALIGN;
+ u8ToU32(&data[index], &temp);
+ fwData->sec1_size = temp;
+ logError(1, "%s parseBinFile: sec1_size = %08X (%d bytes)\n", tag, fwData->sec1_size, fwData->sec1_size);
+
+ index += FW_BYTES_ALIGN;
+ u8ToU32(&data[index], &temp);
+ fwData->sec2_size = temp;
+ logError(1, "%s parseBinFile: sec2_size = %08X (%d bytes)\n", tag, fwData->sec2_size, fwData->sec2_size);
+
+ index += FW_BYTES_ALIGN;
+ u8ToU32(&data[index], &temp);
+ fwData->sec3_size = temp;
+ logError(1, "%s parseBinFile: sec3_size = %08X (%d bytes)\n", tag, fwData->sec3_size, fwData->sec3_size);
+
+ index += FW_BYTES_ALIGN; /* skip header crc */
+
+ if (!keep_cx) {
+ dimension = fwData->sec0_size + fwData->sec1_size + fwData->sec2_size + fwData->sec3_size;
+ temp = fw_size;
+ } else {
+ dimension = fwData->sec0_size + fwData->sec1_size; /* sec2 may contain cx data (future implementation) sec3 atm not used */
+ temp = fw_size - fwData->sec2_size - fwData->sec3_size;
+ }
+
+ if (dimension+FW_HEADER_SIZE+FW_BYTES_ALIGN != temp) {
+ logError(1, "%s parseBinFile: Read only %d instead of %d... ERROR %02X\n", tag, fw_size, dimension+FW_HEADER_SIZE+FW_BYTES_ALIGN, ERROR_FILE_PARSE);
+ res = ERROR_FILE_PARSE;
+ goto END;
+ }
+
+ fwData->data = (u8 *) kmalloc(dimension * sizeof (u8), GFP_KERNEL);
+ if (fwData->data == NULL) {
+ logError(1, "%s parseBinFile: ERROR %02X\n", tag, ERROR_ALLOC);
+ res = ERROR_ALLOC;
+ goto END;
+ }
+
+ index += FW_BYTES_ALIGN;
+ memcpy(fwData->data, &data[index], dimension);
+ fwData->data_size = dimension;
+
+ logError(0, "%s READ FW DONE %d bytes!\n", tag, fwData->data_size);
+ res = OK;
+ goto END;
+ }
+ } else {
+ logError(1, "%s parseBinFile: File Not Found! ERROR %02X\n", tag, ERROR_FILE_NOT_FOUND);
+ return ERROR_FILE_NOT_FOUND;
+ }
+
+END:
+#ifndef FW_H_FILE
+ release_firmware(fw);
+#endif
+ return res;
+}
+
+int readFwFile(const char *path, Firmware *fw, int keep_cx)
+{
+ int res;
+
+ res = parseBinFile(path, fw, keep_cx);
+ if (res < OK) {
+ logError(1, "%s readFwFile: ERROR %02X\n", tag, ERROR_MEMH_READ);
+ return (res | ERROR_MEMH_READ);
+ }
+
+ return OK;
+
+}
+
+int flash_unlock(void)
+{
+ u8 cmd[3] = {FLASH_CMD_UNLOCK, FLASH_UNLOCK_CODE0, FLASH_UNLOCK_CODE1}; /* write the command to perform the unlock */
+
+ logError(0, "%s Command unlock ...\n", tag);
+ if (fts_writeCmd(cmd, sizeof (cmd)) < 0) {
+ logError(1, "%s flash_unlock: ERROR % 02X\n", tag, ERROR_I2C_W);
+ return ERROR_I2C_W;
+ }
+
+ /* msleep(FLASH_WAIT_TIME); */
+ logError(0, "%s Unlock flash DONE!\n", tag);
+
+ return OK;
+
+}
+
+int flash_erase_unlock(void)
+{
+ u8 cmd[3] = {FLASH_CMD_WRITE_REGISTER, FLASH_ERASE_UNLOCK_CODE0, FLASH_ERASE_UNLOCK_CODE1}; /* write the command to perform the unlock for erasing the flash */
+
+ logError(0, "%s Try to erase unlock flash...\n", tag);
+
+ logError(0, "%s Command erase unlock ...\n", tag);
+ if (fts_writeCmd(cmd, sizeof (cmd)) < 0) {
+ logError(1, "%s flash_erase_unlock: ERROR % 02X\n", tag, ERROR_I2C_W);
+ return ERROR_I2C_W;
+ }
+
+ logError(0, "%s Erase Unlock flash DONE!\n", tag);
+
+ return OK;
+
+}
+
+int flash_full_erase(void)
+{
+
+ int status;
+ u8 cmd[3] = {FLASH_CMD_WRITE_REGISTER, FLASH_ERASE_CODE0, FLASH_ERASE_CODE1};
+ /* write the command to erase the flash */
+
+ logError(0, "%s Command full erase sent ...\n", tag);
+ if (fts_writeCmd(cmd, sizeof (cmd)) < 0) {
+ logError(1, "%s flash_full_erase: ERROR % 02X\n", tag, ERROR_I2C_W);
+ return ERROR_I2C_W;
+ }
+
+ status = wait_for_flash_ready(FLASH_ERASE_CODE0);
+
+ if (status != OK) {
+ logError(1, "%s flash_full_erase: ERROR % 02X\n", tag, ERROR_FLASH_NOT_READY);
+ return (status | ERROR_FLASH_NOT_READY);
+ /* Flash not ready within the chosen time, better exit! */
+ }
+
+ logError(0, "%s Full Erase flash DONE!\n", tag);
+
+ return OK;
+
+}
+
+int start_flash_dma(void)
+{
+ int status;
+ u8 cmd[3] = {FLASH_CMD_WRITE_REGISTER, FLASH_DMA_CODE0, FLASH_DMA_CODE1};
+ /* write the command to erase the flash */
+
+ logError(0, "%s Command flash DMA ...\n", tag);
+ if (fts_writeCmd(cmd, sizeof (cmd)) < 0) {
+ logError(1, "%s start_flash_dma: ERROR % 02X\n", tag, ERROR_I2C_W);
+ return ERROR_I2C_W;
+ }
+
+ status = wait_for_flash_ready(FLASH_DMA_CODE0);
+
+ if (status != OK) {
+ logError(1, "%s start_flash_dma: ERROR % 02X\n", tag, ERROR_FLASH_NOT_READY);
+ return (status | ERROR_FLASH_NOT_READY);
+ /* Flash not ready within the chosen time, better exit! */
+ }
+
+ logError(0, "%s flash DMA DONE!\n", tag);
+
+ return OK;
+}
+
+int fillFlash(u32 address, u8 *data, int size)
+{
+
+ int remaining = size;
+ int toWrite = 0;
+ int byteBlock = 0;
+ int wheel = 0;
+ u32 addr = 0;
+ int res;
+ int delta;
+
+ u8 *buff = (u8 *) kmalloc((DMA_CHUNK + 3) * sizeof (u8), GFP_KERNEL);
+ if (buff == NULL) {
+ logError(1, "%s fillFlash: ERROR %02X\n", tag, ERROR_ALLOC);
+ return ERROR_ALLOC;
+ }
+
+ while (remaining > 0) {
+ byteBlock = 0;
+ addr = 0;
+ while (byteBlock < FLASH_CHUNK && remaining > 0) {
+ buff[0] = FLASH_CMD_WRITE_64K;
+ if (remaining >= DMA_CHUNK) {
+ if ((byteBlock + DMA_CHUNK) <= FLASH_CHUNK) {
+ /* logError(1, "%s fillFlash: 1\n", tag); */
+ toWrite = DMA_CHUNK;
+ remaining -= DMA_CHUNK;
+ byteBlock += DMA_CHUNK;
+ } else {
+ /* logError(1, "%s fillFlash: 2\n", tag); */
+ delta = FLASH_CHUNK - byteBlock;
+ toWrite = delta;
+ remaining -= delta;
+ byteBlock += delta;
+ }
+ } else {
+ if ((byteBlock + remaining) <= FLASH_CHUNK) {
+ /* logError(1, "%s fillFlash: 3\n", tag); */
+ toWrite = remaining;
+ byteBlock += remaining;
+ remaining = 0;
+
+ } else {
+ /* logError(1, "%s fillFlash: 4\n", tag); */
+ delta = FLASH_CHUNK - byteBlock;
+ toWrite = delta;
+ remaining -= delta;
+ byteBlock += delta;
+ }
+ }
+
+ buff[1] = (u8) ((addr & 0x0000FF00) >> 8);
+ buff[2] = (u8) (addr & 0x000000FF);
+ memcpy(&buff[3], data, toWrite);
+ if (fts_writeCmd(buff, 3 + toWrite) < 0) {
+ logError(1, "%s fillFlash: ERROR %02X\n", tag, ERROR_I2C_W);
+ return ERROR_I2C_W;
+ }
+
+ addr += toWrite;
+ data += toWrite;
+ }
+
+ kfree(buff);
+
+ /* configuring the DMA */
+ byteBlock = byteBlock / 4 - 1;
+
+ buff = (u8 *) kmalloc((9) * sizeof (u8), GFP_KERNEL);
+ buff[0] = FLASH_CMD_WRITE_REGISTER;
+ buff[1] = FLASH_DMA_CONFIG;
+ buff[2] = 0x00;
+ buff[3] = 0x00;
+
+ addr = address + ((wheel * FLASH_CHUNK)/4);
+ buff[4] = (u8) ((addr & 0x000000FF));
+ buff[5] = (u8) ((addr & 0x0000FF00) >> 8);
+ buff[6] = (u8) (byteBlock & 0x000000FF);
+ buff[7] = (u8) ((byteBlock & 0x0000FF00) >> 8);
+ buff[8] = 0x00;
+
+ logError(0, "%s Command = %02X , address = %02X %02X, words = %02X %02X\n", tag, buff[0], buff[5], buff[4], buff[7], buff[6]);
+ if (fts_writeCmd(buff, 9) < OK) {
+ logError(1, "%s Error during filling Flash! ERROR %02X\n", tag, ERROR_I2C_W);
+ return ERROR_I2C_W;
+ }
+
+ /* msleep(FLASH_WAIT_TIME); */
+ res = start_flash_dma();
+ if (res < OK) {
+ logError(1, "%s Error during flashing DMA! ERROR %02X\n", tag, res);
+ return res;
+ }
+ wheel++;
+ }
+ return OK;
+}
+
+int flash_burn(Firmware fw, int force_burn)
+{
+ int res;
+
+ if (!force_burn) {
+ for (res = EXTERNAL_RELEASE_INFO_SIZE-1; res >= 0; res--) {
+ if (fw.externalRelease[res] > ftsInfo.u8_extReleaseInfo[res])
+ goto start;
+ }
+ logError(1, "%s flash_burn: Firmware in the chip newer or equal to the one to burn! NO UPDATE ERROR %02X\n", tag, ERROR_FW_NO_UPDATE);
+ return (ERROR_FW_NO_UPDATE | ERROR_FLASH_BURN_FAILED);
+ }
+
+ /* programming procedure start */
+start:
+ logError(0, "%s Programming Procedure for flashing started:\n\n", tag);
+
+ logError(0, "%s 1) SYSTEM RESET:\n", tag);
+ res = fts_system_reset();
+ if (res < 0) {
+ logError(1, "%s system reset FAILED!\n", tag);
+ if (res != (ERROR_SYSTEM_RESET_FAIL | ERROR_TIMEOUT))
+ /* if there is no firmware i will not get the controller
+ *ready event and there will be a timeout but i can keep going,
+ *but if there is an I2C error i have to exit
+ */
+ return (res | ERROR_FLASH_BURN_FAILED);
+ } else
+ logError(0, "%s system reset COMPLETED!\n\n", tag);
+
+ logError(0, "%s 2) WARM BOOT:\n", tag);
+ res = fts_warm_boot();
+ if (res < OK) {
+ logError(1, "%s warm boot FAILED!\n", tag);
+ return (res | ERROR_FLASH_BURN_FAILED);
+ } else
+ logError(0, "%s warm boot COMPLETED!\n\n", tag);
+
+ /* msleep(FLASH_WAIT_TIME); */
+ logError(0, "%s 3) FLASH UNLOCK:\n", tag);
+ res = flash_unlock();
+ if (res < OK) {
+ logError(1, "%s flash unlock FAILED! ERROR %02X\n", tag, ERROR_FLASH_BURN_FAILED);
+ return (res | ERROR_FLASH_BURN_FAILED);
+ }
+ logError(0, "%s flash unlock COMPLETED!\n\n", tag);
+
+ /* msleep(200); */
+ logError(0, "%s 4) FLASH ERASE UNLOCK:\n", tag);
+ res = flash_erase_unlock();
+ if (res < 0) {
+ logError(1, "%s flash unlock FAILED! ERROR %02X\n", tag, ERROR_FLASH_BURN_FAILED);
+ return (res | ERROR_FLASH_BURN_FAILED);
+ }
+ logError(0, "%s flash unlock COMPLETED!\n\n", tag);
+
+ /* msleep(FLASH_WAIT_TIME); */
+ logError(0, "%s 5) FLASH ERASE:\n", tag);
+ res = flash_full_erase();
+ if (res < 0) {
+ logError(1, "%s flash erase FAILED! ERROR %02X\n", tag, ERROR_FLASH_BURN_FAILED);
+ return (res | ERROR_FLASH_BURN_FAILED);
+ }
+ logError(0, "%s flash erase COMPLETED!\n\n", tag);
+
+ /* msleep(FLASH_WAIT_TIME); */
+ logError(0, "%s 6) LOAD PROGRAM:\n", tag);
+ res = fillFlash(FLASH_ADDR_CODE, &fw.data[0], fw.sec0_size);
+ if (res < OK) {
+ logError(1, "%s load program ERROR %02X\n", tag, ERROR_FLASH_BURN_FAILED);
+ return (res | ERROR_FLASH_BURN_FAILED);
+ }
+ logError(1, "%s load program DONE!\n", tag);
+
+ logError(0, "%s 7) LOAD CONFIG:\n", tag);
+ res = fillFlash(FLASH_ADDR_CONFIG, &(fw.data[fw.sec0_size]), fw.sec1_size);
+ if (res < OK) {
+ logError(1, "%s load config ERROR %02X\n", tag, ERROR_FLASH_BURN_FAILED);
+ return (res | ERROR_FLASH_BURN_FAILED);
+ }
+ logError(1, "%s load config DONE!\n", tag);
+
+ logError(0, "%s Flash burn COMPLETED!\n\n", tag);
+
+ logError(0, "%s 8) SYSTEM RESET:\n", tag);
+ res = fts_system_reset();
+ if (res < 0) {
+ logError(1, "%s system reset FAILED! ERROR %02X\n", tag, ERROR_FLASH_BURN_FAILED);
+ return (res | ERROR_FLASH_BURN_FAILED);
+ }
+ logError(0, "%s system reset COMPLETED!\n\n", tag);
+
+ logError(0, "%s 9) FINAL CHECK:\n", tag);
+ res = readChipInfo(0);
+ if (res < 0) {
+ logError(1, "%s flash_burn: Unable to retrieve Chip INFO! ERROR %02X\n", tag, ERROR_FLASH_BURN_FAILED);
+ return (res | ERROR_FLASH_BURN_FAILED);
+ }
+
+ for (res = 0; res < EXTERNAL_RELEASE_INFO_SIZE; res++) {
+ if (fw.externalRelease[res] != ftsInfo.u8_extReleaseInfo[res]) {
+ /* external release is prined during readChipInfo */
+ logError(1, "%s Firmware in the chip different from the one that was burn! fw: %x != %x , conf: %x != %x\n", tag, ftsInfo.u16_fwVer, fw.fw_ver, ftsInfo.u16_cfgId, fw.config_id);
+ return ERROR_FLASH_BURN_FAILED;
+ }
+ }
+
+ logError(0, "%s Final check OK! fw: %02X, conf: %02X\n", tag, ftsInfo.u16_fwVer, ftsInfo.u16_cfgId);
+
+ return OK;
+}
+
+int flashProcedure(const char *path, int force, int keep_cx)
+{
+ Firmware fw;
+ int res;
+
+ fw.data = NULL;
+ logError(0, "%s Reading Fw file...\n", tag);
+ res = readFwFile(path, &fw, keep_cx);
+ if (res < OK) {
+ logError(1, "%s flashProcedure: ERROR %02X\n", tag, (res | ERROR_FLASH_PROCEDURE));
+ kfree(fw.data);
+ return (res | ERROR_FLASH_PROCEDURE);
+ }
+ logError(0, "%s Fw file read COMPLETED!\n", tag);
+
+ logError(0, "%s Starting flashing procedure...\n", tag);
+ res = flash_burn(fw, force);
+ if (res < OK && res != (ERROR_FW_NO_UPDATE | ERROR_FLASH_BURN_FAILED)) {
+ logError(1, "%s flashProcedure: ERROR %02X\n", tag, ERROR_FLASH_PROCEDURE);
+ kfree(fw.data);
+ return (res | ERROR_FLASH_PROCEDURE);
+ }
+ logError(0, "%s flashing procedure Finished!\n", tag);
+ kfree(fw.data);
+ return res;
+}
+
+#endif
diff --git a/drivers/input/touchscreen/st/fts_lib/ftsFlash.h b/drivers/input/touchscreen/st/fts_lib/ftsFlash.h
new file mode 100644
index 000000000000..69635e07a9f4
--- /dev/null
+++ b/drivers/input/touchscreen/st/fts_lib/ftsFlash.h
@@ -0,0 +1,79 @@
+/*
+
+**************************************************************************
+** STMicroelectronics **
+**************************************************************************
+** marco.cali@st.com **
+**************************************************************************
+* *
+* FTS API for Flashing the IC *
+* *
+**************************************************************************
+**************************************************************************
+
+*/
+
+#include "ftsSoftware.h"
+
+/* Flash possible status */
+#define FLASH_READY 0
+#define FLASH_BUSY 1
+#define FLASH_UNKNOWN -1
+
+#define FLASH_STATUS_BYTES 1
+
+/* Flash timing parameters */
+#define FLASH_RETRY_COUNT 1000
+#define FLASH_WAIT_BEFORE_RETRY 50 /* ms */
+
+#define FLASH_WAIT_TIME 200 /* ms */
+
+/* PATHS FW FILES */
+/* #define PATH_FILE_FW "fw.memh" */
+#ifdef FTM3_CHIP
+#define PATH_FILE_FW "st_fts.bin"
+#else
+#define PATH_FILE_FW "st_fts.ftb" /* new bin file structure */
+#endif
+
+#ifndef FTM3_CHIP
+#define FLASH_CHUNK (64*1024)
+#define DMA_CHUNK 32
+#endif
+
+typedef struct {
+ u8 *data;
+ u16 fw_ver;
+ u16 config_id;
+ u8 externalRelease[EXTERNAL_RELEASE_INFO_SIZE];
+ int data_size;
+#ifndef FTM3_CHIP
+ u32 sec0_size;
+ u32 sec1_size;
+ u32 sec2_size;
+ u32 sec3_size;
+#endif
+} Firmware;
+
+#ifdef FTM3_CHIP
+int flash_status(void);
+int flash_status_ready(void);
+int wait_for_flash_ready(void);
+int parseBinFile(const char *pathToFile, u8 **data, int *length, int dimension);
+/* int parseMemhFile(const char* pathToFile, u8** data, int* length, int dimension); */
+#else
+int wait_for_flash_ready(u8 type);
+int fts_warm_boot(void);
+int parseBinFile(const char *pathToFile, Firmware *fw, int keep_cx);
+int flash_erase_unlock(void);
+int flash_full_erase(void);
+int start_flash_dma(void);
+int fillFlash(u32 address, u8 *data, int size);
+#endif
+
+int flash_unlock(void);
+int fillMemory(u32 address, u8 *data, int size);
+int getFirmwareVersion(u16 *fw_vers, u16 *config_id);
+int readFwFile(const char *path, Firmware *fw, int keep_cx);
+int flash_burn(Firmware fw, int force_burn);
+int flashProcedure(const char *path, int force, int keep_cx);
diff --git a/drivers/input/touchscreen/st/fts_lib/ftsFrame.c b/drivers/input/touchscreen/st/fts_lib/ftsFrame.c
new file mode 100644
index 000000000000..c502559319a0
--- /dev/null
+++ b/drivers/input/touchscreen/st/fts_lib/ftsFrame.c
@@ -0,0 +1,569 @@
+/*
+
+**************************************************************************
+** STMicroelectronics **
+**************************************************************************
+** marco.cali@st.com **
+**************************************************************************
+* *
+* FTS functions for getting frames *
+* *
+**************************************************************************
+**************************************************************************
+
+*/
+
+#include "ftsCrossCompile.h"
+#include "ftsCompensation.h"
+#include "ftsError.h"
+#include "ftsFrame.h"
+#include "ftsHardware.h"
+#include "ftsIO.h"
+#include "ftsSoftware.h"
+#include "ftsTool.h"
+#include "ftsTime.h"
+
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/platform_device.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <stdarg.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/serio.h>
+#include <linux/time.h>
+#include <linux/pm.h>
+#include <linux/delay.h>
+#include <linux/ctype.h>
+#include <linux/gpio.h>
+#include <linux/i2c.h>
+#include <linux/i2c-dev.h>
+#include <linux/fs.h>
+#include <linux/uaccess.h>
+#include <linux/power_supply.h>
+#include <linux/firmware.h>
+#include <linux/regulator/consumer.h>
+#include <linux/of_gpio.h>
+/* #include <linux/sec_sysfs.h> */
+
+static char tag[8] = "[ FTS ]\0";
+static int sense_len, force_len;
+
+/*int getOffsetFrame(u16 address, u16 *offset)
+{
+
+ u8 data[2];
+ u8 cmd = { FTS_CMD_FRAMEBUFFER_R };
+
+ if (readCmdU16(cmd, address, data, OFFSET_LENGTH, DUMMY_FRAMEBUFFER) < 0) {
+ logError(1, "%s getOffsetFrame: ERROR %02X\n", tag, ERROR_I2C_R);
+ return ERROR_I2C_R;
+ }
+ else {
+ u8ToU16(data, offset);
+ logError(0, "%s %s", tag, printHex("Offest = ", data, OFFSET_LENGTH));
+ return OK;
+ }
+
+}*/
+
+int getChannelsLength(void)
+{
+
+ int ret;
+ u8 *data = (u8 *)kmalloc(2*sizeof(u8), GFP_KERNEL);
+
+ if (data == NULL) {
+ logError(1, "%s getChannelsLength: ERROR %02X\n", tag, ERROR_ALLOC);
+ return ERROR_ALLOC;
+ }
+
+ ret = readB2(ADDR_SENSE_LEN, data, 2);
+ if (ret < OK) {
+ logError(1, "%s getChannelsLength: ERROR %02X\n", tag, ERROR_READ_B2);
+ return (ret|ERROR_READ_B2);
+ }
+
+ sense_len = (int)data[0];
+ force_len = (int)data[1];
+
+ logError(0, "%s Force_len = %d Sense_Len = %d\n", tag, force_len, sense_len);
+
+ kfree(data);
+
+ return OK;
+}
+
+int getFrameData(u16 address, int size, short **frame)
+{
+ int i, j, ret;
+ u8 *data = (u8 *)kmalloc(size*sizeof(u8), GFP_KERNEL);
+ if (data == NULL) {
+ logError(1, "%s getFrameData: ERROR %02X\n", tag, ERROR_ALLOC);
+ return ERROR_ALLOC;
+ }
+
+ ret = readCmdU16(FTS_CMD_FRAMEBUFFER_R, address, data, size, DUMMY_FRAMEBUFFER);
+ if (ret < OK) {
+ logError(1, "%s getFrameData: ERROR %02X\n", tag, ERROR_I2C_R);
+ kfree(data);
+ return ERROR_I2C_R;
+ }
+ j = 0;
+ for (i = 0; i < size; i += 2) {
+ (*frame)[j] = (short)((data[i + 1] << 8) + data[i]);
+ j++;
+ }
+ kfree(data);
+ return OK;
+}
+
+/*int getMSFrame(u16 type, short **frame, int keep_first_row)
+{
+ u16 offset;
+ int size, ret;
+
+ if (getSenseLen() == 0 || getForceLen() == 0) {
+ ret=getChannelsLength();
+ if (ret<OK) {
+ logError(1, "%s getMSFrame: ERROR %02X\n", tag,ERROR_CH_LEN);
+ return (ret|ERROR_CH_LEN);
+ }
+ }
+
+ ret = getOffsetFrame(type, &offset);
+ if (ret<OK) {
+ logError(1, "%s getMSFrame: ERROR %02X\n", tag, ERROR_GET_OFFSET);
+ return (ret | ERROR_GET_OFFSET);
+ }
+
+ switch (type) {
+ case ADDR_RAW_TOUCH:
+ case ADDR_FILTER_TOUCH:
+ case ADDR_NORM_TOUCH:
+ case ADDR_CALIB_TOUCH:
+ if (keep_first_row ==1)
+ size = ((force_len+1)*sense_len);
+ else {
+ size = ((force_len)*sense_len);
+ offset+= (sense_len * BYTES_PER_NODE);
+ }
+ break;
+
+ default:
+ logError(1, "%s getMSFrame: ERROR % 02X\n", tag, ERROR_OP_NOT_ALLOW);
+ return ERROR_OP_NOT_ALLOW;
+ }
+
+ *frame = (short*)kmalloc(size*sizeof(short), GFP_KERNEL);
+ if (*frame==NULL) {
+ logError(1, "%s getMSFrame: ERROR %02X\n", tag, ERROR_ALLOC);
+ return ERROR_ALLOC;
+ }
+
+ ret=getFrameData(offset, size*BYTES_PER_NODE, frame);
+ if (ret<OK) {
+ logError(1, "%s getMSFrame: ERROR %02X\n", tag, ERROR_GET_FRAME_DATA);
+ return (ret|ERROR_GET_FRAME_DATA);
+ }
+
+ logError(0, "%s Frame acquired!\n", tag);
+ return size;
+
+}
+
+int getMSKeyFrame(u16 type, short **frame) {
+ u16 offset;
+ int size, ret;
+ u16 address;
+ MutualSenseData data;
+
+ if (type != ADDR_RAW_MS_KEY) {
+ logError(1, "%s getMSKeyFrame: ERROR % 02X\n", tag, ERROR_OP_NOT_ALLOW);
+ return ERROR_OP_NOT_ALLOW;
+ }
+
+ ret = getOffsetFrame(type, &offset);
+ if (ret<OK) {
+ logError(1, "%s getMSKeyFrame: ERROR %02X\n", tag, ERROR_GET_OFFSET);
+ return (ret | ERROR_GET_OFFSET);
+ }
+
+ ret = requestCompensationData(MS_KEY);
+ if (ret < OK) {
+ logError(1, "%s getMSKeyFrame: readMutualSenseCompensationData ERROR %02X\n", tag, ERROR_REQU_COMP_DATA);
+ return (ret | ERROR_REQU_COMP_DATA);
+ }
+
+ ret = readCompensationDataHeader(MS_KEY, &(data.header), &address);
+ if (ret < OK) {
+ logError(1, "%s getMSKeyFrame: readMutualSenseCompensationData ERROR %02X\n", tag, ERROR_COMP_DATA_HEADER);
+ return (ret | ERROR_COMP_DATA_HEADER);
+ }
+
+ if (data.header.force_node>data.header.sense_node)
+ size = data.header.force_node;
+ else
+ size = data.header.sense_node;
+
+ *frame = (short*)kmalloc(size*sizeof(short), GFP_KERNEL);
+ if (frame == NULL) {
+ logError(1, "%s getMSKeyFrame: ERROR %02X\n", tag, ERROR_ALLOC);
+ return ERROR_ALLOC;
+ }
+
+ ret = getFrameData(offset, size*BYTES_PER_NODE, frame);
+ if (ret<OK) {
+ logError(1, "%s getMSKeyFrame: ERROR %02X\n", tag, ERROR_GET_FRAME_DATA);
+ return (ret | ERROR_GET_FRAME_DATA);
+ }
+
+ logError(0, "%s Frame acquired!\n", tag);
+}
+
+int getSSFrame(u16 type, short **frame) {
+ u16 offset;
+ int size, ret;
+
+ if (getSenseLen() == 0 || getForceLen() == 0) {
+ ret = getChannelsLength();
+ if (ret<0) {
+ logError(1, "%s getSSFrame: ERROR %02X\n", tag, ERROR_CH_LEN);
+ return (ret | ERROR_CH_LEN);
+ }
+ }
+
+ switch (type) {
+ case ADDR_RAW_HOVER_FORCE:
+ case ADDR_FILTER_HOVER_FORCE:
+ case ADDR_NORM_HOVER_FORCE:
+ case ADDR_CALIB_HOVER_FORCE:
+ case ADDR_RAW_PRX_FORCE:
+ case ADDR_FILTER_PRX_FORCE:
+ case ADDR_NORM_PRX_FORCE:
+ case ADDR_CALIB_PRX_FORCE:
+ size = ((force_len)* 1);
+ break;
+
+ case ADDR_RAW_HOVER_SENSE:
+ case ADDR_FILTER_HOVER_SENSE:
+ case ADDR_NORM_HOVER_SENSE:
+ case ADDR_CALIB_HOVER_SENSE:
+ case ADDR_RAW_PRX_SENSE:
+ case ADDR_FILTER_PRX_SENSE:
+ case ADDR_NORM_PRX_SENSE:
+ case ADDR_CALIB_PRX_SENSE:
+ size = ((1)*sense_len);
+ break;
+
+ default:
+ logError(1, "%s getSSFrame: ERROR % 02X\n", tag, ERROR_OP_NOT_ALLOW);
+ return ERROR_OP_NOT_ALLOW;
+
+ }
+
+ ret = getOffsetFrame(type, &offset);
+ if (ret<OK) {
+ logError(1, "%s getSSFrame: ERROR %02X\n", tag, ERROR_GET_OFFSET);
+ return (ret | ERROR_GET_OFFSET);
+ }
+
+ *frame = (short*)kmalloc(size*sizeof(short), GFP_KERNEL);
+ if (*frame == NULL) {
+ logError(1, "%s getSSFrame: ERROR %02X\n", tag, ERROR_ALLOC);
+ return ERROR_ALLOC;
+ }
+
+ ret = getFrameData(offset, size*BYTES_PER_NODE, frame);
+ if (ret<OK) {
+ logError(1, "%s getSSFrame: ERROR %02X\n", tag, ERROR_GET_FRAME_DATA);
+ return (ret | ERROR_GET_FRAME_DATA);
+ }
+
+ logError(0, "%s Frame acquired!\n", tag);
+ return size;
+
+}
+
+int getNmsFrame(u16 type, short ***frames, int *size, int keep_first_row, int fs, int n) {
+ int i;
+ StopWatch global, local;
+ int temp;
+
+ *frames = (short **)kmalloc(n*sizeof(short *), GFP_KERNEL);
+
+ if (*frames == NULL) {
+ logError(1, "%s getNmsFrame: ERROR %02X\n", tag, ERROR_ALLOC);
+ return ERROR_ALLOC;
+ }
+
+ fs = (1*1000 / fs) ;
+
+ startStopWatch(&global);
+ for (i = 0; i < n; i++) {
+
+ startStopWatch(&local);
+
+ *size = getMSFrame(type, ((*frames)+i), keep_first_row);
+ if (*size < OK) {
+ logError(1, "%s getNFrame: getFrame failed\n",tag);
+ return *size;
+ }
+
+ stopStopWatch(&local);
+ temp = elapsedMillisecond(&local);
+ logError(0, "%s Iteration %d performed in %d ms... the process wait for %ld ms\n\n", tag, i, temp, (unsigned long)(fs - temp));
+
+ if (temp < fs)
+ msleep((unsigned long)(fs - temp));
+
+ }
+
+ stopStopWatch(&global);
+ temp = elapsedMillisecond(&global);
+ logError(0, "%s Global Iteration performed in %d ms\n", tag, temp);
+ temp /= n;
+ logError(0, "%s Mean Iteration performed in %d ms\n", tag, temp);
+ return (1000 / (temp));
+
+}*/
+
+int getSenseLen(void)
+{
+ int ret;
+ if (sense_len != 0)
+ return sense_len;
+ ret = getChannelsLength();
+ if (ret < OK)
+ return ret;
+ else
+ return sense_len;
+}
+
+int getForceLen(void)
+{
+ int ret;
+ if (force_len != 0)
+ return force_len;
+ ret = getChannelsLength();
+ if (ret < OK)
+ return ret;
+ else
+ return force_len;
+}
+
+int requestFrame(u16 type)
+{
+ int retry = 0;
+ int ret;
+ u16 answer;
+
+ int event_to_search[1];
+ u8 readEvent[FIFO_EVENT_SIZE];
+
+ u8 cmd[3] = { FTS_CMD_REQU_FRAME_DATA, 0x00, 0x00 };
+ /* B7 is the command for asking frame data */
+ event_to_search[0] = (int)EVENTID_FRAME_DATA_READ;
+
+ u16ToU8(type, &cmd[1]);
+
+ while (retry < FRAME_DATA_READ_RETRY) {
+ logError(0, "%s %s", tag, printHex("Command = ", cmd, 3));
+ ret = fts_writeFwCmd(cmd, 3);
+ /* send the request to the chip to load in memory the Frame Data */
+ if (ret < OK) {
+ logError(1, "%s requestFrame: ERROR %02X\n", tag, ERROR_I2C_W);
+ return ERROR_I2C_W;
+ }
+ ret = pollForEvent(event_to_search, 1, readEvent, TIMEOUT_REQU_COMP_DATA);
+ if (ret < OK) {
+ logError(0, "%s Event did not Found at %d attemp!\n", tag, retry + 1);
+ retry += 1;
+ } else {
+ retry = 0;
+ break;
+ }
+ }
+
+ if (retry == FRAME_DATA_READ_RETRY) {
+ logError(1, "%s requestFrame: ERROR %02X\n", tag, ERROR_TIMEOUT);
+ return ERROR_TIMEOUT;
+ }
+
+ u8ToU16_le(&readEvent[1], &answer);
+
+ if (answer == type)
+ return OK;
+ logError(1, "%s The event found has a different type of Frame data ERROR %02X\n", tag, ERROR_DIFF_COMP_TYPE);
+ return ERROR_DIFF_COMP_TYPE;
+
+}
+
+int readFrameDataHeader(u16 type, DataHeader *header)
+{
+
+ u16 offset = ADDR_FRAMEBUFFER_DATA;
+ u16 answer;
+ u8 data[FRAME_DATA_HEADER];
+
+ if (readCmdU16(FTS_CMD_FRAMEBUFFER_R, offset, data, FRAME_DATA_HEADER, DUMMY_FRAMEBUFFER) < 0) {
+ logError(1, "%s readFrameDataHeader: ERROR %02X\n", tag, ERROR_I2C_R);
+ return ERROR_I2C_R;
+ }
+ logError(0, "%s Read Data Header done!\n", tag);
+
+ if (data[0] != FRAME_HEADER_SIGNATURE) {
+ logError(1, "%s readFrameDataHeader: ERROR %02X The Header Signature was wrong! %02X != %02X\n", tag, ERROR_WRONG_COMP_SIGN, data[0], HEADER_SIGNATURE);
+ return ERROR_WRONG_COMP_SIGN;
+ }
+
+ u8ToU16_le(&data[1], &answer);
+
+ if (answer != type) {
+ logError(1, "%s readFrameDataHeader: ERROR %02X\n", tag, ERROR_DIFF_COMP_TYPE);
+ return ERROR_DIFF_COMP_TYPE;
+ }
+
+ logError(0, "%s Type of Frame data OK!\n", tag);
+
+ header->type = type;
+ header->force_node = (int)data[4];
+ header->sense_node = (int)data[5];
+
+ return OK;
+
+}
+
+int getMSFrame2(u16 type, MutualSenseFrame *frame)
+{
+ u16 offset = ADDR_FRAMEBUFFER_DATA+FRAME_DATA_HEADER;
+ int size, ret;
+
+ if (!(type == MS_TOUCH_ACTIVE || type == MS_TOUCH_LOW_POWER || type == MS_TOUCH_ULTRA_LOW_POWER || type == MS_KEY)) {
+ logError(1, "%s getMSFrame: Choose a MS type of frame data ERROR %02X\n", tag, ERROR_OP_NOT_ALLOW);
+ return ERROR_OP_NOT_ALLOW;
+ }
+
+ ret = requestFrame(type);
+ if (ret < 0) {
+ logError(1, "%s readMutualSenseCompensationData: ERROR %02X\n", tag, ERROR_REQU_COMP_DATA);
+ return (ret | ERROR_REQU_COMP_DATA);
+ }
+
+ ret = readFrameDataHeader(type, &(frame->header));
+ if (ret < 0) {
+ logError(1, "%s readMutualSenseCompensationData: ERROR %02X\n", tag, ERROR_COMP_DATA_HEADER);
+ return (ret | ERROR_COMP_DATA_HEADER);
+ }
+
+ switch (type) {
+ case MS_TOUCH_ACTIVE:
+ case MS_TOUCH_LOW_POWER:
+ case MS_TOUCH_ULTRA_LOW_POWER:
+ size = frame->header.force_node*frame->header.sense_node;
+ break;
+ case MS_KEY:
+ if (frame->header.force_node > frame->header.sense_node)
+ /* or use directly the number in the ftsChip */
+ size = frame->header.force_node;
+ else
+ size = frame->header.sense_node;
+ frame->header.force_node = 1;
+ frame->header.sense_node = size;
+ break;
+
+ default:
+ logError(1, "%s getMSFrame: ERROR % 02X\n", tag, ERROR_OP_NOT_ALLOW);
+ return ERROR_OP_NOT_ALLOW;
+ }
+
+ frame->node_data = (short *)kmalloc(size*sizeof(short), GFP_KERNEL);
+ if (frame->node_data == NULL) {
+ logError(1, "%s getMSFrame: ERROR %02X\n", tag, ERROR_ALLOC);
+ return ERROR_ALLOC;
+ }
+
+ ret = getFrameData(offset, size*BYTES_PER_NODE, &(frame->node_data));
+ if (ret < OK) {
+ logError(1, "%s getMSFrame: ERROR %02X\n", tag, ERROR_GET_FRAME_DATA);
+ return (ret | ERROR_GET_FRAME_DATA);
+ }
+ /* if you want to access one node i,j, you should compute the offset like: offset = i*columns + j = > frame[i, j] */
+
+ logError(0, "%s Frame acquired!\n", tag);
+ frame->node_data_size = size;
+ return size; /* return the number of data put inside frame */
+
+}
+
+int getSSFrame2(u16 type, SelfSenseFrame *frame)
+{
+ u16 offset = ADDR_FRAMEBUFFER_DATA + FRAME_DATA_HEADER;
+ int size, ret;
+ short *temp = NULL;
+
+ if (!(type == SS_TOUCH || type == SS_KEY || type == SS_HOVER || type == SS_PROXIMITY)) {
+ logError(1, "%s getSSFrame: Choose a SS type of frame data ERROR %02X\n", tag, ERROR_OP_NOT_ALLOW);
+ return ERROR_OP_NOT_ALLOW;
+ }
+
+ ret = requestFrame(type);
+ if (ret < 0) {
+ logError(1, "%s getSSFrame: ERROR %02X\n", tag, ERROR_REQU_COMP_DATA);
+ return (ret | ERROR_REQU_COMP_DATA);
+ }
+
+ ret = readFrameDataHeader(type, &(frame->header));
+ if (ret < 0) {
+ logError(1, "%s getSSFrame: ERROR %02X\n", tag, ERROR_COMP_DATA_HEADER);
+ return (ret | ERROR_COMP_DATA_HEADER);
+ }
+
+ switch (type) {
+ case SS_TOUCH:
+ case SS_HOVER:
+ case SS_PROXIMITY:
+ size = frame->header.force_node+frame->header.sense_node;
+ break;
+
+ default:
+ logError(1, "%s getSSFrame: ERROR % 02X\n", tag, ERROR_OP_NOT_ALLOW);
+ return ERROR_OP_NOT_ALLOW;
+ }
+
+ temp = (short *)kmalloc(size*sizeof(short), GFP_KERNEL);
+ if (temp == NULL) {
+ logError(1, "%s getSSFrame: ERROR %02X\n", tag, ERROR_ALLOC);
+ return ERROR_ALLOC;
+ }
+
+ ret = getFrameData(offset, size*BYTES_PER_NODE, &temp);
+ if (ret < OK) {
+ logError(1, "%s getMSFrame: ERROR %02X\n", tag, ERROR_GET_FRAME_DATA);
+ return (ret | ERROR_GET_FRAME_DATA);
+ }
+
+ frame->force_data = (short *)kmalloc(frame->header.force_node*sizeof(short), GFP_KERNEL);
+ if (frame->force_data == NULL) {
+ logError(1, "%s getSSFrame: ERROR %02X\n", tag, ERROR_ALLOC);
+ return ERROR_ALLOC;
+ }
+
+ memcpy(frame->force_data, temp, frame->header.force_node*sizeof(short));
+
+ frame->sense_data = (short *)kmalloc(frame->header.sense_node*sizeof(short), GFP_KERNEL);
+ if (frame->sense_data == NULL) {
+ logError(1, "%s getSSFrame: ERROR %02X\n", tag, ERROR_ALLOC);
+ return ERROR_ALLOC;
+ }
+
+ memcpy(frame->sense_data, &temp[frame->header.force_node], frame->header.sense_node*sizeof(short));
+
+ logError(0, "%s Frame acquired!\n", tag);
+ kfree(temp);
+ return size; /* return the number of data put inside frame */
+
+}
diff --git a/drivers/input/touchscreen/st/fts_lib/ftsFrame.h b/drivers/input/touchscreen/st/fts_lib/ftsFrame.h
new file mode 100644
index 000000000000..89f4e5080a53
--- /dev/null
+++ b/drivers/input/touchscreen/st/fts_lib/ftsFrame.h
@@ -0,0 +1,49 @@
+/*
+
+**************************************************************************
+** STMicroelectronics **
+**************************************************************************
+** marco.cali@st.com **
+**************************************************************************
+* *
+* FTS functions for getting frames *
+* *
+**************************************************************************
+**************************************************************************
+
+*/
+
+#include "ftsSoftware.h"
+
+/* Number of data bytes for each node */
+#define BYTES_PER_NODE 2
+#define OFFSET_LENGTH 2
+#define FRAME_DATA_HEADER 8
+#define FRAME_HEADER_SIGNATURE 0xB5
+#define FRAME_DATA_READ_RETRY 2
+
+typedef struct {
+ DataHeader header;
+ short *node_data;
+ int node_data_size;
+} MutualSenseFrame;
+
+typedef struct {
+ DataHeader header;
+ short *force_data;
+ short *sense_data;
+} SelfSenseFrame;
+
+/* int getOffsetFrame(u16 address, u16 *offset); */
+int getChannelsLength(void);
+int getFrameData(u16 address, int size, short **frame);
+/* int getMSFrame(u16 type, short **frame, int keep_first_row); */
+/* int getMSKeyFrame(u16 type, short **frame); */
+/* int getSSFrame(u16 type, short **frame); */
+/* int getNmsFrame(u16 type, short ***frames, int * sizes, int keep_first_row, int fs, int n); */
+int getSenseLen(void);
+int getForceLen(void);
+int requestFrame(u16 type);
+int readFrameDataHeader(u16 type, DataHeader *header);
+int getMSFrame2(u16 type, MutualSenseFrame *frame);
+int getSSFrame2(u16 type, SelfSenseFrame *frame);
diff --git a/drivers/input/touchscreen/st/fts_lib/ftsGesture.c b/drivers/input/touchscreen/st/fts_lib/ftsGesture.c
new file mode 100644
index 000000000000..fda4ab281948
--- /dev/null
+++ b/drivers/input/touchscreen/st/fts_lib/ftsGesture.c
@@ -0,0 +1,393 @@
+/*
+
+**************************************************************************
+** STMicroelectronics **
+**************************************************************************
+** marco.cali@st.com **
+**************************************************************************
+* *
+* FTS Gesture Utilities *
+* *
+**************************************************************************
+**************************************************************************
+
+*/
+
+#include "ftsSoftware.h"
+#include "ftsError.h"
+#include "ftsGesture.h"
+#include "ftsIO.h"
+#include "ftsTool.h"
+
+static char tag[8] = "[ FTS ]\0";
+
+static u8 gesture_mask[GESTURE_MASK_SIZE] = { 0 };
+static u8 custom_gestures[GESTURE_CUSTOM_NUMBER][GESTURE_CUSTOM_POINTS];
+static u8 custom_gesture_index[GESTURE_CUSTOM_NUMBER] = { 0 };
+
+int enableGesture(u8 *mask, int size)
+{
+ u8 cmd[size+2];
+ u8 readData[FIFO_EVENT_SIZE];
+ int i, res;
+ int event_to_search[4] = {EVENTID_GESTURE, EVENT_TYPE_ENB, 0x00, GESTURE_ENABLE};
+
+ logError(0, "%s Trying to enable gesture...\n", tag);
+ cmd[0] = FTS_CMD_GESTURE_CMD;
+ cmd[1] = GESTURE_ENABLE;
+
+ if (size <= GESTURE_MASK_SIZE) {
+ if (mask != NULL) {
+ for (i = 0; i < size; i++) {
+ cmd[i + 2] = mask[i];
+ gesture_mask[i] = gesture_mask[i]|mask[i];
+ /* back up of the gesture enabled */
+ }
+ while (i < GESTURE_MASK_SIZE) {
+ cmd[i + 2] = gesture_mask[i];
+ i++;
+ }
+ } else {
+ for (i = 0; i < GESTURE_MASK_SIZE; i++) {
+ cmd[i + 2] = gesture_mask[i];
+ }
+ }
+
+ res = fts_writeFwCmd(cmd, GESTURE_MASK_SIZE + 2);
+ if (res < OK) {
+ logError(1, "%s enableGesture: ERROR %08X\n", tag, res);
+ return res;
+ }
+
+ res = pollForEvent(event_to_search, 4, readData, GENERAL_TIMEOUT);
+ if (res < OK) {
+ logError(1, "%s enableGesture: pollForEvent ERROR %08X\n", tag, res);
+ return res;
+ }
+
+ if (readData[4] != 0x00) {
+ logError(1, "%s enableGesture: ERROR %08X\n", tag, ERROR_GESTURE_ENABLE_FAIL);
+ return ERROR_GESTURE_ENABLE_FAIL;
+ }
+
+ logError(0, "%s enableGesture DONE!\n", tag);
+ return OK;
+ } else {
+ logError(1, "%s enableGesture: Size not valid! %d > %d ERROR %08X\n", tag, size, GESTURE_MASK_SIZE);
+ return ERROR_OP_NOT_ALLOW;
+ }
+
+}
+
+int disableGesture(u8 *mask, int size)
+{
+ u8 cmd[2+GESTURE_MASK_SIZE];
+ u8 readData[FIFO_EVENT_SIZE];
+ u8 temp;
+ int i, res;
+ int event_to_search[4] = { EVENTID_GESTURE, EVENT_TYPE_ENB, 0x00, GESTURE_DISABLE };
+
+ logError(0, "%s Trying to disable gesture...\n", tag);
+ cmd[0] = FTS_CMD_GESTURE_CMD;
+ cmd[1] = GESTURE_DISABLE;
+
+ if (size <= GESTURE_MASK_SIZE) {
+ if (mask != NULL) {
+ for (i = 0; i < size; i++) {
+ cmd[i + 2] = mask[i];
+ temp = gesture_mask[i] ^ mask[i];
+ /* enabled XOR disabled */
+ gesture_mask[i] = temp & gesture_mask[i];
+ /* disable the gestures that were enabled */
+ }
+ while (i < GESTURE_MASK_SIZE) {
+ cmd[i + 2] = gesture_mask[i];
+ /* disable all the other gesture not specified */
+ gesture_mask[i] = 0x00;
+ i++;
+ }
+ } else {
+ for (i = 0; i < GESTURE_MASK_SIZE; i++) {
+ cmd[i + 2] = gesture_mask[i];
+ }
+ }
+
+ res = fts_writeFwCmd(cmd, 2 + GESTURE_MASK_SIZE);
+ if (res < OK) {
+ logError(1, "%s disableGesture: ERROR %08X\n", tag, res);
+ return res;
+ }
+
+ res = pollForEvent(event_to_search, 4, readData, GENERAL_TIMEOUT);
+ if (res < OK) {
+ logError(1, "%s disableGesture: pollForEvent ERROR %08X\n", tag, res);
+ return res;
+ }
+
+ if (readData[4] != 0x00) {
+ logError(1, "%s disableGesture: ERROR %08X\n", tag, ERROR_GESTURE_ENABLE_FAIL);
+ return ERROR_GESTURE_ENABLE_FAIL;
+ }
+
+ logError(0, "%s disableGesture DONE!\n", tag);
+ return OK;
+ } else {
+ logError(1, "%s disableGesture: Size not valid! %d > %d ERROR %08X\n", tag, size, GESTURE_MASK_SIZE);
+ return ERROR_OP_NOT_ALLOW;
+ }
+}
+
+int startAddCustomGesture(u8 gestureID)
+{
+ u8 cmd[3] = { FTS_CMD_GESTURE_CMD, GESTURE_START_ADD, gestureID };
+ int res;
+ u8 readData[FIFO_EVENT_SIZE];
+ int event_to_search[4] = { EVENTID_GESTURE, EVENT_TYPE_ENB, gestureID, GESTURE_START_ADD };
+
+ res = fts_writeFwCmd(cmd, 3);
+ if (res < OK) {
+ logError(1, "%s startAddCustomGesture: Impossible to start adding custom gesture ID = %02X! ERROR %08X\n", tag, gestureID, res);
+ return res;
+ }
+
+ res = pollForEvent(event_to_search, 4, readData, GENERAL_TIMEOUT);
+ if (res < OK) {
+ logError(1, "%s startAddCustomGesture: start add event not found! ERROR %08X\n", tag, res);
+ return res;
+ }
+
+ if (readData[2] != gestureID || readData[4] != 0x00) { /* check of gestureID is redundant */
+ logError(1, "%s startAddCustomGesture: start add event status not OK! ERROR %08X\n", tag, readData[4]);
+ return ERROR_GESTURE_START_ADD;
+ }
+
+ return OK;
+}
+
+int finishAddCustomGesture(u8 gestureID)
+{
+ u8 cmd[3] = { FTS_CMD_GESTURE_CMD, GESTURE_FINISH_ADD, gestureID };
+ int res;
+ u8 readData[FIFO_EVENT_SIZE];
+ int event_to_search[4] = { EVENTID_GESTURE, EVENT_TYPE_ENB, gestureID, GESTURE_FINISH_ADD };
+
+ res = fts_writeFwCmd(cmd, 3);
+ if (res < OK) {
+ logError(1, "%s finishAddCustomGesture: Impossible to finish adding custom gesture ID = %02X! ERROR %08X\n", tag, gestureID, res);
+ return res;
+ }
+
+ res = pollForEvent(event_to_search, 4, readData, GENERAL_TIMEOUT);
+ if (res < OK) {
+ logError(1, "%s finishAddCustomGesture: finish add event not found! ERROR %08X\n", tag, res);
+ return res;
+ }
+
+ if (readData[2] != gestureID || readData[4] != 0x00) { /* check of gestureID is redundant */
+ logError(1, "%s finishAddCustomGesture: finish add event status not OK! ERROR %08X\n", tag, readData[4]);
+ return ERROR_GESTURE_FINISH_ADD;
+ }
+
+ return OK;
+
+}
+
+int loadCustomGesture(u8 *template, u8 gestureID)
+{
+ int res, i;
+ int remaining = GESTURE_CUSTOM_POINTS;
+ int toWrite, offset = 0;
+ u8 cmd[TEMPLATE_CHUNK + 5];
+ int event_to_search[4] = { EVENTID_GESTURE, EVENT_TYPE_ENB, gestureID, GESTURE_DATA_ADD };
+ u8 readData[FIFO_EVENT_SIZE];
+
+ logError(0, "%s Starting adding custom gesture procedure...\n", tag);
+
+ res = startAddCustomGesture(gestureID);
+ if (res < OK) {
+ logError(1, "%s loadCustomGesture: unable to start adding procedure! ERROR %08X\n", tag, res);
+ return res;
+ }
+
+ cmd[0] = FTS_CMD_GESTURE_CMD;
+ cmd[1] = GESTURE_DATA_ADD;
+ cmd[2] = gestureID;
+ while (remaining > 0) {
+ if (remaining > TEMPLATE_CHUNK) {
+ toWrite = TEMPLATE_CHUNK;
+ } else {
+ toWrite = remaining;
+ }
+
+ cmd[3] = toWrite;
+ cmd[4] = offset;
+ for (i = 0; i < toWrite; i++) {
+ cmd[i + 5] = template[i];
+ }
+
+ res = fts_writeFwCmd(cmd, toWrite + 5);
+ if (res < OK) {
+ logError(1, "%s loadCustomGesture: unable to start adding procedure! ERROR %08X\n", tag, res);
+ return res;
+ }
+
+ res = pollForEvent(event_to_search, 4, readData, GENERAL_TIMEOUT);
+ if (res < OK) {
+ logError(1, "%s loadCustomGesture: add event not found! ERROR %08X\n", tag, res);
+ return res;
+ }
+
+ if (readData[2] != gestureID || readData[4] != 0x00) { /* check of gestureID is redundant */
+ logError(1, "%s loadCustomGesture: add event status not OK! ERROR %08X\n", tag, readData[4]);
+ return ERROR_GESTURE_DATA_ADD;
+ }
+
+ remaining -= toWrite;
+ offset += toWrite / 2;
+ }
+
+ res = finishAddCustomGesture(gestureID);
+ if (res < OK) {
+ logError(1, "%s loadCustomGesture: unable to finish adding procedure! ERROR %08X\n", tag, res);
+ return res;
+ }
+
+ logError(0, "%s Adding custom gesture procedure DONE!\n", tag);
+ return OK;
+
+}
+
+int reloadCustomGesture(void)
+{
+ int res, i;
+
+ logError(0, "%s Starting reload Gesture Template...\n", tag);
+
+ for (i = 0; i < GESTURE_CUSTOM_NUMBER; i++) {
+ if (custom_gesture_index[i] == 1) {
+ res = loadCustomGesture(custom_gestures[i], GESTURE_CUSTOM_OFFSET+i);
+ if (res < OK) {
+ logError(1, "%s reloadCustomGesture: Impossible to load custom gesture ID = %02X! ERROR %08X\n", tag, GESTURE_CUSTOM_OFFSET + i, res);
+ return res;
+ }
+ }
+ }
+
+ logError(0, "%s Reload Gesture Template DONE!\n", tag);
+ return OK;
+
+}
+
+int enterGestureMode(int reload)
+{
+ u8 cmd = FTS_CMD_GESTURE_MODE;
+ int res, ret;
+
+ res = fts_disableInterrupt();
+ if (res < OK) {
+ logError(1, "%s enterGestureMode: ERROR %08X\n", tag, res|ERROR_DISABLE_INTER);
+ return res | ERROR_DISABLE_INTER;
+ }
+
+ if (reload == 1) {
+
+ res = reloadCustomGesture();
+ if (res < OK) {
+ logError(1, "%s enterGestureMode: impossible reload custom gesture! ERROR %08X\n", tag, res);
+ goto END;
+ }
+
+ res = disableGesture(NULL, 0);
+ if (res < OK) {
+ logError(1, "%s enterGestureMode: disableGesture ERROR %08X\n", tag, res);
+ goto END;
+ }
+
+ res = enableGesture(NULL, 0);
+ if (res < OK) {
+ logError(1, "%s enterGestureMode: enableGesture ERROR %08X\n", tag, res);
+ goto END;
+ }
+ }
+
+ res = fts_writeFwCmd(&cmd, 1);
+ if (res < OK) {
+ logError(1, "%s enterGestureMode: enter gesture mode ERROR %08X\n", tag, res);
+ goto END;
+ }
+
+ res = OK;
+END:
+ ret = fts_enableInterrupt();
+ if (ret < OK) {
+ logError(1, "%s enterGestureMode: fts_enableInterrupt ERROR %08X\n", tag, res | ERROR_ENABLE_INTER);
+ res |= ret | ERROR_ENABLE_INTER;
+ }
+
+ return res;
+}
+
+int addCustomGesture(u8 *data, int size, u8 gestureID)
+{
+ int index, res, i;
+
+ index = gestureID - GESTURE_CUSTOM_OFFSET;
+
+ logError(0, "%s Starting Custom Gesture Adding procedure...\n", tag);
+ if (size != GESTURE_CUSTOM_POINTS && gestureID != GES_ID_CUST1 && gestureID != GES_ID_CUST2 && gestureID != GES_ID_CUST3 && gestureID != GES_ID_CUST4 && gestureID && GES_ID_CUST5) {
+ logError(1, "%s addCustomGesture: Invalid size (%d) or Custom GestureID (%02X)! ERROR %08X\n", tag, size, gestureID, ERROR_OP_NOT_ALLOW);
+ return ERROR_OP_NOT_ALLOW;
+ }
+
+ for (i = 0; i < GESTURE_CUSTOM_POINTS; i++) {
+ custom_gestures[index][i] = data[i];
+ }
+
+ res = loadCustomGesture(custom_gestures[index], gestureID);
+ if (res < OK) {
+ logError(1, "%s addCustomGesture: impossible to load the custom gesture! ERROR %08X\n", tag, res);
+ return res;
+ }
+
+ custom_gesture_index[index] = 1;
+ logError(0, "%s Custom Gesture Adding procedure DONE!\n", tag);
+ return OK;
+}
+
+int removeCustomGesture(u8 gestureID)
+{
+ int res, index;
+ u8 cmd[3] = { FTS_CMD_GESTURE_CMD, GETURE_REMOVE_CUSTOM, gestureID };
+ int event_to_search[4] = {EVENTID_GESTURE, EVENT_TYPE_ENB, gestureID, GETURE_REMOVE_CUSTOM };
+ u8 readData[FIFO_EVENT_SIZE];
+
+ index = gestureID - GESTURE_CUSTOM_OFFSET;
+
+ logError(0, "%s Starting Custom Gesture Removing procedure...\n", tag);
+ if (gestureID != GES_ID_CUST1 && gestureID != GES_ID_CUST2 && gestureID != GES_ID_CUST3 && gestureID != GES_ID_CUST4 && gestureID && GES_ID_CUST5) {
+ logError(1, "%s removeCustomGesture: Invalid size (%d) or Custom GestureID (%02X)! ERROR %08X\n", tag, gestureID, ERROR_OP_NOT_ALLOW);
+ return ERROR_OP_NOT_ALLOW;
+ }
+
+ res = fts_writeFwCmd(cmd, 3);/* when a gesture is removed, it is also disabled automatically */
+ if (res < OK) {
+ logError(1, "%s removeCustomGesture: Impossible to remove custom gesture ID = %02X! ERROR %08X\n", tag, gestureID, res);
+ return res;
+ }
+
+ res = pollForEvent(event_to_search, 4, readData, GENERAL_TIMEOUT);
+ if (res < OK) {
+ logError(1, "%s removeCustomGesture: remove event not found! ERROR %08X\n", tag, res);
+ return res;
+ }
+
+ if (readData[2] != gestureID || readData[4] != 0x00) { /* check of gestureID is redundant */
+ logError(1, "%s removeCustomGesture: remove event status not OK! ERROR %08X\n", tag, readData[4]);
+ return ERROR_GESTURE_REMOVE;
+ }
+
+ custom_gesture_index[index] = 0;
+ logError(0, "%s Custom Gesture Remove procedure DONE!\n", tag);
+ return OK;
+
+}
diff --git a/drivers/input/touchscreen/st/fts_lib/ftsGesture.h b/drivers/input/touchscreen/st/fts_lib/ftsGesture.h
new file mode 100644
index 000000000000..a9c3e3c05573
--- /dev/null
+++ b/drivers/input/touchscreen/st/fts_lib/ftsGesture.h
@@ -0,0 +1,74 @@
+/*
+
+**************************************************************************
+** STMicroelectronics **
+**************************************************************************
+** marco.cali@st.com **
+**************************************************************************
+* *
+* FTS Gesture Utilities *
+* *
+**************************************************************************
+**************************************************************************
+
+*/
+
+#define GESTURE_MASK_SIZE 8
+
+#define GESTURE_CUSTOM_POINTS (30*2)
+/* for each custom gesture should be provided 30 points (each point is a couple of x,y) */
+#define GESTURE_CUSTOM_NUMBER 5 /* fw support up to 5 custom gestures */
+
+#define TEMPLATE_CHUNK (10*2)
+/* number of points to transfer with each I2C transaction */
+
+/* Gesture IDs */
+#define GES_ID_DBLTAP 0x01 /* Double Tap */
+#define GES_ID_O 0x02 /* 'O' */
+#define GES_ID_C 0x03 /* 'C' */
+#define GES_ID_M 0x04 /* 'M' */
+#define GES_ID_W 0x05 /* 'W' */
+#define GES_ID_E 0x06 /* 'e' */
+#define GES_ID_HFLIP_L2R 0x07 /* Left to right line */
+#define GES_ID_HFLIP_R2L 0x08 /* Right to left line */
+#define GES_ID_VFLIP_T2D 0x09 /* Top to bottom line */
+#define GES_ID_VFLIP_D2T 0x0A /* Bottom to Top line */
+#define GES_ID_L 0x0B /* 'L' */
+#define GES_ID_F 0x0C /* 'F' */
+#define GES_ID_V 0x0D /* 'V' */
+#define GES_ID_AT 0x0E /* '@' */
+#define GES_ID_S 0x0F /* 'S' */
+#define GES_ID_Z 0x10 /* 'Z' */
+#define GES_ID_CUST1 0x11 /* Custom gesture 1 */
+#define GES_ID_CUST2 0x12 /* Custom gesture 2 */
+#define GES_ID_CUST3 0x13 /* Custom gesture 3 */
+#define GES_ID_CUST4 0x14 /* Custom gesture 4 */
+#define GES_ID_CUST5 0x15 /* Custom gesture 5 */
+#define GES_ID_LEFTBRACE 0x20 /* '<' */
+#define GES_ID_RIGHTBRACE 0x21 /* '>' */
+
+#define GESTURE_CUSTOM_OFFSET GES_ID_CUST1
+
+/* Command sub-type */
+#define GESTURE_ENABLE 0x01
+#define GESTURE_DISABLE 0x02
+#define GESTURE_ENB_CHECK 0x03
+#define GESTURE_START_ADD 0x10
+#define GESTURE_DATA_ADD 0x11
+#define GESTURE_FINISH_ADD 0x12
+#define GETURE_REMOVE_CUSTOM 0x13
+#define GESTURE_CHECK_CUSTOM 0x14
+
+/* Event sub-type */
+#define EVENT_TYPE_ENB 0x04
+#define EVENT_TYPE_CHECK_ENB 0x03
+#define EVENT_TYPE_GESTURE_DTC1 0x01
+#define EVENT_TYPE_GESTURE_DTC2 0x02
+
+int disableGesture(u8 *mask, int size);
+int enableGesture(u8 *mask, int size);
+int startAddCustomGesture(u8 gestureID);
+int finishAddCustomGesture(u8 gestureID);
+int loadCustomGesture(u8 *template, u8 gestureID);
+int reloadCustomGesture(void);
+int enterGestureMode(int reload);
diff --git a/drivers/input/touchscreen/st/fts_lib/ftsHardware.h b/drivers/input/touchscreen/st/fts_lib/ftsHardware.h
new file mode 100644
index 000000000000..933059e671b4
--- /dev/null
+++ b/drivers/input/touchscreen/st/fts_lib/ftsHardware.h
@@ -0,0 +1,177 @@
+/*
+
+**************************************************************************
+** STMicroelectronics **
+**************************************************************************
+** marco.cali@st.com **
+**************************************************************************
+* *
+* HW related data *
+* *
+**************************************************************************
+**************************************************************************
+
+*/
+
+#define FTM3_CHIP
+
+/* DUMMY BYTES DATA */
+#define DUMMY_HW_REG 1
+#define DUMMY_FRAMEBUFFER 1
+#define DUMMY_MEMORY 1
+
+/* DIGITAL CHIP INFO */
+#ifdef FTM3_CHIP
+#define DCHIP_ID_0 0x39
+#define DCHIP_ID_1 0x6C
+#else
+#define DCHIP_ID_0 0x36
+#define DCHIP_ID_1 0x70
+#endif
+
+#ifdef FTM3_CHIP
+#define DCHIP_ID_ADDR 0x0007
+#define DCHIP_FW_VER_ADDR 0x000A
+#else
+#define DCHIP_ID_ADDR 0x0004
+#define DCHIP_FW_VER_ADDR 0x000B
+#endif
+
+#define DCHIP_FW_VER_BYTE 2
+
+/* CHUNKS */
+#define READ_CHUNK (2*1024)
+#define WRITE_CHUNK (2*1024)
+#define MEMORY_CHUNK (2*1024)
+
+/* PROTOCOL INFO */
+#ifdef FTM3_CHIP
+#define I2C_SAD 0x49
+#else
+#define I2C_SAD 0x48
+#endif
+
+#define I2C_INTERFACE /* comment if the chip use SPI */
+#define ICR_ADDR 0x0024
+#define ICR_SPI_VALUE 0x02
+
+/* SYSTEM RESET INFO */
+#ifdef FTM3_CHIP
+#define SYSTEM_RESET_ADDRESS 0x0023
+#define SYSTEM_RESET_VALUE 0x01
+#else
+#define SYSTEM_RESET_ADDRESS 0x0028
+#define SYSTEM_RESET_VALUE 0x80
+#endif
+
+/* INTERRUPT INFO */
+#ifdef FTM3_CHIP
+#define IER_ADDR 0x001C
+#else
+#define IER_ADDR 0x002C
+#endif
+
+#define IER_ENABLE 0x41
+#define IER_DISABLE 0x00
+
+/* FLASH COMMAND */
+
+#define FLASH_CMD_UNLOCK 0xF7
+
+#ifdef FTM3_CHIP
+#define FLASH_CMD_WRITE_LOWER_64 0xF0
+#define FLASH_CMD_WRITE_UPPER_64 0xF1
+#define FLASH_CMD_BURN 0xF2
+#define FLASH_CMD_ERASE 0xF3
+#define FLASH_CMD_READSTATUS 0xF4
+#else
+#define FLASH_CMD_WRITE_64K 0xF8
+#define FLASH_CMD_READ_REGISTER 0xF9
+#define FLASH_CMD_WRITE_REGISTER 0xFA
+#endif
+
+/* FLASH UNLOCK PARAMETER */
+#define FLASH_UNLOCK_CODE0 0x74
+#define FLASH_UNLOCK_CODE1 0x45
+
+#ifndef FTM3_CHIP
+/* FLASH ERASE and DMA PARAMETER */
+#define FLASH_ERASE_UNLOCK_CODE0 0x72
+#define FLASH_ERASE_UNLOCK_CODE1 0x03
+#define FLASH_ERASE_UNLOCK_CODE2 0x02
+#define FLASH_ERASE_CODE0 0x02
+#define FLASH_ERASE_CODE1 0xC0
+#define FLASH_DMA_CODE0 0x05
+#define FLASH_DMA_CODE1 0xC0
+#define FLASH_DMA_CONFIG 0x06
+#endif
+
+/* FLASH ADDRESS */
+#ifdef FTM3_CHIP
+#define FLASH_ADDR_SWITCH_CMD 0x00010000
+#define FLASH_ADDR_CODE 0x00000000
+#define FLASH_ADDR_CONFIG 0x0001E800
+#define FLASH_ADDR_CX 0x0001F000
+#else
+#define ADDR_WARM_BOOT 0x001E
+#define WARM_BOOT_VALUE 0x38
+#define FLASH_ADDR_CODE 0x00000000
+#define FLASH_ADDR_CONFIG 0x0000FC00
+#endif
+
+/* CRC ADDR */
+#ifdef FTM3_CHIP
+#define ADDR_CRC_BYTE0 0x00
+#define ADDR_CRC_BYTE1 0x86
+#define CRC_MASK 0x02
+#else
+#define ADDR_CRC_BYTE0 0x00
+#define ADDR_CRC_BYTE1 0x74
+#define CRC_MASK 0x03
+#endif
+
+/* SIZES FW, CODE, CONFIG, MEMH */
+#ifdef FTM3_CHIP
+#define FW_HEADER_SIZE 32
+#define FW_SIZE (int)(128*1024)
+#define FW_CODE_SIZE (int)(122*1024)
+#define FW_CONFIG_SIZE (int)(2*1024)
+#define FW_CX_SIZE (int)(FW_SIZE-FW_CODE_SIZE-FW_CONFIG_SIZE)
+#define FW_VER_MEMH_BYTE1 193
+#define FW_VER_MEMH_BYTE0 192
+#define FW_OFF_CONFID_MEMH_BYTE1 2
+#define FW_OFF_CONFID_MEMH_BYTE0 1
+#define FW_BIN_VER_OFFSET 4
+#define FW_BIN_CONFIG_VER_OFFSET (FW_HEADER_SIZE+FW_CODE_SIZE+1)
+#else
+#define FW_HEADER_SIZE 64
+#define FW_HEADER_SIGNATURE 0xAA55AA55
+#define FW_FTB_VER 0x00000001
+#define FW_BYTES_ALIGN 4
+#define FW_BIN_VER_OFFSET 16
+#define FW_BIN_CONFIG_VER_OFFSET 20
+#endif
+
+/* FIFO */
+#define FIFO_EVENT_SIZE 8
+#ifdef FTM3_CHIP
+#define FIFO_DEPTH 32
+#else
+#define FIFO_DEPTH 64
+#endif
+
+#define FIFO_CMD_READONE 0x85
+#define FIFO_CMD_READALL 0x86
+#define FIFO_CMD_LAST 0x87
+#define FIFO_CMD_FLUSH 0xA1
+
+/* CONSTANT TOTAL CX */
+#define CX1_WEIGHT 4
+#define CX2_WEIGHT 1
+
+/* OP CODES FOR MEMORY (based on protocol) */
+
+#define FTS_CMD_HW_REG_R 0xB6
+#define FTS_CMD_HW_REG_W 0xB6
+#define FTS_CMD_FRAMEBUFFER_R 0xD0
+#define FTS_CMD_FRAMEBUFFER_W 0xD0
diff --git a/drivers/input/touchscreen/st/fts_lib/ftsIO.c b/drivers/input/touchscreen/st/fts_lib/ftsIO.c
new file mode 100644
index 000000000000..96ca8cfecd8a
--- /dev/null
+++ b/drivers/input/touchscreen/st/fts_lib/ftsIO.c
@@ -0,0 +1,403 @@
+/*
+
+**************************************************************************
+** STMicroelectronics **
+**************************************************************************
+** marco.cali@st.com **
+**************************************************************************
+* *
+* I2C/SPI Communication *
+* *
+**************************************************************************
+**************************************************************************
+
+*/
+
+#include "ftsSoftware.h"
+#include "ftsCrossCompile.h"
+
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/platform_device.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <stdarg.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/serio.h>
+#include <linux/init.h>
+#include <linux/pm.h>
+#include <linux/delay.h>
+#include <linux/ctype.h>
+#include <linux/gpio.h>
+#include <linux/i2c.h>
+#include <linux/i2c-dev.h>
+#include <linux/fs.h>
+#include <linux/uaccess.h>
+#include <linux/power_supply.h>
+#include <linux/firmware.h>
+#include <linux/regulator/consumer.h>
+#include <linux/of_gpio.h>
+/* #include <linux/sec_sysfs.h> */
+#include <linux/i2c.h>
+#include <linux/i2c-dev.h>
+#include <linux/spi/spidev.h>
+static struct i2c_client *client;
+static u16 I2CSAD;
+
+#include "ftsError.h"
+#include "ftsHardware.h"
+#include "ftsIO.h"
+#include "ftsTool.h"
+
+static char tag[8] = "[ FTS ]\0";
+
+int openChannel(struct i2c_client *clt)
+{
+ client = clt;
+ I2CSAD = clt->addr;
+ logError(1, "%s openChannel: SAD: %02X\n", tag, I2CSAD);
+ return OK;
+}
+
+struct device *getDev(void)
+{
+ if (client != NULL)
+ return &(client->dev);
+ else
+ return NULL;
+}
+
+struct i2c_client *getClient(void)
+{
+ if (client != NULL)
+ return client;
+ else
+ return NULL;
+}
+
+int fts_readCmd(u8 *cmd, int cmdLength, u8 *outBuf, int byteToRead)
+{
+ int ret = -1;
+ int retry = 0;
+ struct i2c_msg I2CMsg[2];
+
+ /* write msg */
+ I2CMsg[0].addr = (__u16)I2CSAD;
+ I2CMsg[0].flags = (__u16)0;
+ I2CMsg[0].len = (__u16)cmdLength;
+ I2CMsg[0].buf = (__u8 *)cmd;
+
+ /* read msg */
+ I2CMsg[1].addr = (__u16)I2CSAD;
+ I2CMsg[1].flags = I2C_M_RD;
+ I2CMsg[1].len = byteToRead;
+ I2CMsg[1].buf = (__u8 *)outBuf;
+
+ if (client == NULL)
+ return ERROR_I2C_O;
+ while (retry < I2C_RETRY && ret < OK) {
+ ret = i2c_transfer(client->adapter, I2CMsg, 2);
+ if (ret >= OK)
+ break;
+ retry++;
+ msleep(I2C_WAIT_BEFORE_RETRY);
+ }
+ if (ret < 0) {
+ logError(1, "%s fts_readCmd: ERROR %02X\n", tag, ERROR_I2C_R);
+ return ERROR_I2C_R;
+ }
+ return OK;
+}
+
+int fts_writeCmd(u8 *cmd, int cmdLength)
+{
+ int ret = -1;
+ int retry = 0;
+ struct i2c_msg I2CMsg[2];
+
+ I2CMsg[0].addr = (__u16)I2CSAD;
+ I2CMsg[0].flags = (__u16)0;
+ I2CMsg[0].len = (__u16)cmdLength;
+ I2CMsg[0].buf = (__u8 *)cmd;
+
+ if (client == NULL)
+return ERROR_I2C_O;
+ while (retry < I2C_RETRY && ret < OK) {
+ ret = i2c_transfer(client->adapter, I2CMsg, 1);
+ if (ret >= OK)
+ break;
+ retry++;
+ msleep(I2C_WAIT_BEFORE_RETRY);
+ /* logError(1, "%s fts_writeCmd: attempt %d\n", tag, retry); */
+ }
+ if (ret < 0) {
+ logError(1, "%s fts_writeCmd: ERROR %02X\n", tag, ERROR_I2C_W);
+ return ERROR_I2C_W;
+ }
+ return OK;
+}
+
+int fts_writeFwCmd(u8 *cmd, int cmdLength)
+{
+ int ret = -1;
+ int ret2 = -1;
+ int retry = 0;
+ struct i2c_msg I2CMsg[2];
+
+ I2CMsg[0].addr = (__u16)I2CSAD;
+ I2CMsg[0].flags = (__u16)0;
+ I2CMsg[0].len = (__u16)cmdLength;
+ I2CMsg[0].buf = (__u8 *)cmd;
+
+ if (client == NULL)
+return ERROR_I2C_O;
+ while (retry < I2C_RETRY && (ret < OK || ret2 < OK)) {
+ ret = i2c_transfer(client->adapter, I2CMsg, 1);
+ retry++;
+ if (ret >= 0) {
+ ret2 = checkEcho(cmd, cmdLength);
+ break;
+ }
+ msleep(I2C_WAIT_BEFORE_RETRY);
+ /* logError(1, "%s fts_writeCmd: attempt %d\n", tag, retry); */
+ }
+ if (ret < 0) {
+ logError(1, "%s fts_writeFwCmd: ERROR %02X\n", tag, ERROR_I2C_W);
+ return ERROR_I2C_W;
+ }
+ if (ret2 < OK) {
+ logError(1, "%s fts_writeFwCmd: check echo ERROR %02X\n", tag, ret2);
+ return (ret|ERROR_I2C_W);
+ }
+ return OK;
+}
+
+int writeReadCmd(u8 *writeCmd1, int writeCmdLength, u8 *readCmd1,
+ int readCmdLength, u8 *outBuf, int byteToRead)
+{
+ int ret = -1;
+ int retry = 0;
+ struct i2c_msg I2CMsg[3];
+
+ /* write msg */
+ I2CMsg[0].addr = (__u16)I2CSAD;
+ I2CMsg[0].flags = (__u16)0;
+ I2CMsg[0].len = (__u16)writeCmdLength;
+ I2CMsg[0].buf = (__u8 *)writeCmd1;
+
+ /* write msg */
+ I2CMsg[1].addr = (__u16)I2CSAD;
+ I2CMsg[1].flags = (__u16)0;
+ I2CMsg[1].len = (__u16)readCmdLength;
+ I2CMsg[1].buf = (__u8 *)readCmd1;
+
+ /* read msg */
+ I2CMsg[2].addr = (__u16)I2CSAD;
+ I2CMsg[2].flags = I2C_M_RD;
+ I2CMsg[2].len = byteToRead;
+ I2CMsg[2].buf = (__u8 *)outBuf;
+
+ if (client == NULL)
+ return ERROR_I2C_O;
+ while (retry < I2C_RETRY && ret < OK) {
+ ret = i2c_transfer(client->adapter, I2CMsg, 3);
+ if (ret >= OK)
+ break;
+ retry++;
+ msleep(I2C_WAIT_BEFORE_RETRY);
+ }
+
+ if (ret < 0) {
+ logError(1, "%s writeReadCmd: ERROR %02X\n", tag, ERROR_I2C_WR);
+ return ERROR_I2C_WR;
+ }
+ return OK;
+
+}
+
+int readCmdU16(u8 cmd, u16 address, u8 *outBuf, int byteToRead, int hasDummyByte)
+{
+
+ int remaining = byteToRead;
+ int toRead = 0;
+ u8 rCmd[3] = { cmd, 0x00, 0x00 };
+
+ u8 *buff = (u8 *)kmalloc((READ_CHUNK + 1)*sizeof(u8), GFP_KERNEL);
+ if (buff == NULL) {
+ logError(1, "%s readCmdU16: ERROR %02X\n", tag, ERROR_ALLOC);
+ return ERROR_ALLOC;
+ }
+
+ while (remaining > 0) {
+ if (remaining >= READ_CHUNK) {
+ toRead = READ_CHUNK;
+ remaining -= READ_CHUNK;
+ } else {
+ toRead = remaining;
+ remaining = 0;
+ }
+
+ rCmd[1] = (u8)((address & 0xFF00) >> 8);
+ rCmd[2] = (u8)(address & 0xFF);
+
+ if (hasDummyByte) {
+ if (fts_readCmd(rCmd, 3, buff, toRead + 1) < 0) {
+ logError(1, "%s readCmdU16: ERROR %02X\n", tag, ERROR_I2C_R);
+ return ERROR_I2C_R;
+ }
+ memcpy(outBuf, buff + 1, toRead);
+ } else {
+ if (fts_readCmd(rCmd, 3, buff, toRead) < 0)
+ return ERROR_I2C_R;
+ memcpy(outBuf, buff, toRead);
+ }
+
+ address += toRead;
+
+ outBuf += toRead;
+
+ }
+ kfree(buff);
+
+ return OK;
+}
+
+int writeCmdU16(u8 WriteCmd, u16 address, u8 *dataToWrite, int byteToWrite)
+{
+
+ int remaining = byteToWrite;
+ int toWrite = 0;
+
+ u8 *buff = (u8 *)kmalloc((WRITE_CHUNK + 3)*sizeof(u8), GFP_KERNEL);
+ if (buff == NULL) {
+ logError(1, "%s writeCmdU16: ERROR %02X\n", tag, ERROR_ALLOC);
+ return ERROR_ALLOC;
+ }
+
+ buff[0] = WriteCmd;
+
+ while (remaining > 0) {
+ if (remaining >= WRITE_CHUNK) {
+ toWrite = WRITE_CHUNK;
+ remaining -= WRITE_CHUNK;
+ } else {
+ toWrite = remaining;
+ remaining = 0;
+ }
+
+ buff[1] = (u8)((address & 0xFF00) >> 8);
+ buff[2] = (u8)(address & 0xFF);
+ memcpy(buff + 3, dataToWrite, toWrite);
+ if (fts_writeCmd(buff, 3 + toWrite) < 0) {
+ logError(1, "%s writeCmdU16: ERROR %02\n", tag, ERROR_I2C_W);
+ return ERROR_I2C_W;
+ }
+ address += toWrite;
+ dataToWrite += toWrite;
+
+ }
+
+ return OK;
+}
+
+int writeCmdU32(u8 writeCmd1, u8 writeCmd2, u32 address, u8 *dataToWrite, int byteToWrite)
+{
+
+ int remaining = byteToWrite;
+ int toWrite = 0;
+
+ u8 buff1[3] = { writeCmd1, 0x00, 0x00 };
+ u8 *buff2 = (u8 *)kmalloc((WRITE_CHUNK + 3)*sizeof(u8), GFP_KERNEL);
+ if (buff2 == NULL) {
+ logError(1, "%s writeCmdU32: ERROR %02X\n", tag, ERROR_ALLOC);
+ return ERROR_ALLOC;
+ }
+ buff2[0] = writeCmd2;
+
+ while (remaining > 0) {
+ if (remaining >= WRITE_CHUNK) {
+ toWrite = WRITE_CHUNK;
+ remaining -= WRITE_CHUNK;
+ } else {
+ toWrite = remaining;
+ remaining = 0;
+ }
+
+ buff1[1] = (u8)((address & 0xFF000000) >> 24);
+ buff1[2] = (u8)((address & 0x00FF0000) >> 16);
+ buff2[1] = (u8)((address & 0x0000FF00) >> 8);
+ buff2[2] = (u8)(address & 0xFF);
+ memcpy(buff2 + 3, dataToWrite, toWrite);
+
+ if (fts_writeCmd(buff1, 3) < 0) {
+ logError(1, "%s writeCmdU32: ERROR %02X\n", tag, ERROR_I2C_W);
+ return ERROR_I2C_W;
+ }
+ if (fts_writeCmd(buff2, 3 + toWrite) < 0) {
+ logError(1, "%s writeCmdU32: ERROR %02X\n", tag, ERROR_I2C_W);
+ return ERROR_I2C_W;
+ }
+
+ address += toWrite;
+ dataToWrite += toWrite;
+
+ }
+
+ return OK;
+}
+
+int writeReadCmdU32(u8 wCmd, u8 rCmd, u32 address, u8 *outBuf, int byteToRead, int hasDummyByte)
+{
+
+ int remaining = byteToRead;
+ int toRead = 0;
+ u8 reaCmd[3];
+ u8 wriCmd[3];
+
+ u8 *buff = (u8 *)kmalloc((READ_CHUNK + 1)*sizeof(u8), GFP_KERNEL);
+ if (buff == NULL) {
+ logError(1, "%s writereadCmd32: ERROR %02X\n", tag, ERROR_ALLOC);
+ return ERROR_ALLOC;
+ }
+
+ reaCmd[0] = rCmd;
+ wriCmd[0] = wCmd;
+
+ while (remaining > 0) {
+ if (remaining >= READ_CHUNK) {
+ toRead = READ_CHUNK;
+ remaining -= READ_CHUNK;
+ } else {
+ toRead = remaining;
+ remaining = 0;
+ }
+
+ wriCmd[1] = (u8)((address & 0xFF000000) >> 24);
+ wriCmd[2] = (u8)((address & 0x00FF0000) >> 16);
+
+ reaCmd[1] = (u8)((address & 0x0000FF00) >> 8);
+ reaCmd[2] = (u8)(address & 0x000000FF);
+
+ if (hasDummyByte) {
+ if (writeReadCmd(wriCmd, 3, reaCmd, 3, buff, toRead + 1) < 0) {
+ logError(1, "%s writeCmdU32: ERROR %02X\n", tag, ERROR_I2C_WR);
+ return ERROR_I2C_WR;
+ }
+ memcpy(outBuf, buff + 1, toRead);
+ } else {
+ if (writeReadCmd(wriCmd, 3, reaCmd, 3, buff, toRead) < 0)
+ return ERROR_I2C_WR;
+ memcpy(outBuf, buff, toRead);
+ }
+
+ address += toRead;
+
+ outBuf += toRead;
+
+ }
+
+ return OK;
+}
diff --git a/drivers/input/touchscreen/st/fts_lib/ftsIO.h b/drivers/input/touchscreen/st/fts_lib/ftsIO.h
new file mode 100644
index 000000000000..7bdeda2f9a2d
--- /dev/null
+++ b/drivers/input/touchscreen/st/fts_lib/ftsIO.h
@@ -0,0 +1,35 @@
+/*
+
+**************************************************************************
+** STMicroelectronics **
+**************************************************************************
+** marco.cali@st.com **
+**************************************************************************
+* *
+* I2C/SPI Communication *
+* *
+**************************************************************************
+**************************************************************************
+
+*/
+
+#include "ftsSoftware.h"
+#include "ftsCrossCompile.h"
+
+#include <linux/i2c.h>
+#include <linux/i2c-dev.h>
+
+#define I2C_RETRY 3 /* number */
+#define I2C_WAIT_BEFORE_RETRY 10 /* ms */
+
+int openChannel(struct i2c_client *clt);
+struct device *getDev(void);
+struct i2c_client *getClient(void);
+int fts_readCmd(u8 *cmd, int cmdLenght, u8 *outBuf, int byteToRead);
+int fts_writeCmd(u8 *cmd, int cmdLenght);
+int fts_writeFwCmd(u8 *cmd, int cmdLenght);
+int writeReadCmd(u8 *writeCmd, int writeCmdLenght, u8 *readCmd, int readCmdLenght, u8 *outBuf, int byteToRead);
+int readCmdU16(u8 cmd, u16 address, u8 *outBuf, int byteToRead, int hasDummyByte);
+int writeCmdU16(u8 WriteCmd, u16 address, u8 *dataToWrite, int byteToWrite);
+int writeCmdU32(u8 writeCmd1, u8 writeCmd2, u32 address, u8 *dataToWrite, int byteToWrite);
+int writeReadCmdU32(u8 wCmd, u8 rCmd, u32 address, u8 *outBuf, int byteToRead, int hasDummyByte);
diff --git a/drivers/input/touchscreen/st/fts_lib/ftsSoftware.h b/drivers/input/touchscreen/st/fts_lib/ftsSoftware.h
new file mode 100644
index 000000000000..c8bbc8e18d28
--- /dev/null
+++ b/drivers/input/touchscreen/st/fts_lib/ftsSoftware.h
@@ -0,0 +1,131 @@
+/*
+
+**************************************************************************
+** STMicroelectronics **
+**************************************************************************
+** marco.cali@st.com **
+**************************************************************************
+* *
+* FW related data *
+* *
+**************************************************************************
+**************************************************************************
+
+*/
+
+#include "ftsHardware.h"
+
+typedef unsigned char u8;
+typedef unsigned short u16;
+typedef unsigned int u32;
+
+#define ECHO_ENABLED 0x00000001
+
+/* chipInfo ftsInfo; */
+
+/* FTS FW COMAND */
+#define FTS_CMD_MS_MT_SENSE_OFF 0x92
+#define FTS_CMD_MS_MT_SENSE_ON 0x93
+#define FTS_CMD_SS_HOVER_OFF 0x94
+#define FTS_CMD_SS_HOVER_ON 0x95
+#define FTS_CMD_LP_TIMER_CALIB 0x97
+#define FTS_CMD_MS_KEY_OFF 0x9A
+#define FTS_CMD_MS_KEY_ON 0x9B
+#define FTS_CMD_MS_COMP_TUNING 0xA3
+#define FTS_CMD_SS_COMP_TUNING 0xA4
+#define FTS_CMD_FULL_INITIALIZATION 0xA5
+#define FTS_CMD_ITO_CHECK 0xA7
+#define FTS_CMD_RELEASE_INFO 0xAA
+#define FTS_CMD_GESTURE_MODE 0xAD
+#define FTS_CMD_REQU_FW_CONF 0xB2
+#define FTS_CMD_REQU_FRAME_DATA 0xB7
+#define FTS_CMD_REQU_COMP_DATA 0xB8
+#define FTS_CMD_WRITE_MP_FLAG 0xC0
+#define FTS_CMD_FEATURE_ENABLE 0xC1
+#define FTS_CMD_FEATURE_DISABLE 0xC2
+#define FTS_CMD_GESTURE_CMD 0xC3
+#define FTS_CMD_SAVE_CX_TUNING 0xFC
+
+/* Event ID */
+#define EVENTID_NO_EVENT 0x00
+#define EVENTID_ERROR_EVENT 0x0F
+#define EVENTID_CONTROL_READY 0x10
+#define EVENTID_FW_CONFIGURATION 0x12
+#define EVENTID_COMP_DATA_READ 0x13
+#define EVENTID_STATUS_UPDATE 0x16
+#define EVENTID_RELEASE_INFO 0x1C
+#define EVENTID_ENTER_POINTER 0x03
+#define EVENTID_LEAVE_POINTER 0x04
+#define EVENTID_MOTION_POINTER 0x05
+#define EVENTID_HOVER_ENTER_POINTER 0x07
+#define EVENTID_HOVER_LEAVE_POINTER 0x08
+#define EVENTID_HOVER_MOTION_POINTER 0x09
+#define EVENTID_PROXIMITY_ENTER 0x0B
+#define EVENTID_PROXIMITY_LEAVE 0x0C
+#define EVENTID_KEY_STATUS 0x0E
+#define EVENTID_GESTURE 0x22
+#define EVENTID_FRAME_DATA_READ 0x25
+#define EVENTID_ECHO 0xEC
+#define EVENTID_LAST (EVENTID_FRAME_DATA_READ+1)
+
+/* EVENT TYPE */
+#define EVENT_TYPE_MS_TUNING_CMPL 0x01
+#define EVENT_TYPE_SS_TUNING_CMPL 0x02
+#define EVENT_TYPE_COMP_DATA_SAVED 0x04
+#define EVENT_TYPE_ITO 0x05
+#define EVENT_TYPE_FULL_INITIALIZATION 0x07
+#define EVENT_TYPE_LPTIMER_TUNING_CMPL 0x20
+#define EVENT_TYPE_ESD_ERROR 0x0A
+#define EVENT_TYPE_WATCHDOG_ERROR 0x01
+
+/* CONFIG ID INFO */
+#define CONFIG_ID_ADDR 0x0001
+#define CONFIG_ID_BYTE 2
+
+/* ADDRESS OFFSET IN SYSINFO */
+#define ADDR_RAW_TOUCH 0x0000
+#define ADDR_FILTER_TOUCH 0x0002
+#define ADDR_NORM_TOUCH 0x0004
+#define ADDR_CALIB_TOUCH 0x0006
+#define ADDR_RAW_HOVER_FORCE 0x000A
+#define ADDR_RAW_HOVER_SENSE 0x000C
+#define ADDR_FILTER_HOVER_FORCE 0x000E
+#define ADDR_FILTER_HOVER_SENSE 0x0010
+#define ADDR_NORM_HOVER_FORCE 0x0012
+#define ADDR_NORM_HOVER_SENSE 0x0014
+#define ADDR_CALIB_HOVER_FORCE 0x0016
+#define ADDR_CALIB_HOVER_SENSE 0x0018
+#define ADDR_RAW_PRX_FORCE 0x001A
+#define ADDR_RAW_PRX_SENSE 0x001C
+#define ADDR_FILTER_PRX_FORCE 0x001E
+#define ADDR_FILTER_PRX_SENSE 0x0020
+#define ADDR_NORM_PRX_FORCE 0x0022
+#define ADDR_NORM_PRX_SENSE 0x0024
+#define ADDR_CALIB_PRX_FORCE 0x0026
+#define ADDR_CALIB_PRX_SENSE 0x0028
+#define ADDR_RAW_MS_KEY 0x0032
+#define ADDR_COMP_DATA 0x0050
+#define ADDR_FRAMEBUFFER_DATA 0x8000
+
+/* ADDRESS FW REGISTER */
+#define ADDR_SENSE_LEN 0x0014
+#define ADDR_FORCE_LEN 0x0015
+#define ADDR_MS_TUNING_VER 0x0729
+#define ADDR_SS_TUNING_VER 0x074E
+
+/* B2 INFO */
+#define B2_DATA_BYTES 4
+#define B2_CHUNK ((FIFO_DEPTH/2)*B2_DATA_BYTES) /* number of bytes */
+
+/* FEATURES */
+#define FEAT_GESTURE 0x00
+#define FEAT_GLOVE 0x01
+#define FEAT_STYLUS 0x02
+#define FEAT_COVER 0x04
+#define FEAT_CHARGER 0x08
+#define FEAT_VR 0x10
+#define FEAT_EDGE_REJECTION 0x20
+
+/* MP_FLAG_VALUE */
+#define INIT_MP 0xA5A5A501
+#define INIT_FIELD 0xA5A5A502
diff --git a/drivers/input/touchscreen/st/fts_lib/ftsTest.c b/drivers/input/touchscreen/st/fts_lib/ftsTest.c
new file mode 100644
index 000000000000..68bd04eff316
--- /dev/null
+++ b/drivers/input/touchscreen/st/fts_lib/ftsTest.c
@@ -0,0 +1,2324 @@
+/*
+
+ **************************************************************************
+ ** STMicroelectronics **
+ **************************************************************************
+ ** marco.cali@st.com **
+ **************************************************************************
+ * *
+ * FTS API for MP test *
+ * *
+ **************************************************************************
+ **************************************************************************
+
+ */
+
+#include "ftsCrossCompile.h"
+#include "ftsCompensation.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/init.h>
+#include <linux/errno.h>
+#include <linux/platform_device.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <stdarg.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/serio.h>
+#include <linux/time.h>
+#include <linux/pm.h>
+#include <linux/delay.h>
+#include <linux/ctype.h>
+#include <linux/gpio.h>
+#include <linux/i2c.h>
+#include <linux/i2c-dev.h>
+#include <linux/fs.h>
+#include <linux/uaccess.h>
+#include <linux/power_supply.h>
+#include <linux/firmware.h>
+#include <linux/regulator/consumer.h>
+#include <linux/of_gpio.h>
+/* #include <linux/sec_sysfs.h> */
+
+#ifdef LIMITS_H_FILE
+#include <../fts_limits.h>
+#endif
+
+/* static char tag[8] = "[ FTS ]\0"; */
+
+int computeAdjHoriz(u8 *data, int row, int column, u8 **result)
+{
+ int i, j;
+ int size = row * (column - 1);
+
+ if (column < 2) {
+ logError(1, "%s computeAdjHoriz: ERROR % 02X\n", tag, ERROR_OP_NOT_ALLOW);
+ return ERROR_OP_NOT_ALLOW;
+ }
+
+ *result = (u8 *) kmalloc(size * sizeof (u8), GFP_KERNEL);
+ if (*result == NULL) {
+ logError(1, "%s computeAdjHoriz: ERROR %02X\n", tag, 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;
+
+}
+
+int computeAdjHorizTotal(u16 *data, int row, int column, u16 **result)
+{
+ int i, j;
+ int size = row * (column - 1);
+
+ if (column < 2) {
+ logError(1, "%s computeAdjHorizTotal: ERROR % 02X\n", tag, ERROR_OP_NOT_ALLOW);
+ return ERROR_OP_NOT_ALLOW;
+ }
+
+ *result = (u16 *) kmalloc(size * sizeof (u16), GFP_KERNEL);
+ if (*result == NULL) {
+ logError(1, "%s computeAdjHorizTotal: ERROR %02X\n", tag, 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;
+
+}
+
+int computeAdjVert(u8 *data, int row, int column, u8 **result)
+{
+ int i, j;
+ int size = (row - 1)*(column);
+
+ if (row < 2) {
+ logError(1, "%s computeAdjVert: ERROR % 02X\n", tag, ERROR_OP_NOT_ALLOW);
+ return ERROR_OP_NOT_ALLOW;
+ }
+
+ *result = (u8 *) kmalloc(size * sizeof (u8), GFP_KERNEL);
+ if (*result == NULL) {
+ logError(1, "%s computeAdjVert: ERROR %02X\n", tag, 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;
+}
+
+int computeAdjVertTotal(u16 *data, int row, int column, u16 **result)
+{
+ int i, j;
+ int size = (row - 1)*(column);
+
+ if (row < 2) {
+ logError(1, "%s computeAdjVertTotal: ERROR % 02X\n", tag, ERROR_OP_NOT_ALLOW);
+ return ERROR_OP_NOT_ALLOW;
+ }
+
+ *result = (u16 *) kmalloc(size * sizeof (u16), GFP_KERNEL);
+ if (*result == NULL) {
+ logError(1, "%s computeAdjVertTotal: ERROR %02X\n", tag, 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;
+}
+
+int computeTotal(u8 *data, u8 main, int row, int column, int m, int n, u16 **result)
+{
+ int i, j;
+ int size = (row)*(column);
+
+ *result = (u16 *) kmalloc(size * sizeof (u16), GFP_KERNEL);
+ if (*result == NULL) {
+ logError(1, "%s computeTotal : ERROR %02X\n", tag, ERROR_ALLOC);
+ return ERROR_ALLOC;
+ }
+
+ for (i = 0; i < row; i++) {
+ for (j = 0; j < column; j++) {
+ *(*result + (i * column + j)) = m * main + n * data[i * column + j];
+ }
+ }
+
+ return 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) {
+ logError(1, "%s checkLimitsMinMax: Node[%d,%d] = %d exceed limit [%d, %d]\n", tag, i, j, data[i * column + j], min, max);
+ count++;
+ }
+ }
+ }
+
+ return count; /* if count is 0 = OK, test completed successfully */
+}
+
+int checkLimitsGap(short *data, int row, int column, int threshold)
+{
+ int i, j;
+ int min_node;
+ int max_node;
+
+ if (row == 0 || column == 0) {
+ logError(1, "%s checkLimitsGap: invalid number of rows = %d or columns = %d ERROR %02\n", tag, 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) {
+ logError(1, "%s checkLimitsGap: GAP = %d exceed limit %d\n", tag, max_node - min_node, threshold);
+ return ERROR_TEST_CHECK_FAIL;
+ } else
+ return OK;
+
+}
+
+int checkLimitsMap(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]) {
+ logError(1, "%s checkLimitsMap: Node[%d,%d] = %d exceed limit [%d, %d]\n", tag, 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 */
+}
+
+int checkLimitsMapTotal(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]) {
+ logError(1, "%s checkLimitsMapTotal: Node[%d,%d] = %d exceed limit [%d, %d]\n", tag, 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 */
+}
+
+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]) {
+ logError(1, "%s checkLimitsMapAdj: Node[%d,%d] = %d exceed limit > %d\n", tag, i, j, data[i * column + j], max[i * column + j]);
+ count++;
+ }
+ }
+ }
+
+ return count; /* if count is 0 = OK, test completed successfully */
+}
+
+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]) {
+ logError(1, "%s checkLimitsMapAdjTotal: Node[%d,%d] = %d exceed limit > %d\n", tag, i, j, data[i * column + j], max[i * column + j]);
+ count++;
+ }
+ }
+ }
+
+ return count; /* if count is 0 = OK, test completed successfully */
+}
+
+int production_test_ito(void)
+{
+ int res = OK;
+ u8 cmd;
+ u8 readData[FIFO_EVENT_SIZE];
+ int eventToSearch[2] = {EVENTID_ERROR_EVENT, EVENT_TYPE_ITO}; /* look for ito event */
+
+ logError(0, "%s ITO Production test is starting...\n", tag);
+
+ res = fts_system_reset();
+ if (res < 0) {
+ logError(1, "%s production_test_ito: ERROR %02X\n", tag, ERROR_PROD_TEST_ITO);
+ return (res | ERROR_PROD_TEST_ITO);
+ }
+
+ cmd = FTS_CMD_ITO_CHECK;
+
+ logError(0, "%s ITO Check command sent...\n", tag);
+ if (fts_writeFwCmd(&cmd, 1) < 0) {
+ logError(1, "%s production_test_ito: ERROR %02X\n", tag, (ERROR_I2C_W | ERROR_PROD_TEST_ITO));
+ return (ERROR_I2C_W | ERROR_PROD_TEST_ITO);
+ }
+
+ logError(0, "%s Looking for ITO Event...\n", tag);
+ res = pollForEvent(eventToSearch, 2, readData, TIMEOUT_ITO_TEST_RESULT);
+ if (res < 0) {
+ logError(1, "%s production_test_ito: ITO Production test failed... ERROR %02X\n", tag, ERROR_PROD_TEST_ITO);
+ return (res | ERROR_PROD_TEST_ITO);
+ }
+
+ if (readData[2] != 0x00 || readData[3] != 0x00) {
+ logError(0, "%s ITO Production testes finished!.................FAILED ERROR %02X\n", tag, (ERROR_TEST_CHECK_FAIL | ERROR_PROD_TEST_ITO));
+ res = (ERROR_TEST_CHECK_FAIL | ERROR_PROD_TEST_ITO);
+ } else {
+ logError(0, "%s ITO Production test finished!.................OK\n", tag);
+ res = OK;
+ }
+
+ res |= fts_system_reset();
+ if (res < 0) {
+ logError(1, "%s production_test_ito: ERROR %02X\n", tag, ERROR_PROD_TEST_ITO);
+ res = (res | ERROR_PROD_TEST_ITO);
+ }
+ return res;
+}
+
+int production_test_initialization(void)
+{
+ int res;
+ u8 cmd;
+ u8 readData[FIFO_EVENT_SIZE];
+ int eventToSearch[2] = {EVENTID_STATUS_UPDATE, EVENT_TYPE_FULL_INITIALIZATION};
+
+ logError(0, "%s INITIALIZATION Production test is starting...\n", tag);
+
+ res = fts_system_reset();
+ if (res < 0) {
+ logError(1, "%s production_test_initialization: ERROR %02X\n", tag, ERROR_PROD_TEST_INITIALIZATION);
+ return (res | ERROR_PROD_TEST_INITIALIZATION);
+ }
+
+ logError(0, "%s INITIALIZATION command sent...\n", tag);
+ cmd = FTS_CMD_FULL_INITIALIZATION;
+ if (fts_writeFwCmd(&cmd, 1) < 0) {
+ logError(1, "%s production_test_initialization: ERROR %02X\n", tag, (ERROR_I2C_W | ERROR_PROD_TEST_INITIALIZATION));
+ return (ERROR_I2C_W | ERROR_PROD_TEST_INITIALIZATION);
+ }
+
+ logError(0, "%s Looking for INITIALIZATION Event...\n", tag);
+ res = pollForEvent(eventToSearch, 2, readData, TIMEOUT_INITIALIZATION_TEST_RESULT);
+ if (res < 0) {
+ logError(1, "%s production_test_initialization: INITIALIZATION Production test failed... ERROR %02X\n", tag, ERROR_PROD_TEST_INITIALIZATION);
+ return (res | ERROR_PROD_TEST_INITIALIZATION);
+ }
+
+ if (readData[2] != 0x00) {
+ logError(0, "%s INITIALIZATION Production testes finished!.................FAILED ERROR %02X\n", tag, (ERROR_TEST_CHECK_FAIL | ERROR_PROD_TEST_INITIALIZATION));
+ res = (ERROR_TEST_CHECK_FAIL | ERROR_PROD_TEST_INITIALIZATION);
+ } else {
+ logError(0, "%s INITIALIZATION Production test.................OK\n", tag);
+ res = OK;
+ }
+
+ logError(0, "%s Refresh Chip Info...\n", tag);
+ res |= readChipInfo(1);
+ /* need to update the chipInfo in order to refresh the tuning_versione */
+
+ if (res < 0) {
+ logError(1, "%s production_test_initialization: read chip info ERROR %02X\n", tag, ERROR_PROD_TEST_INITIALIZATION);
+ res = (res | ERROR_PROD_TEST_INITIALIZATION);
+ }
+
+ return res;
+
+}
+
+int ms_compensation_tuning(void)
+{
+ int res;
+ u8 cmd;
+ u8 readData[FIFO_EVENT_SIZE];
+ int eventToSearch[2] = {EVENTID_STATUS_UPDATE, EVENT_TYPE_MS_TUNING_CMPL};
+
+ logError(0, "%s MS INITIALIZATION command sent...\n", tag);
+ cmd = FTS_CMD_MS_COMP_TUNING;
+ if (fts_writeFwCmd(&cmd, 1) < 0) {
+ logError(1, "%s ms_compensation_tuning 2: ERROR %02X\n", tag, (ERROR_I2C_W | ERROR_MS_TUNING));
+ return (ERROR_I2C_W | ERROR_MS_TUNING);
+ }
+
+ logError(0, "%s Looking for MS INITIALIZATION Event...\n", tag);
+ res = pollForEvent(eventToSearch, 2, readData, TIMEOUT_INITIALIZATION_TEST_RESULT);
+ if (res < 0) {
+ logError(1, "%s ms_compensation_tuning: MS INITIALIZATION Production test failed... ERROR %02X\n", tag, ERROR_MS_TUNING);
+ return (res | ERROR_MS_TUNING);
+ }
+
+ if (readData[2] != 0x00 || readData[3] != 0x00) {
+ logError(0, "%s MS INITIALIZATION Production test finished!.................FAILED ERROR %02X\n", tag, ERROR_MS_TUNING);
+ res = ERROR_MS_TUNING;
+ } else {
+ logError(0, "%s MS INITIALIZATION Production test finished!.................OK\n", tag);
+ res = OK;
+ }
+
+ return res;
+}
+
+int ss_compensation_tuning(void)
+{
+ int res;
+ u8 cmd;
+ u8 readData[FIFO_EVENT_SIZE];
+ int eventToSearch[2] = {EVENTID_STATUS_UPDATE, EVENT_TYPE_SS_TUNING_CMPL};
+
+ logError(0, "%s SS INITIALIZATION command sent...\n", tag);
+ cmd = FTS_CMD_SS_COMP_TUNING;
+ if (fts_writeFwCmd(&cmd, 1) < 0) {
+ logError(1, "%s ss_compensation_tuning 2: ERROR %02X\n", tag, (ERROR_I2C_W | ERROR_SS_TUNING));
+ return (ERROR_I2C_W | ERROR_SS_TUNING);
+ }
+
+ logError(0, "%s Looking for SS INITIALIZATION Event...\n", tag);
+ res = pollForEvent(eventToSearch, 2, readData, TIMEOUT_INITIALIZATION_TEST_RESULT);
+ if (res < 0) {
+ logError(1, "%s ms_compensation_tuning: SS INITIALIZATION Production test failed... ERROR %02X\n", tag, ERROR_SS_TUNING);
+ return (res | ERROR_SS_TUNING);
+ }
+
+ if (readData[2] != 0x00 || readData[3] != 0x00) {
+ logError(0, "%s SS INITIALIZATION Production test finished!.................FAILED ERROR %02X\n", tag, ERROR_SS_TUNING);
+ res = ERROR_SS_TUNING;
+ } else {
+ logError(0, "%s SS INITIALIZATION Production test finished!.................OK\n", tag);
+ res = OK;
+ }
+
+ return res;
+}
+
+int lp_timer_calibration(void)
+{
+ int res;
+ u8 cmd;
+ u8 readData[FIFO_EVENT_SIZE];
+ int eventToSearch[2] = {EVENTID_STATUS_UPDATE, EVENT_TYPE_LPTIMER_TUNING_CMPL};
+
+ logError(0, "%s LP TIMER CALIBRATION command sent...\n", tag);
+ cmd = FTS_CMD_LP_TIMER_CALIB;
+ if (fts_writeFwCmd(&cmd, 1) < 0) {
+ logError(1, "%s lp_timer_calibration 2: ERROR %02X\n", tag, (ERROR_I2C_W | ERROR_LP_TIMER_TUNING));
+ return (ERROR_I2C_W | ERROR_LP_TIMER_TUNING);
+ }
+
+ logError(0, "%s Looking for LP TIMER CALIBRATION Event...\n", tag);
+ res = pollForEvent(eventToSearch, 2, readData, TIMEOUT_INITIALIZATION_TEST_RESULT);
+ if (res < 0) {
+ logError(1, "%s lp_timer_calibration: LP TIMER CALIBRATION Production test failed... ERROR %02X\n", tag, ERROR_LP_TIMER_TUNING);
+ return (res | ERROR_LP_TIMER_TUNING);
+ }
+
+ if (readData[2] != 0x00 || readData[3] != 0x01) {
+ logError(0, "%s LP TIMER CALIBRATION Production test finished!.................FAILED ERROR %02X\n", tag, ERROR_LP_TIMER_TUNING);
+ res = ERROR_LP_TIMER_TUNING;
+ } else {
+ logError(0, "%s LP TIMER CALIBRATION Production test finished!.................OK\n", tag);
+ res = OK;
+ }
+
+ return res;
+}
+
+int save_cx_tuning(void)
+{
+ int res;
+ u8 cmd;
+ u8 readData[FIFO_EVENT_SIZE];
+ int eventToSearch[2] = {EVENTID_STATUS_UPDATE, EVENT_TYPE_COMP_DATA_SAVED};
+
+ logError(0, "%s SAVE CX command sent...\n", tag);
+ cmd = FTS_CMD_SAVE_CX_TUNING;
+ if (fts_writeCmd(&cmd, 1) < 0) {
+ logError(1, "%s save_cx_tuning 2: ERROR %02X\n", tag, (ERROR_I2C_W | ERROR_SAVE_CX_TUNING));
+ return (ERROR_I2C_W | ERROR_SAVE_CX_TUNING);
+ }
+
+ logError(0, "%s Looking for SAVE CX Event...\n", tag);
+ res = pollForEvent(eventToSearch, 2, readData, TIMEOUT_INITIALIZATION_TEST_RESULT);
+ if (res < 0) {
+ logError(1, "%s save_cx_tuning: SAVE CX failed... ERROR %02X\n", tag, ERROR_SAVE_CX_TUNING);
+ return (res | ERROR_SAVE_CX_TUNING);
+ }
+
+ if (readData[2] != 0x00 || readData[3] != 0x00) {
+ logError(0, "%s SAVE CX finished!.................FAILED ERROR %02X\n", tag, ERROR_SAVE_CX_TUNING);
+ res = ERROR_SAVE_CX_TUNING;
+ } else {
+ logError(0, "%s SAVE CX finished!.................OK\n", tag);
+ res = OK;
+ }
+
+ return res;
+}
+
+int production_test_splited_initialization(int saveToFlash)
+{
+ int res;
+
+ logError(0, "%s Splitted Initialization test is starting...\n", tag);
+ res = fts_system_reset();
+ if (res < 0) {
+ logError(1, "%s production_test_initialization: ERROR %02X\n", tag, ERROR_PROD_TEST_INITIALIZATION);
+ logError(0, "%s LP INITIALIZATION TEST:\n", tag);
+ return (res | ERROR_PROD_TEST_INITIALIZATION);
+ }
+
+ logError(0, "%s MS INITIALIZATION TEST:\n", tag);
+ res = ms_compensation_tuning();
+ if (res < 0) {
+ logError(0, "%s production_test_splited_initialization: MS INITIALIZATION TEST FAILED! ERROR %02X\n", tag, ERROR_PROD_TEST_INITIALIZATION);
+ return (res | ERROR_PROD_TEST_INITIALIZATION);
+ }
+ logError(0, "%s MS INITIALIZATION TEST OK!\n", tag);
+
+ logError(0, "%s\n", tag);
+
+ logError(0, "%s SS INITIALIZATION TEST:\n", tag);
+ res = ss_compensation_tuning();
+ if (res < 0) {
+ logError(0, "%s production_test_splited_initialization: SS INITIALIZATION TEST FAILED! ERROR %02X\n", tag, ERROR_PROD_TEST_INITIALIZATION);
+ return (res | ERROR_PROD_TEST_INITIALIZATION);
+ }
+ logError(0, "%s SS INITIALIZATION TEST OK!\n", tag);
+
+ logError(0, "%s\n", tag);
+
+ logError(0, "%s LP INITIALIZATION TEST:\n", tag);
+ res = lp_timer_calibration();
+ if (res < 0) {
+ logError(0, "%s production_test_splited_initialization: LP INITIALIZATION TEST FAILED! ERROR %02X\n", tag, ERROR_PROD_TEST_INITIALIZATION);
+ return (res | ERROR_PROD_TEST_INITIALIZATION);
+ }
+ logError(0, "%s LP INITIALIZATION TEST OK!\n", tag);
+ if (saveToFlash) {
+ logError(0, "%s\n", tag);
+ logError(0, "%s SAVE CX TEST:\n", tag);
+ res = save_cx_tuning();
+ if (res < 0) {
+ logError(0, "%s production_test_splited_initialization: SAVE CX TEST FAILED! ERROR %02X\n", tag, res);
+ return (res | ERROR_PROD_TEST_INITIALIZATION);
+ }
+ logError(0, "%s SAVE CX TEST OK!\n", tag);
+ }
+ logError(0, "%s Refresh Chip Info...\n", tag);
+ res |= readChipInfo(1);
+ if (res < 0) {
+ logError(1, "%s production_test_initialization: read chip info ERROR %02X\n", tag, ERROR_PROD_TEST_INITIALIZATION);
+ res = (res | ERROR_PROD_TEST_INITIALIZATION);
+ } else
+ logError(0, "%s Splited Initialization test finished!.................OK\n", tag);
+ return res;
+}
+
+int production_test_main(char *pathThresholds, int stop_on_fail,
+ int saveInit, TestToDo *todo, u32 signature)
+{
+ int res, ret;
+
+ logError(0, "%s MAIN Production test is starting...\n", tag);
+
+ logError(0, "%s\n", tag);
+
+ logError(0, "%s ITO TEST:\n", tag);
+ res = production_test_ito();
+ if (res < 0) {
+ logError(0, "%s Error during ITO TEST! ERROR %02X\n", tag, (u8) res);
+ goto END; /* in case of ITO TEST failure is no sense keep going */
+ } else {
+ logError(0, "%s ITO TEST OK!\n", tag);
+ }
+
+ logError(0, "%s\n", tag);
+
+ logError(0, "%s INITIALIZATION TEST :\n", tag);
+ if (saveInit == 1) {
+ res = production_test_initialization();
+ if (res < 0) {
+ logError(0, "%s Error during INITIALIZATION TEST! ERROR %02X\n", tag, (u8) res);
+ if (stop_on_fail)
+ goto END;
+ } else {
+ logError(0, "%s INITIALIZATION TEST OK!\n", tag);
+ }
+ } else
+ logError(0, "%s INITIALIZATION TEST :................. SKIPPED\n", tag);
+
+ logError(0, "%s\n", tag);
+
+ if (saveInit == 1) {
+ logError(0, "%s Cleaning up...\n", tag);
+ ret = cleanUp(0);
+ if (ret < 0) {
+ logError(1, "%s production_test_main: clean up ERROR %02X\n", tag, ret);
+ res |= ret;
+ if (stop_on_fail)
+ goto END;
+ }
+ logError(0, "%s\n", tag);
+ }
+
+ logError(0, "%s PRODUCTION DATA TEST:\n", tag);
+ ret = production_test_data(pathThresholds, stop_on_fail, todo);
+ if (ret < 0) {
+ logError(0, "%s Error during PRODUCTION DATA TEST! ERROR %02X\n", tag, ret);
+ } else {
+ logError(0, "%s PRODUCTION DATA TEST OK!\n", tag);
+ }
+
+ res |= ret;
+ /* the OR is important because if the data test is OK but the inizialization test fail,
+ * the main production test result should = FAIL
+ */
+
+ if (ret == OK && saveInit == 1) {
+ logError(0, "%s SAVE FLAG:\n", tag);
+ ret = save_mp_flag(signature);
+ if (ret < OK)
+ logError(0, "%s SAVE FLAG:................. FAIL! ERROR %08X\n", tag, ret);
+ else
+ logError(0, "%s SAVE FLAG:................. OK!\n", tag);
+ res |= ret;
+ }
+
+ logError(0, "%s\n", tag);
+END:
+ if (res < 0) {
+ logError(0, "%s MAIN Production test finished.................FAILED\n", tag);
+ return res;
+ }
+ logError(0, "%s MAIN Production test finished.................OK\n", tag);
+ return OK;
+}
+
+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;
+
+ /*********************** Mutual Sense Test **********************/
+ logError(0, "%s\n", tag);
+ logError(0, "%s MS RAW DATA TEST is starting...\n", tag);
+ if (todo->MutualRaw == 1 || todo->MutualRawGap == 1) {
+
+ ret = getMSFrame2(MS_TOUCH_ACTIVE, &msRawFrame);
+ if (ret < 0) {
+ logError(1, "%s production_test_data: getMSFrame failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+
+ logError(0, "%s MS RAW MIN MAX TEST:\n", tag);
+ if (todo->MutualRaw == 1) {
+ ret = parseProductionTestLimits(path_limits, MS_RAW_MIN_MAX, &thresholds, &trows, &tcolumns);
+ if (ret < 0 || (trows != 1 || tcolumns != 2)) {
+ logError(1, "%s production_test_data: parseProductionTestLimits MS_RAW_MIN_MAX failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+
+ ret = checkLimitsMinMax(msRawFrame.node_data, msRawFrame.header.force_node, msRawFrame.header.sense_node, thresholds[0], thresholds[1]);
+ if (ret != OK) {
+ logError(1, "%s production_test_data: checkLimitsMinMax MS RAW failed... ERROR COUNT = %d\n", tag, ret);
+ logError(0, "%s MS RAW MIN MAX TEST:.................FAIL\n\n", tag);
+ count_fail += 1;
+ if (stop_on_fail == 1)
+ goto ERROR;
+ }
+ kfree(thresholds);
+ logError(0, "%s MS RAW MIN MAX TEST:.................OK\n", tag);
+ } else
+ logError(0, "%s MS RAW MIN MAX TEST:.................SKIPPED\n", tag);
+
+ logError(0, "%s\n", tag);
+ logError(0, "%s MS RAW GAP TEST:\n", tag);
+ if (todo->MutualRawGap == 1) {
+ ret = parseProductionTestLimits(path_limits, MS_RAW_GAP, &thresholds, &trows, &tcolumns);
+ if (ret < 0 || (trows != 1 || tcolumns != 1)) {
+ logError(1, "%s production_test_data: parseProductionTestLimits MS_RAW_GAP failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+
+ ret = checkLimitsGap(msRawFrame.node_data, msRawFrame.header.force_node, msRawFrame.header.sense_node, thresholds[0]);
+ if (ret != OK) {
+ logError(1, "%s production_test_data: checkLimitsGap MS RAW failed... ERROR = %02X\n", tag, ret);
+ count_fail += 1;
+ if (stop_on_fail == 1)
+ goto ERROR;
+
+ } else
+ logError(0, "%s MS RAW GAP TEST:.................OK\n\n", tag);
+ kfree(thresholds);
+ } else
+ logError(0, "%s MS RAW GAP TEST:.................SKIPPED\n", tag);
+
+ kfree(msRawFrame.node_data);
+ } else
+ logError(0, "%s MS RAW FRAME TEST:.................SKIPPED\n", tag);
+
+ logError(0, "%s\n", tag);
+ logError(0, "%s MS KEY RAW TEST:\n", tag);
+ if (todo->MutualKeyRaw == 1) {
+ ret = production_test_ms_key_raw(path_limits);
+ if (ret < 0) {
+ logError(1, "%s production_test_data: production_test_ms_key_raw failed... ERROR = %02X\n", tag, ret);
+ count_fail += 1;
+ }
+ } else
+ logError(0, "%s MS KEY RAW TEST:.................SKIPPED\n", tag);
+
+ERROR:
+ logError(0, "%s\n", tag);
+ if (count_fail == 0) {
+ logError(0, "%s MS RAW DATA TEST finished!.................OK\n", tag);
+ return OK;
+ }
+ 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);
+ logError(0, "%s MS RAW DATA TEST:.................FAIL fails_count = %d\n\n", tag, count_fail);
+ return (ERROR_PROD_TEST_DATA | ERROR_TEST_CHECK_FAIL);
+}
+
+int production_test_ms_key_raw(char *path_limits)
+{
+
+ int ret;
+ MutualSenseFrame msRawFrame;
+
+ int *thresholds = NULL;
+ int trows, tcolumns;
+
+ /******************************* Mutual Sense Test *******************************/
+ logError(0, "%s MS KEY RAW DATA TEST is starting...\n", tag);
+
+ ret = getMSFrame2(MS_KEY, &msRawFrame);
+ if (ret < 0) {
+ logError(1, "%s production_test_data: getMSKeyFrame failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+
+ ret = parseProductionTestLimits(path_limits, MS_KEY_RAW_MIN_MAX, &thresholds, &trows, &tcolumns);
+ if (ret < 0 || (trows != 1 || tcolumns != 2)) {
+ logError(1, "%s production_test_data: parseProductionTestLimits MS_KEY_RAW_MIN_MAX failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+
+ ret = checkLimitsMinMax(msRawFrame.node_data, msRawFrame.header.force_node, msRawFrame.header.sense_node, thresholds[0], thresholds[1]);
+ if (ret != OK) {
+ logError(1, "%s production_test_data: checkLimitsMinMax MS KEY RAW failed... ERROR COUNT = %d\n", tag, ret);
+ goto ERROR;
+ } else
+ logError(0, "%s MS KEY RAW TEST:.................OK\n\n", tag);
+
+ kfree(thresholds);
+
+ kfree(msRawFrame.node_data);
+
+ 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);
+ logError(0, "%s MS KEY RAW TEST:.................FAIL\n\n", tag);
+ return (ERROR_PROD_TEST_DATA | ERROR_TEST_CHECK_FAIL);
+
+}
+
+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;
+
+ u8 *adjhor = NULL;
+
+ u8 *adjvert = NULL;
+
+ u16 container;
+ u16 *total_cx = NULL;
+ u16 *total_adjhor = NULL;
+ u16 *total_adjvert = NULL;
+
+ /* MS CX TEST */
+ logError(0, "%s\n", tag);
+ logError(0, "%s MS CX Testes are starting...\n", tag);
+
+ ret = readMutualSenseCompensationData(MS_TOUCH_ACTIVE, &msCompData); /* read MS compensation data */
+ if (ret < 0) {
+ logError(1, "%s production_test_data: readMutualSenseCompensationData failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+
+ logError(0, "%s MS CX1 TEST:\n", tag);
+ if (todo->MutualCx1 == 1) {
+
+ ret = parseProductionTestLimits(path_limits, MS_CX1_MIN_MAX, &thresholds, &trows, &tcolumns);
+ if (ret < 0 || (trows != 1 || tcolumns != 2)) {
+ logError(1, "%s production_test_data: parseProductionTestLimits MS_CX1_MIN_MAX failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+
+ container = (u16) msCompData.cx1;
+ ret = checkLimitsMinMax(&container, 1, 1, thresholds[0], thresholds[1]); /* check the limits */
+ if (ret != OK) {
+ logError(1, "%s production_test_data: checkLimitsMinMax MS CX1 failed... ERROR COUNT = %d\n", tag, ret);
+ logError(0, "%s MS CX1 TEST:.................FAIL\n\n", tag);
+ count_fail += 1;
+ if (stop_on_fail)
+ goto ERROR;
+ } else
+ logError(0, "%s MS CX1 TEST:.................OK\n\n", tag);
+ } else
+ logError(0, "%s MS CX1 TEST:.................SKIPPED\n\n", tag);
+
+ kfree(thresholds);
+
+ logError(0, "%s MS CX2 MIN MAX TEST:\n", tag);
+ if (todo->MutualCx2 == 1) {
+ ret = parseProductionTestLimits(path_limits, MS_CX2_MAP_MIN, &thresholds_min, &trows, &tcolumns); /* load min thresholds */
+ if (ret < 0 || (trows != msCompData.header.force_node || tcolumns != msCompData.header.sense_node)) {
+ logError(1, "%s production_test_data: parseProductionTestLimits MS_CX2_MAP_MIN failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+
+ ret = parseProductionTestLimits(path_limits, MS_CX2_MAP_MAX, &thresholds_max, &trows, &tcolumns); /* load max thresholds */
+ if (ret < 0 || (trows != msCompData.header.force_node || tcolumns != msCompData.header.sense_node)) {
+ logError(1, "%s production_test_data: parseProductionTestLimits MS_CX2_MAP_MAX failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+
+ ret = checkLimitsMap(msCompData.node_data, msCompData.header.force_node, msCompData.header.sense_node, thresholds_min, thresholds_max); /* check the limits */
+ if (ret != OK) {
+ logError(1, "%s production_test_data: checkLimitsMap MS CX2 MIN MAX failed... ERROR COUNT = %d\n", tag, ret);
+ logError(0, "%s MS CX2 MIN MAX TEST:.................FAIL\n\n", tag);
+ count_fail += 1;
+ if (stop_on_fail)
+ goto ERROR;
+ } else
+ logError(0, "%s MS CX2 MIN MAX TEST:.................OK\n\n", tag);
+
+ kfree(thresholds_min);
+ kfree(thresholds_max);
+ } else
+ logError(0, "%s MS CX2 MIN MAX TEST:.................SKIPPED\n\n", tag);
+
+ logError(0, "%s MS CX2 ADJ TEST:\n", tag);
+ if (todo->MutualCx2Adj == 1) {
+ /* MS CX2 ADJ HORIZ */
+ logError(0, "%s MS CX2 ADJ HORIZ TEST:\n", tag);
+
+ ret = computeAdjHoriz(msCompData.node_data, msCompData.header.force_node, msCompData.header.sense_node, &adjhor);
+ if (ret < 0) {
+ logError(1, "%s production_test_data: computeAdjHoriz failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+ logError(0, "%s MS CX2 ADJ HORIZ computed!\n", tag);
+
+ ret = parseProductionTestLimits(path_limits, MS_CX2_ADJH_MAP_MAX, &thresholds_max, &trows, &tcolumns);
+ if (ret < 0 || (trows != msCompData.header.force_node || tcolumns != msCompData.header.sense_node - 1)) {
+ logError(1, "%s production_test_data: parseProductionTestLimits MS_CX2_ADJH_MAP_MAX failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+
+ ret = checkLimitsMapAdj(adjhor, msCompData.header.force_node, msCompData.header.sense_node - 1, thresholds_max);
+ if (ret != OK) {
+ logError(1, "%s production_test_data: checkLimitsMapAdj CX2 ADJH failed... ERROR COUNT = %d\n", tag, ret);
+ logError(0, "%s MS CX2 ADJ HORIZ TEST:.................FAIL\n\n", tag);
+ count_fail += 1;
+ if (stop_on_fail)
+ goto ERROR;
+ } else
+ logError(0, "%s MS CX2 ADJ HORIZ TEST:.................OK\n\n", tag);
+
+ kfree(thresholds_max);
+ kfree(adjhor);
+
+ /* MS CX2 ADJ VERT */
+ logError(0, "%s MS CX2 ADJ VERT TEST:\n", tag);
+
+ ret = computeAdjVert(msCompData.node_data, msCompData.header.force_node, msCompData.header.sense_node, &adjvert);
+ if (ret < 0) {
+ logError(1, "%s production_test_data: computeAdjVert failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+ logError(0, "%s MS CX2 ADJ VERT computed!\n", tag);
+
+ ret = parseProductionTestLimits(path_limits, MS_CX2_ADJV_MAP_MAX, &thresholds_max, &trows, &tcolumns);
+ if (ret < 0 || (trows != msCompData.header.force_node - 1 || tcolumns != msCompData.header.sense_node)) {
+ logError(1, "%s production_test_data: parseProductionTestLimits MS_CX2_ADJV_MAP_MAX failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+
+ ret = checkLimitsMapAdj(adjvert, msCompData.header.force_node - 1, msCompData.header.sense_node - 1, thresholds_max);
+ if (ret != OK) {
+ logError(1, "%s production_test_data: checkLimitsMapAdj CX2 ADJV failed... ERROR COUNT = %d\n", tag, ret);
+ logError(0, "%s MS CX2 ADJ HORIZ TEST:.................FAIL\n\n", tag);
+ count_fail += 1;
+ if (stop_on_fail)
+ goto ERROR;
+ } else
+ logError(0, "%s MS CX2 ADJ VERT TEST:.................OK\n\n", tag);
+
+ kfree(thresholds_max);
+ kfree(adjvert);
+ } else
+ logError(0, "%s MS CX2 ADJ TEST:.................SKIPPED\n\n", tag);
+
+ /* START OF TOTAL CHECK */
+ logError(0, "%s MS TOTAL CX TEST:\n", tag);
+
+ if (todo->MutualCxTotal == 1 || todo->MutualCxTotalAdj == 1) {
+ ret = computeTotal(msCompData.node_data, msCompData.cx1, msCompData.header.force_node, msCompData.header.sense_node, CX1_WEIGHT, CX2_WEIGHT, &total_cx);
+ if (ret < 0) {
+ logError(1, "%s production_test_data: computeTotalCx failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+ logError(0, "%s MS TOTAL CX MIN MAX TEST:\n", tag);
+ if (todo->MutualCxTotal == 1) {
+ ret = parseProductionTestLimits(path_limits, MS_TOTAL_CX_MAP_MIN, &thresholds_min, &trows, &tcolumns); /* load min thresholds */
+ if (ret < 0 || (trows != msCompData.header.force_node || tcolumns != msCompData.header.sense_node)) {
+ logError(1, "%s production_test_data: parseProductionTestLimits MS_TOTAL_CX_MAP_MIN failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+
+ ret = parseProductionTestLimits(path_limits, MS_TOTAL_CX_MAP_MAX, &thresholds_max, &trows, &tcolumns); /* load max thresholds */
+ if (ret < 0 || (trows != msCompData.header.force_node || tcolumns != msCompData.header.sense_node)) {
+ logError(1, "%s production_test_data: parseProductionTestLimits MS_TOTAL_CX_MAP_MAX failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+
+ ret = checkLimitsMapTotal(total_cx, msCompData.header.force_node, msCompData.header.sense_node, thresholds_min, thresholds_max); /* check the limits */
+ if (ret != OK) {
+ logError(1, "%s production_test_data: checkLimitsMap MS TOTAL CX TEST failed... ERROR COUNT = %d\n", tag, ret);
+ logError(0, "%s MS TOTAL CX MIN MAX TEST:.................FAIL\n\n", tag);
+ count_fail += 1;
+ if (stop_on_fail)
+ goto ERROR;
+ } else
+ logError(0, "%s MS TOTAL CX MIN MAX TEST:.................OK\n\n", tag);
+
+ kfree(thresholds_min);
+ kfree(thresholds_max);
+ } else
+ logError(0, "%s MS TOTAL CX MIN MAX TEST:.................SKIPPED\n\n", tag);
+
+ logError(0, "%s MS TOTAL CX ADJ TEST:\n", tag);
+ if (todo->MutualCxTotalAdj == 1) {
+ /* MS TOTAL CX ADJ HORIZ */
+ logError(0, "%s MS TOTAL CX ADJ HORIZ TEST:\n", tag);
+
+ /* thresholds_max = NULL; */
+ ret = computeAdjHorizTotal(total_cx, msCompData.header.force_node, msCompData.header.sense_node, &total_adjhor);
+ if (ret < 0) {
+ logError(1, "%s production_test_data: computeAdjHoriz failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+ logError(0, "%s MS TOTAL CX ADJ HORIZ computed!\n", tag);
+
+ ret = parseProductionTestLimits(path_limits, MS_TOTAL_CX_ADJH_MAP_MAX, &thresholds_max, &trows, &tcolumns);
+ if (ret < 0 || (trows != msCompData.header.force_node || tcolumns != msCompData.header.sense_node - 1)) {
+ logError(1, "%s production_test_data: parseProductionTestLimits MS_TOTAL_CX_ADJH_MAP_MAX failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+
+ ret = checkLimitsMapAdjTotal(total_adjhor, msCompData.header.force_node, msCompData.header.sense_node - 1, thresholds_max);
+ if (ret != OK) {
+ logError(1, "%s production_test_data: checkLimitsMapAdj MS TOTAL CX ADJH failed... ERROR COUNT = %d\n", tag, ret);
+ logError(0, "%s MS TOTAL CX ADJ HORIZ TEST:.................FAIL\n\n", tag);
+ count_fail += 1;
+ if (stop_on_fail)
+ goto ERROR;
+ } else
+ logError(0, "%s MS TOTAL CX ADJ HORIZ TEST:.................OK\n\n", tag);
+
+ kfree(thresholds_max);
+ kfree(total_adjhor);
+
+ /* MS TOTAL CX ADJ VERT */
+ logError(0, "%s MS TOTAL CX ADJ VERT TEST:\n", tag);
+
+ ret = computeAdjVertTotal(total_cx, msCompData.header.force_node, msCompData.header.sense_node, &total_adjvert);
+ if (ret < 0) {
+ logError(1, "%s production_test_data: computeAdjVert failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+ logError(0, "%s MS TOTAL CX ADJ VERT computed!\n", tag);
+
+ ret = parseProductionTestLimits(path_limits, MS_TOTAL_CX_ADJV_MAP_MAX, &thresholds_max, &trows, &tcolumns);
+ if (ret < 0 || (trows != msCompData.header.force_node - 1 || tcolumns != msCompData.header.sense_node)) {
+ logError(1, "%s production_test_data: parseProductionTestLimits MS_TOTAL_CX_ADJV_MAP_MAX failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+
+ ret = checkLimitsMapAdjTotal(total_adjvert, msCompData.header.force_node - 1, msCompData.header.sense_node - 1, thresholds_max);
+ if (ret != OK) {
+ logError(1, "%s production_test_data: checkLimitsMapAdj MS TOTAL CX ADJV failed... ERROR COUNT = %d\n", tag, ret);
+ logError(0, "%s MS TOTAL CX ADJ HORIZ TEST:.................FAIL\n", tag);
+ count_fail += 1;
+ if (stop_on_fail)
+ goto ERROR;
+ } else
+ logError(0, "%s MS TOTAL CX ADJ VERT TEST:.................OK\n", tag);
+
+ kfree(thresholds_max);
+ kfree(total_adjvert);
+ } else
+ logError(0, "%s MS TOTAL CX ADJ TEST:.................SKIPPED\n", tag);
+
+ kfree(total_cx);
+ } else
+ logError(0, "%s MS TOTAL CX TEST:.................SKIPPED\n", tag);
+
+ kfree(msCompData.node_data);
+
+ 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;
+ logError(1, "%s production_test_data: production_test_ms_key_cx failed... ERROR = %02X\n", tag, ret);
+ logError(0, "%s MS CX testes finished!.................FAILED fails_count = %d\n\n", tag, count_fail);
+ return ret;
+ }
+ } else
+ logError(0, "%s MS KEY CX TEST:.................SKIPPED\n", tag);
+
+ERROR:
+ logError(0, "%s\n", tag);
+ if (count_fail == 0) {
+ logError(0, "%s MS CX testes finished!.................OK\n", tag);
+ return OK;
+ }
+ print_frame_u8("MS Init Data (Cx2) =", array1dTo2d_u8(msCompData.node_data, msCompData.node_data_size, msCompData.header.sense_node), msCompData.header.force_node, msCompData.header.sense_node);
+ logError(0, "%s MS CX testes finished!.................FAILED fails_count = %d\n\n", tag, count_fail);
+ return (ERROR_TEST_CHECK_FAIL | ERROR_PROD_TEST_DATA);
+
+}
+
+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;
+
+ u16 container;
+ u16 *total_cx = NULL;
+
+ /* MS CX TEST */
+ logError(0, "%s MS KEY CX Testes are starting...\n", tag);
+
+ ret = readMutualSenseCompensationData(MS_KEY, &msCompData); /* read MS compensation data */
+ if (ret < 0) {
+ logError(1, "%s production_test_data: readMutualSenseCompensationData failed... ERROR %02X\n", tag, 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;
+
+ logError(0, "%s MS KEY CX1 TEST:\n", tag);
+ if (todo->MutualKeyCx1 == 1) {
+
+ ret = parseProductionTestLimits(path_limits, MS_KEY_CX1_MIN_MAX, &thresholds, &trows, &tcolumns);
+ if (ret < 0 || (trows != 1 || tcolumns != 2)) {
+ logError(1, "%s production_test_data: parseProductionTestLimits MS_KEY_CX1_MIN_MAX failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+
+ container = (u16) msCompData.cx1;
+ ret = checkLimitsMinMax(&container, 1, 1, thresholds[0], thresholds[1]); /* check the limits */
+ if (ret != OK) {
+ logError(1, "%s production_test_data: checkLimitsMinMax MS CX1 failed... ERROR COUNT = %d\n", tag, ret);
+ logError(0, "%s MS KEY CX1 TEST:.................FAIL\n\n", tag);
+ count_fail += 1;
+ if (stop_on_fail)
+ goto ERROR;
+ } else
+ logError(0, "%s MS KEY CX1 TEST:.................OK\n\n", tag);
+ } else
+ logError(0, "%s MS KEY CX1 TEST:.................SKIPPED\n\n", tag);
+
+ kfree(thresholds);
+
+ logError(0, "%s MS KEY CX2 TEST:\n", tag);
+ if (todo->MutualKeyCx2 == 1) {
+ ret = parseProductionTestLimits(path_limits, MS_KEY_CX2_MAP_MIN, &thresholds_min, &trows, &tcolumns); /* load min thresholds */
+ if (ret < 0 || (trows != 1 || tcolumns != num_keys)) {
+ logError(1, "%s production_test_data: parseProductionTestLimits MS_KEY_CX2_MAP_MIN failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+
+ ret = parseProductionTestLimits(path_limits, MS_KEY_CX2_MAP_MAX, &thresholds_max, &trows, &tcolumns); /* load max thresholds */
+ if (ret < 0 || (trows != 1 || tcolumns != num_keys)) {
+ logError(1, "%s production_test_data: parseProductionTestLimits MS_KEY_CX2_MAP_MAX failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+
+ ret = checkLimitsMap(msCompData.node_data, 1, num_keys, thresholds_min, thresholds_max); /* check the limits */
+ if (ret != OK) {
+ logError(1, "%s production_test_data: checkLimitsMap MS KEY CX2 failed... ERROR COUNT = %d\n", tag, ret);
+ logError(0, "%s MS KEY CX2 TEST:.................FAIL\n\n", tag);
+ count_fail += 1;
+ if (stop_on_fail)
+ goto ERROR;
+ } else
+ logError(0, "%s MS KEY CX2 TEST:.................OK\n\n", tag);
+
+ kfree(thresholds_min);
+ kfree(thresholds_max);
+ } else
+ logError(0, "%s MS CX2 TEST:.................SKIPPED\n\n", tag);
+
+ /* START OF TOTAL CHECK */
+ logError(0, "%s MS KEY TOTAL CX TEST:\n", tag);
+
+ if (todo->MutualKeyCxTotal == 1) {
+ ret = computeTotal(msCompData.node_data, msCompData.cx1, 1, num_keys, CX1_WEIGHT, CX2_WEIGHT, &total_cx);
+ if (ret < 0) {
+ logError(1, "%s production_test_data: computeTotalCx failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+
+ ret = parseProductionTestLimits(path_limits, MS_KEY_TOTAL_CX_MAP_MIN, &thresholds_min, &trows, &tcolumns); /* load min thresholds */
+ if (ret < 0 || (trows != 1 || tcolumns != num_keys)) {
+ logError(1, "%s production_test_data: parseProductionTestLimits MS_KEY_TOTAL_CX_MAP_MIN failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+
+ ret = parseProductionTestLimits(path_limits, MS_KEY_TOTAL_CX_MAP_MAX, &thresholds_max, &trows, &tcolumns); /* load max thresholds */
+ if (ret < 0 || (trows != 1 || tcolumns != num_keys)) {
+ logError(1, "%s production_test_data: parseProductionTestLimits MS_KEY_TOTAL_CX_MAP_MAX failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+
+ ret = checkLimitsMapTotal(total_cx, 1, num_keys, thresholds_min, thresholds_max); /* check the limits */
+ if (ret != OK) {
+ logError(1, "%s production_test_data: checkLimitsMap MS TOTAL KEY CX TEST failed... ERROR COUNT = %d\n", tag, ret);
+ logError(0, "%s MS KEY TOTAL CX TEST:.................FAIL\n\n", tag);
+ count_fail += 1;
+ if (stop_on_fail)
+ goto ERROR;
+ } else
+ logError(0, "%s MS KEY TOTAL CX TEST:.................OK\n\n", tag);
+
+ kfree(thresholds_min);
+ kfree(thresholds_max);
+
+ kfree(total_cx);
+ } else
+ logError(0, "%s MS KEY TOTAL CX TEST:.................SKIPPED\n", tag);
+
+ kfree(msCompData.node_data);
+ERROR:
+ logError(0, "%s\n", tag);
+ if (count_fail == 0) {
+ logError(0, "%s MS KEY CX testes finished!.................OK\n", tag);
+ return OK;
+ }
+ print_frame_u8("MS Key Init Data (Cx2) =", array1dTo2d_u8(msCompData.node_data, msCompData.node_data_size, msCompData.header.sense_node), 1, msCompData.header.sense_node);
+ logError(0, "%s MS Key CX testes finished!.................FAILED fails_count = %d\n\n", tag, count_fail);
+ return (ERROR_TEST_CHECK_FAIL | ERROR_PROD_TEST_DATA);
+}
+
+int production_test_ss_raw(char *path_limits, int stop_on_fail, TestToDo *todo)
+{
+ int ret;
+ int count_fail = 0;
+ int rows, columns;
+
+ /* short *ssRawFrame = NULL; */
+ SelfSenseFrame ssRawFrame;
+
+ int *thresholds = NULL;
+ int trows, tcolumns;
+
+ /* MS SS TEST */
+ logError(0, "%s\n", tag);
+ logError(0, "%s SS RAW Testes are starting...\n", tag);
+
+ /******************************* Self Sense Test *******************************/
+
+ logError(0, "%s Getting SS Frame...\n", tag);
+ ret = getSSFrame2(SS_TOUCH, &ssRawFrame);
+ if (ret < 0) {
+ logError(1, "%s production_test_data: getSSFrame failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+
+ /* SS RAW (PROXIMITY) FORCE TEST */
+ logError(0, "%s SS RAW (PROXIMITY) FORCE TEST:\n", tag);
+
+ if (todo->SelfForceRaw == 1 || todo->SelfForceRawGap == 1) {
+
+ columns = 1;
+ /* there are no data for the sense channels due to the fact that the force frame is analized */
+ rows = ssRawFrame.header.force_node;
+
+ logError(0, "%s SS RAW (PROXIMITY) FORCE MIN MAX TEST:\n", tag);
+ if (todo->SelfForceRaw == 1) {
+
+ ret = parseProductionTestLimits(path_limits, SS_RAW_FORCE_MIN_MAX, &thresholds, &trows, &tcolumns);
+ if (ret < 0 || (trows != 1 || tcolumns != 2)) {
+ logError(1, "%s production_test_data: parseProductionTestLimits SS_RAW_FORCE_MIN_MAX failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+
+ ret = checkLimitsMinMax(ssRawFrame.force_data, rows, columns, thresholds[0], thresholds[1]);
+ if (ret != OK) {
+ logError(1, "%s production_test_data: checkLimitsMinMax SS RAW (PROXIMITY) FORCE failed... ERROR COUNT = %d\n", tag, ret);
+ logError(0, "%s SS RAW (PROXIMITY) FORCE MIN MAX TEST:.................FAIL\n\n", tag);
+ count_fail += 1;
+ print_frame_short("SS Raw force frame =", array1dTo2d_short(ssRawFrame.force_data, rows*columns, columns), rows, columns);
+ if (stop_on_fail)
+ return (ERROR_PROD_TEST_DATA | ERROR_TEST_CHECK_FAIL);
+ } else
+ logError(0, "%s SS RAW (PROXIMITY) FORCE MIN MAX TEST:.................OK\n\n", tag);
+
+ kfree(thresholds);
+ } else
+ logError(0, "%s SS RAW (PROXIMITY) FORCE MIN MAX TEST:.................SKIPPED\n\n", tag);
+
+ logError(0, "%s\n", tag);
+ logError(0, "%s SS RAW (PROXIMITY) FORCE GAP TEST:\n", tag);
+ if (todo->SelfForceRawGap == 1) {
+
+ ret = parseProductionTestLimits(path_limits, SS_RAW_FORCE_GAP, &thresholds, &trows, &tcolumns);
+ if (ret < 0 || (trows != 1 || tcolumns != 1)) {
+ logError(1, "%s production_test_data: parseProductionTestLimits SS_RAW_FORCE_GAP failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+
+ ret = checkLimitsGap(ssRawFrame.force_data, rows, columns, thresholds[0]);
+ if (ret != OK) {
+ logError(1, "%s production_test_data: checkLimitsGap SS RAW (PROXIMITY) FORCE GAP failed... ERROR = %02X\n", tag, ret);
+ logError(0, "%s SS RAW (PROXIMITY) FORCE GAP TEST:.................FAIL\n\n", tag);
+ count_fail += 1;
+ print_frame_short("SS Raw force frame =", array1dTo2d_short(ssRawFrame.force_data, rows*columns, columns), rows, columns);
+ if (stop_on_fail)
+ return (ERROR_PROD_TEST_DATA | ERROR_TEST_CHECK_FAIL);
+ } else
+ logError(0, "%s SS RAW (PROXIMITY) FORCE GAP TEST:.................OK\n\n", tag);
+
+ kfree(thresholds);
+ } else
+ logError(0, "%s SS RAW (PROXIMITY) FORCE GAP TEST:.................SKIPPED\n\n", tag);
+
+ kfree(ssRawFrame.force_data);
+ } else
+ logError(0, "%s SS RAW (PROXIMITY) FORCE TEST:.................SKIPPED\n\n", tag);
+
+ logError(0, "%s\n", tag);
+ /* SS RAW (PROXIMITY) SENSE TEST */
+ logError(0, "%s SS RAW (PROXIMITY) SENSE TEST:\n", tag);
+
+ if (todo->SelfSenseRaw == 1 || todo->SelfSenseRawGap == 1) {
+ columns = ssRawFrame.header.sense_node;
+ rows = 1; /* there are no data for the force channels due to the fact that the sense frame is analized */
+
+ logError(0, "%s SS RAW (PROXIMITY) SENSE MIN MAX TEST:\n", tag);
+ if (todo->SelfSenseRaw == 1) {
+ ret = parseProductionTestLimits(path_limits, SS_RAW_SENSE_MIN_MAX, &thresholds, &trows, &tcolumns);
+ if (ret < 0 || (trows != 1 || tcolumns != 2)) {
+ logError(1, "%s production_test_data: parseProductionTestLimits SS_RAW_SENSE_MIN_MAX failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+
+ ret = checkLimitsMinMax(ssRawFrame.sense_data, rows, columns, thresholds[0], thresholds[1]);
+ if (ret != OK) {
+ logError(1, "%s production_test_data: checkLimitsMinMax SS RAW (PROXIMITY) SENSE failed... ERROR COUNT = %d\n", tag, ret);
+ logError(0, "%s SS RAW (PROXIMITY) SENSE MIN MAX TEST:.................FAIL\n", tag);
+ count_fail += 1;
+ print_frame_short("SS Raw sense frame =", array1dTo2d_short(ssRawFrame.sense_data, rows*columns, columns), rows, columns);
+ if (stop_on_fail)
+ return (ERROR_PROD_TEST_DATA | ERROR_TEST_CHECK_FAIL);
+ } else
+ logError(0, "%s SS RAW (PROXIMITY) SENSE MIN MAX TEST:.................OK\n", tag);
+
+ kfree(thresholds);
+ } else
+ logError(0, "%s SS RAW (PROXIMITY) SENSE MIN MAX TEST:.................SKIPPED\n", tag);
+
+ logError(0, "%s\n", tag);
+ logError(0, "%s SS RAW (PROXIMITY) SENSE GAP TEST:\n", tag);
+ if (todo->SelfSenseRawGap == 1) {
+ ret = parseProductionTestLimits(path_limits, SS_RAW_SENSE_GAP, &thresholds, &trows, &tcolumns);
+ if (ret < 0 || (trows != 1 || tcolumns != 1)) {
+ logError(1, "%s production_test_data: parseProductionTestLimits SS_RAW_SENSE_GAP failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+
+ ret = checkLimitsGap(ssRawFrame.sense_data, rows, columns, thresholds[0]);
+ if (ret != OK) {
+ logError(1, "%s production_test_data: checkLimitsGap SS RAW (PROXIMITY) SENSE GAP failed... ERROR = %02X\n", tag, ret);
+ logError(0, "%s SS RAW (PROXIMITY) SENSE GAP TEST:.................FAIL\n", tag);
+ count_fail += 1;
+ print_frame_short("SS Raw sense frame =", array1dTo2d_short(ssRawFrame.sense_data, rows*columns, columns), rows, columns);
+ if (stop_on_fail)
+ return (ERROR_PROD_TEST_DATA | ERROR_TEST_CHECK_FAIL);
+ } else
+ logError(0, "%s SS RAW (PROXIMITY) SENSE GAP TEST:.................OK\n", tag);
+
+ kfree(thresholds);
+ } else
+ logError(0, "%s SS RAW (PROXIMITY) SENSE GAP TEST:.................SKIPPED\n", tag);
+
+ kfree(ssRawFrame.sense_data);
+ }
+
+ logError(0, "%s\n", tag);
+ if (count_fail == 0) {
+ logError(0, "%s SS RAW testes finished!.................OK\n\n", tag);
+ return OK;
+ }
+ logError(0, "%s SS RAW testes finished!.................FAILED fails_count = %d\n\n", tag, count_fail);
+ return (ERROR_TEST_CHECK_FAIL | ERROR_PROD_TEST_DATA);
+}
+
+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;
+
+ u8 *adjhor = NULL;
+ u8 *adjvert = NULL;
+
+ u16 container;
+ int *ix1_w, *ix2_w;
+ u16 *total_ix = NULL;
+ u16 *total_cx = NULL;
+
+ u16 *total_adjhor = NULL;
+ u16 *total_adjvert = NULL;
+
+ logError(0, "%s\n", tag);
+ logError(0, "%s SS IX CX testes are starting...\n", tag);
+ ret = readSelfSenseCompensationData(SS_TOUCH, &ssCompData); /* read the SS compensation data */
+ if (ret < 0) {
+ logError(1, "%s production_test_data: readSelfSenseCompensationData failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+
+ /*************************** SS FORCE IX *************************************/
+ /* SS IX1 FORCE TEST */
+ logError(0, "%s SS IX1 FORCE TEST:\n", tag);
+ if (todo->SelfForceIx1 == 1) {
+
+ ret = parseProductionTestLimits(path_limits, SS_IX1_FORCE_MIN_MAX, &thresholds, &trows, &tcolumns);
+ if (ret < 0 || (trows != 1 || tcolumns != 2)) {
+ logError(1, "%s production_test_data: parseProductionTestLimits SS_IX1_FORCE_MIN_MAX failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+ container = (u16) ssCompData.f_ix1;
+ ret = checkLimitsMinMax(&container, 1, 1, thresholds[0], thresholds[1]); /* check the limits */
+ if (ret != OK) {
+ logError(1, "%s production_test_data: checkLimitsMinMax SS IX1 FORCE TEST failed... ERROR COUNT = %d\n", tag, ret);
+ count_fail += 1;
+ if (stop_on_fail)
+ goto ERROR;
+ } else
+ logError(0, "%s SS IX1 FORCE TEST:.................OK\n\n", tag);
+ } else
+ logError(0, "%s SS IX1 FORCE TEST:.................SKIPPED\n\n", tag);
+
+ kfree(thresholds);
+ /* SS IX2 FORCE TEST */
+ logError(0, "%s SS IX2 FORCE MIN MAX TEST:\n", tag);
+ if (todo->SelfForceIx2 == 1) {
+ ret = parseProductionTestLimits(path_limits, SS_IX2_FORCE_MAP_MIN, &thresholds_min, &trows, &tcolumns); /* load the min thresholds */
+ if (ret < 0 || (trows != ssCompData.header.force_node || tcolumns != 1)) {
+ logError(1, "%s production_test_data: parseProductionTestLimits SS_IX2_FORCE_MAP_MIN failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+
+ ret = parseProductionTestLimits(path_limits, SS_IX2_FORCE_MAP_MAX, &thresholds_max, &trows, &tcolumns); /* load the max thresholds */
+ if (ret < 0 || (trows != ssCompData.header.force_node || tcolumns != 1)) {
+ logError(1, "%s production_test_data: parseProductionTestLimits SS_IX2_FORCE_MAP_MAX failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+
+ ret = checkLimitsMap(ssCompData.ix2_fm, ssCompData.header.force_node, 1, thresholds_min, thresholds_max); /* check the values with thresholds */
+ if (ret != OK) {
+ logError(1, "%s production_test_data: checkLimitsMap SS IX2 FORCE failed... ERROR COUNT = %d\n", tag, ret);
+ logError(0, "%s SS IX2 FORCE MIN MAX TEST:.................FAIL\n\n", tag);
+ count_fail += 1;
+ if (stop_on_fail)
+ goto ERROR;
+ } else
+ logError(0, "%s SS IX2 FORCE MIN MAX TEST:.................OK\n\n", tag);
+
+ kfree(thresholds_min);
+ kfree(thresholds_max);
+ } else
+ logError(0, "%s SS IX2 FORCE MIN MAX TEST:.................SKIPPED\n\n", tag);
+
+ logError(0, "%s SS IX2 FORCE ADJ TEST:\n", tag);
+ if (todo->SelfForceIx2Adj == 1) {
+ /* SS IX2 FORCE ADJV TEST */
+ logError(0, "%s SS IX2 FORCE ADJVERT TEST:\n", tag);
+ ret = computeAdjVert(ssCompData.ix2_fm, ssCompData.header.force_node, 1, &adjvert);
+ if (ret < 0) {
+ logError(1, "%s production_test_data: computeAdjVert SS IX2 FORCE ADJV failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+ logError(0, "%s SS IX2 FORCE ADJV computed!\n", tag);
+
+ ret = parseProductionTestLimits(path_limits, 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)) {
+ logError(1, "%s production_test_data: parseProductionTestLimits SS_IX2_FORCE_ADJV_MAP_MAX failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+
+ ret = checkLimitsMapAdj(adjvert, ssCompData.header.force_node - 1, 1, thresholds_max);
+ /* check the values with thresholds */
+ if (ret != OK) {
+ logError(1, "%s production_test_data: checkLimitsMap SS IX2 FORCE failed... ERROR COUNT = %d\n", tag, ret);
+ logError(0, "%s SS IX2 FORCE ADJV TEST:.................FAIL\n\n", tag);
+ count_fail += 1;
+ if (stop_on_fail)
+ goto ERROR;
+ } else
+ logError(0, "%s SS IX2 FORCE ADJV TEST:.................OK\n\n", tag);
+
+ kfree(thresholds_max);
+ kfree(adjvert);
+
+ } else
+ logError(0, "%s SS IX2 FORCE ADJ TEST:.................SKIPPED\n\n", tag);
+
+ /* SS TOTAL FORCE IX */
+ logError(0, "%s SS TOTAL IX FORCE TEST:\n", tag);
+ if (todo->SelfForceIxTotal == 1 || todo->SelfForceIxTotalAdj == 1) {
+ logError(0, "%s Reading TOTAL IX FORCE Weights...\n", tag);
+ ret = parseProductionTestLimits(path_limits, SS_IX1_FORCE_W, &ix1_w, &trows, &tcolumns); /* load the IX1 weight */
+ if (ret < 0 || (trows != 1 || tcolumns != 1)) {
+ logError(1, "%s production_test_data: parseProductionTestLimits SS_IX1_FORCE_W failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+
+ ret = parseProductionTestLimits(path_limits, SS_IX2_FORCE_W, &ix2_w, &trows, &tcolumns); /* load the IX2 weight */
+ if (ret < 0 || (trows != 1 || tcolumns != 1)) {
+ logError(1, "%s production_test_data: parseProductionTestLimits SS_IX1_FORCE_W failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+
+ logError(0, "%s Weights: IX1_W = %d IX2_W = %d\n", tag, *ix1_w, *ix2_w);
+
+ ret = computeTotal(ssCompData.ix2_fm, ssCompData.f_ix1, ssCompData.header.force_node, 1, *ix1_w, *ix2_w, &total_ix);
+ if (ret < 0) {
+ logError(1, "%s production_test_data: computeTotal Ix Force failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+
+ logError(0, "%s SS TOTAL IX FORCE MIN MAX TEST:\n", tag);
+ if (todo->SelfForceIxTotal == 1) {
+ ret = parseProductionTestLimits(path_limits, SS_TOTAL_IX_FORCE_MAP_MIN, &thresholds_min, &trows, &tcolumns); /* load the min thresholds */
+ if (ret < 0 || (trows != ssCompData.header.force_node || tcolumns != 1)) {
+ logError(1, "%s production_test_data: parseProductionTestLimits SS_TOTAL_IX_FORCE_MAP_MIN failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+
+ ret = parseProductionTestLimits(path_limits, SS_TOTAL_IX_FORCE_MAP_MAX, &thresholds_max, &trows, &tcolumns); /* load the max thresholds */
+ if (ret < 0 || (trows != ssCompData.header.force_node || tcolumns != 1)) {
+ logError(1, "%s production_test_data: parseProductionTestLimits SS_TOTAL_IX_FORCE_MAP_MAX failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+
+ ret = checkLimitsMapTotal(total_ix, ssCompData.header.force_node, 1, thresholds_min, thresholds_max); /* check the values with thresholds */
+ if (ret != OK) {
+ logError(1, "%s production_test_data: checkLimitsMap SS TOTAL IX FORCE failed... ERROR COUNT = %d\n", tag, ret);
+ logError(0, "%s SS TOTAL IX FORCE MIN MAX TEST:.................FAIL\n\n", tag);
+ count_fail += 1;
+ if (stop_on_fail)
+ goto ERROR;
+ } else
+ logError(0, "%s SS TOTAL IX FORCE MIN MAX TEST:.................OK\n\n", tag);
+
+ kfree(thresholds_min);
+ kfree(thresholds_max);
+ } else
+ logError(0, "%s SS TOTAL IX FORCE MIN MAX TEST:.................SKIPPED\n", tag);
+
+ logError(0, "%s SS TOTAL IX FORCE ADJ TEST:\n", tag);
+ if (todo->SelfForceIxTotalAdj == 1) {
+ /* SS TOTAL IX FORCE ADJV TEST */
+ logError(0, "%s SS TOTAL IX FORCE ADJVERT TEST:\n", tag);
+ ret = computeAdjVertTotal(total_ix, ssCompData.header.force_node, 1, &total_adjvert);
+ if (ret < 0) {
+ logError(1, "%s production_test_data: computeAdjVert SS TOTAL IX FORCE ADJV failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+ logError(0, "%s SS TOTAL IX FORCE ADJV computed!\n", tag);
+
+ ret = parseProductionTestLimits(path_limits, SS_TOTAL_IX_FORCE_ADJV_MAP_MAX, &thresholds_max, &trows, &tcolumns); /* load the max thresholds */
+ if (ret < 0 || (trows != ssCompData.header.force_node - 1 || tcolumns != 1)) {
+ logError(1, "%s production_test_data: parseProductionTestLimits SS_TOTAL_IX_FORCE_ADJV_MAP_MAX... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+
+ ret = checkLimitsMapAdjTotal(total_adjvert, ssCompData.header.force_node - 1, 1, thresholds_max); /* check the values with thresholds */
+ if (ret != OK) {
+ logError(1, "%s production_test_data: checkLimitsMap SS TOTAL IX FORCE failed... ERROR COUNT = %d\n", tag, ret);
+ logError(0, "%s SS TOTAL IX FORCE ADJV TEST:.................FAIL\n\n", tag);
+ count_fail += 1;
+ if (stop_on_fail)
+ goto ERROR;
+ } else
+ logError(0, "%s SS TOTAL IX FORCE ADJV TEST:.................OK\n\n", tag);
+
+ kfree(thresholds_max);
+ kfree(total_adjvert);
+ } else
+ logError(0, "%s SS TOTAL IX FORCE ADJ TEST:.................SKIPPED\n", tag);
+
+ kfree(total_ix);
+ } else
+ logError(0, "%s SS TOTAL IX FORCE TEST:.................SKIPPED\n\n", tag);
+
+ /******************* SS SENSE IX **************************/
+ /* SS IX1 SENSE TEST */
+ logError(0, "%s SS IX1 SENSE TEST:\n", tag);
+ if (todo->SelfSenseIx1 == 1) {
+
+ ret = parseProductionTestLimits(path_limits, SS_IX1_SENSE_MIN_MAX, &thresholds, &trows, &tcolumns);
+ if (ret < 0 || (trows != 1 || tcolumns != 2)) {
+ logError(1, "%s production_test_data: parseProductionTestLimits SS_IX1_SENSE_MIN_MAX failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+
+ container = (u16) ssCompData.s_ix1;
+ ret = checkLimitsMinMax(&container, 1, 1, thresholds[0], thresholds[1]); /* check the limits */
+ if (ret != OK) {
+ logError(1, "%s production_test_data: checkLimitsMinMax SS IX1 SENSE TEST failed... ERROR COUNT = %d\n", tag, ret);
+ count_fail += 1;
+ if (stop_on_fail)
+ goto ERROR;
+ } else
+ logError(0, "%s SS IX1 SENSE TEST:.................OK\n\n", tag);
+ } else
+ logError(0, "%s SS IX1 SENSE TEST:.................SKIPPED\n\n", tag);
+
+ kfree(thresholds);
+ /* SS IX2 SENSE TEST */
+ logError(0, "%s SS IX2 SENSE MIN MAX TEST:\n", tag);
+ if (todo->SelfSenseIx2 == 1) {
+ ret = parseProductionTestLimits(path_limits, SS_IX2_SENSE_MAP_MIN, &thresholds_min, &trows, &tcolumns); /* load the min thresholds */
+ if (ret < 0 || (trows != 1 || tcolumns != ssCompData.header.sense_node)) {
+ logError(1, "%s production_test_data: parseProductionTestLimits SS_IX2_SENSE_MAP_MIN failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+
+ ret = parseProductionTestLimits(path_limits, SS_IX2_SENSE_MAP_MAX, &thresholds_max, &trows, &tcolumns); /* load the max thresholds */
+ if (ret < 0 || (trows != 1 || tcolumns != ssCompData.header.sense_node)) {
+ logError(1, "%s production_test_data: parseProductionTestLimits SS_IX2_SENSE_MAP_MAX failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+
+ ret = checkLimitsMap(ssCompData.ix2_sn, 1, ssCompData.header.sense_node, thresholds_min, thresholds_max); /* check the values with thresholds */
+ if (ret != OK) {
+ logError(1, "%s production_test_data: checkLimitsMap SS IX2 SENSE failed... ERROR COUNT = %d\n", tag, ret);
+ logError(0, "%s SS IX2 SENSE MIN MAX TEST:.................FAIL\n\n", tag);
+ count_fail += 1;
+ if (stop_on_fail)
+ goto ERROR;
+ } else
+ logError(0, "%s SS IX2 SENSE MIN MAX TEST:.................OK\n\n", tag);
+
+ kfree(thresholds_min);
+ kfree(thresholds_max);
+ } else
+ logError(0, "%s SS IX2 SENSE MIN MAX TEST:.................SKIPPED\n\n", tag);
+
+ logError(0, "%s SS IX2 SENSE ADJ TEST:\n", tag);
+ if (todo->SelfSenseIx2Adj == 1) {
+ /* SS IX2 SENSE ADJH TEST */
+ logError(0, "%s SS IX2 SENSE ADJHORIZ TEST:\n", tag);
+ ret = computeAdjHoriz(ssCompData.ix2_sn, 1, ssCompData.header.sense_node, &adjhor);
+ if (ret < 0) {
+ logError(1, "%s production_test_data: computeAdjHoriz SS IX2 SENSE ADJH failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+ logError(0, "%s SS IX2 SENSE ADJ HORIZ computed!\n", tag);
+
+ ret = parseProductionTestLimits(path_limits, 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)) {
+ logError(1, "%s production_test_data: parseProductionTestLimits SS_IX2_SENSE_ADJH_MAP_MAX failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+
+ ret = checkLimitsMapAdj(adjhor, 1, ssCompData.header.sense_node - 1, thresholds_max); /* check the values with thresholds */
+ if (ret != OK) {
+ logError(1, "%s production_test_data: checkLimitsMapAdj SS IX2 SENSE ADJH failed... ERROR COUNT = %d\n", tag, ret);
+ logError(0, "%s SS IX2 SENSE ADJH TEST:.................FAIL\n\n", tag);
+ count_fail += 1;
+ if (stop_on_fail)
+ goto ERROR;
+ } else
+ logError(0, "%s SS IX2 SENSE ADJH TEST:.................OK\n\n", tag);
+
+ kfree(thresholds_max);
+ kfree(adjhor);
+ } else
+ logError(0, "%s SS IX2 SENSE ADJ TEST:.................SKIPPED\n", tag);
+
+ /* SS TOTAL IX SENSE */
+ logError(0, "%s SS TOTAL IX SENSE TEST:\n", tag);
+ if (todo->SelfSenseIxTotal == 1 || todo->SelfSenseIxTotalAdj == 1) {
+ logError(0, "%s Reading TOTAL IX SENSE Weights...\n", tag);
+ ret = parseProductionTestLimits(path_limits, SS_IX1_SENSE_W, &ix1_w, &trows, &tcolumns); /* load the IX1 weight */
+ if (ret < 0 || (trows != 1 || tcolumns != 1)) {
+ logError(1, "%s production_test_data: parseProductionTestLimits SS_IX1_SENSE_W failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+
+ ret = parseProductionTestLimits(path_limits, SS_IX2_SENSE_W, &ix2_w, &trows, &tcolumns); /* load the IX2 weight */
+ if (ret < 0 || (trows != 1 || tcolumns != 1)) {
+ logError(1, "%s production_test_data: parseProductionTestLimits SS_IX1_SENSE_W failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+
+ logError(0, "%s Weights: IX1_W = %d IX2_W = %d\n", tag, *ix1_w, *ix2_w);
+
+ ret = computeTotal(ssCompData.ix2_sn, ssCompData.s_ix1, 1, ssCompData.header.sense_node, *ix1_w, *ix2_w, &total_ix);
+ if (ret < 0) {
+ logError(1, "%s production_test_data: computeTotal Ix Sense failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+
+ logError(0, "%s SS TOTAL IX SENSE MIN MAX TEST:\n", tag);
+ if (todo->SelfSenseIxTotal == 1) {
+ ret = parseProductionTestLimits(path_limits, SS_TOTAL_IX_SENSE_MAP_MIN, &thresholds_min, &trows, &tcolumns); /* load the min thresholds */
+ if (ret < 0 || (trows != 1 || tcolumns != ssCompData.header.sense_node)) {
+ logError(1, "%s production_test_data: parseProductionTestLimits SS_TOTAL_IX_SENSE_MAP_MIN failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+
+ ret = parseProductionTestLimits(path_limits, SS_TOTAL_IX_SENSE_MAP_MAX, &thresholds_max, &trows, &tcolumns); /* load the max thresholds */
+ if (ret < 0 || (trows != 1 || tcolumns != ssCompData.header.sense_node)) {
+ logError(1, "%s production_test_data: parseProductionTestLimits SS_TOTAL_IX_SENSE_MAP_MAX failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+
+ ret = checkLimitsMapTotal(total_ix, 1, ssCompData.header.sense_node, thresholds_min, thresholds_max); /* check the values with thresholds */
+ if (ret != OK) {
+ logError(1, "%s production_test_data: checkLimitsMap SS TOTAL IX SENSE failed... ERROR COUNT = %d\n", tag, ret);
+ logError(0, "%s SS TOTAL IX SENSE MIN MAX TEST:.................FAIL\n\n", tag);
+ count_fail += 1;
+ if (stop_on_fail)
+ goto ERROR;
+ } else
+ logError(0, "%s SS TOTAL IX SENSE MIN MAX TEST:.................OK\n\n", tag);
+
+ kfree(thresholds_min);
+ kfree(thresholds_max);
+ } else
+ logError(0, "%s SS TOTAL IX SENSE MIN MAX TEST:.................SKIPPED\n", tag);
+
+ logError(0, "%s SS TOTAL IX SENSE ADJ TEST:\n", tag);
+ if (todo->SelfSenseIxTotalAdj == 1) {
+ /* SS TOTAL IX SENSE ADJH TEST */
+ logError(0, "%s SS TOTAL IX SENSE ADJHORIZ TEST:\n", tag);
+ ret = computeAdjHorizTotal(total_ix, 1, ssCompData.header.sense_node, &total_adjhor);
+ if (ret < 0) {
+ logError(1, "%s production_test_data: computeAdjHoriz SS TOTAL IX SENSE ADJH failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+ logError(0, "%s SS TOTAL IX SENSE ADJ HORIZ computed!\n", tag);
+
+ ret = parseProductionTestLimits(path_limits, SS_TOTAL_IX_SENSE_ADJH_MAP_MAX, &thresholds_max, &trows, &tcolumns); /* load the max thresholds */
+ if (ret < 0 || (trows != 1 || tcolumns != ssCompData.header.sense_node - 1)) {
+ logError(1, "%s production_test_data: parseProductionTestLimits SS_TOTAL_IX_SENSE_ADJH_MAP_MAX failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+
+ ret = checkLimitsMapAdjTotal(total_adjhor, 1, ssCompData.header.sense_node - 1, thresholds_max); /* check the values with thresholds */
+ if (ret != OK) {
+ logError(1, "%s production_test_data: checkLimitsMapAdj SS TOTAL IX SENSE ADJH failed... ERROR COUNT = %d\n", tag, ret);
+ logError(0, "%s SS TOTAL IX SENSE ADJH TEST:.................FAIL\n\n", tag);
+ count_fail += 1;
+ if (stop_on_fail)
+ goto ERROR;
+ } else
+ logError(0, "%s SS TOTAL IX SENSE ADJH TEST:.................OK\n\n", tag);
+
+ kfree(thresholds_max);
+ kfree(total_adjhor);
+ } else
+ logError(0, "%s SS TOTAL IX SENSE ADJ TEST:.................SKIPPED\n", tag);
+ kfree(total_ix);
+ } else
+ logError(0, "%s SS TOTAL IX SENSE TEST:.................SKIPPED\n", tag);
+
+ /*********************** SS SENSE CX ******************************/
+ /* SS CX1 FORCE TEST */
+ logError(0, "%s SS CX1 FORCE TEST:\n", tag);
+ if (todo->SelfForceCx1 == 1) {
+
+ ret = parseProductionTestLimits(path_limits, SS_CX1_FORCE_MIN_MAX, &thresholds, &trows, &tcolumns);
+ if (ret < 0 || (trows != 1 || tcolumns != 2)) {
+ logError(1, "%s production_test_data: parseProductionTestLimits SS_CX1_FORCE_MIN_MAX failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+
+ container = (u16) ssCompData.f_cx1;
+ ret = checkLimitsMinMax(&container, 1, 1, thresholds[0], thresholds[1]); /* check the limits */
+ if (ret != OK) {
+ logError(1, "%s production_test_data: checkLimitsMinMax SS CX1 FORCE TEST failed... ERROR COUNT = %d\n", tag, ret);
+ count_fail += 1;
+ /* if (stop_on_fail) return (ERROR_PROD_TEST_DATA | ERROR_TEST_CHECK_FAIL); */
+ if (stop_on_fail)
+ goto ERROR;
+ } else
+ logError(0, "%s SS CX1 FORCE TEST:.................OK\n\n", tag);
+ kfree(thresholds);
+ } else
+ logError(0, "%s SS CX1 FORCE TEST:.................SKIPPED\n\n", tag);
+
+ /* SS CX2 FORCE TEST */
+ logError(0, "%s SS CX2 FORCE MIN MAX TEST:\n", tag);
+ if (todo->SelfForceCx2 == 1) {
+ ret = parseProductionTestLimits(path_limits, SS_CX2_FORCE_MAP_MIN, &thresholds_min, &trows, &tcolumns); /* load the min thresholds */
+ if (ret < 0 || (trows != ssCompData.header.force_node || tcolumns != 1)) {
+ logError(1, "%s production_test_data: parseProductionTestLimits SS_CX2_FORCE_MAP_MIN failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+
+ ret = parseProductionTestLimits(path_limits, SS_CX2_FORCE_MAP_MAX, &thresholds_max, &trows, &tcolumns); /* load the max thresholds */
+ if (ret < 0 || (trows != ssCompData.header.force_node || tcolumns != 1)) {
+ logError(1, "%s production_test_data: parseProductionTestLimits SS_CX2_FORCE_MAP_MAX failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+
+ ret = checkLimitsMap(ssCompData.cx2_fm, ssCompData.header.force_node, 1, thresholds_min, thresholds_max); /* check the values with thresholds */
+ if (ret != OK) {
+ logError(1, "%s production_test_data: checkLimitsMap SS CX2 FORCE failed... ERROR COUNT = %d\n", tag, ret);
+ logError(0, "%s SS CX2 FORCE MIN MAX TEST:.................FAIL\n\n", tag);
+ count_fail += 1;
+ if (stop_on_fail)
+ goto ERROR;
+ } else
+ logError(0, "%s SS CX2 FORCE MIN MAX TEST:.................OK\n\n", tag);
+
+ kfree(thresholds_min);
+ kfree(thresholds_max);
+ } else
+ logError(0, "%s SS CX2 FORCE MIN MAX TEST:.................SKIPPED\n", tag);
+
+ logError(0, "%s SS CX2 FORCE ADJ TEST:\n", tag);
+ if (todo->SelfForceCx2Adj == 1) {
+ /* SS CX2 FORCE ADJV TEST */
+ logError(0, "%s SS CX2 FORCE ADJVERT TEST:\n", tag);
+ ret = computeAdjVert(ssCompData.cx2_fm, ssCompData.header.force_node,
+ 1, &adjvert); /* comepute the ADJV for CX2 FORCE */
+ if (ret < 0) {
+ logError(1, "%s production_test_data: computeAdjVert SS CX2 FORCE ADJV failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+ logError(0, "%s SS CX2 FORCE ADJV computed!\n", tag);
+
+ ret = parseProductionTestLimits(path_limits, 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)) {
+ logError(1, "%s production_test_data: parseProductionTestLimits SS_CX2_FORCE_ADJV_MAP_MAX failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+
+ ret = checkLimitsMapAdj(adjvert, ssCompData.header.force_node - 1, 1, thresholds_max); /* check the values with thresholds */
+ if (ret != OK) {
+ logError(1, "%s production_test_data: checkLimitsMap SS IX2 FORCE failed... ERROR COUNT = %d\n", tag, ret);
+ logError(0, "%s SS CX2 FORCE ADJV TEST:.................FAIL\n\n", tag);
+ count_fail += 1;
+ if (stop_on_fail)
+ goto ERROR;
+ } else
+ logError(0, "%s SS CX2 FORCE ADJV TEST:.................OK\n\n", tag);
+
+ kfree(thresholds_max);
+ kfree(adjvert);
+ } else
+ logError(0, "%s SS CX2 FORCE ADJ TEST:.................SKIPPED\n\n", tag);
+
+ /* SS TOTAL CX FORCE */
+ logError(0, "%s SS TOTAL CX FORCE TEST:\n", tag);
+ if (todo->SelfForceCxTotal == 1 || todo->SelfForceCxTotalAdj == 1) {
+ ret = computeTotal(ssCompData.cx2_fm, ssCompData.f_cx1, ssCompData.header.force_node, 1, CX1_WEIGHT, CX2_WEIGHT, &total_cx);
+ if (ret < 0) {
+ logError(1, "%s production_test_data: computeTotal Cx Force failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+
+ logError(0, "%s SS TOTAL CX FORCE MIN MAX TEST:\n", tag);
+ if (todo->SelfForceCxTotal == 1) {
+ ret = parseProductionTestLimits(path_limits, SS_TOTAL_CX_FORCE_MAP_MIN, &thresholds_min, &trows, &tcolumns); /* load the min thresholds */
+ if (ret < 0 || (trows != ssCompData.header.force_node || tcolumns != 1)) {
+ logError(1, "%s production_test_data: parseProductionTestLimits SS_TOTAL_CX_FORCE_MAP_MIN failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+
+ ret = parseProductionTestLimits(path_limits, SS_TOTAL_CX_FORCE_MAP_MAX, &thresholds_max, &trows, &tcolumns); /* load the max thresholds */
+ if (ret < 0 || (trows != ssCompData.header.force_node || tcolumns != 1)) {
+ logError(1, "%s production_test_data: parseProductionTestLimits SS_TOTAL_CX_FORCE_MAP_MAX failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+
+ ret = checkLimitsMapTotal(total_cx, ssCompData.header.force_node, 1, thresholds_min, thresholds_max); /* check the values with thresholds */
+ if (ret != OK) {
+ logError(1, "%s production_test_data: checkLimitsMap SS TOTAL FORCE failed... ERROR COUNT = %d\n", tag, ret);
+ logError(0, "%s SS TOTAL FORCE MIN MAX TEST:.................FAIL\n\n", tag);
+ count_fail += 1;
+ if (stop_on_fail)
+ goto ERROR;
+ } else
+ logError(0, "%s SS TOTAL FORCE MIN MAX TEST:.................OK\n\n", tag);
+
+ kfree(thresholds_min);
+ kfree(thresholds_max);
+ } else
+ logError(0, "%s SS TOTAL CX FORCE MIN MAX TEST:.................SKIPPED\n", tag);
+
+ /* SS TOTAL CX FORCE ADJV TEST */
+ logError(0, "%s SS TOTAL CX FORCE ADJ TEST:\n", tag);
+ if (todo->SelfForceCxTotalAdj == 1) {
+ logError(0, "%s SS TOTAL CX FORCE ADJVERT TEST:\n", tag);
+ ret = computeAdjVertTotal(total_cx, ssCompData.header.force_node, 1, &total_adjvert); /* comepute the ADJV for CX2 FORCE */
+ if (ret < 0) {
+ logError(1, "%s production_test_data: computeAdjVert SS TOTAL CX FORCE ADJV failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+ logError(0, "%s SS TOTAL CX FORCE ADJV computed!\n", tag);
+
+ ret = parseProductionTestLimits(path_limits, SS_TOTAL_CX_FORCE_ADJV_MAP_MAX, &thresholds_max, &trows, &tcolumns); /* load the max thresholds */
+ if (ret < 0 || (trows != ssCompData.header.force_node - 1 || tcolumns != 1)) {
+ logError(1, "%s production_test_data: parseProductionTestLimits SS_TOTAL_CX_FORCE_ADJV_MAP_MAX failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+
+ ret = checkLimitsMapAdjTotal(total_adjvert, ssCompData.header.force_node - 1, 1, thresholds_max); /* check the values with thresholds */
+ if (ret != OK) {
+ logError(1, "%s production_test_data: checkLimitsMap SS TOTAL CX FORCE failed... ERROR COUNT = %d\n", tag, ret);
+ logError(0, "%s SS TOTAL CX FORCE ADJV TEST:.................FAIL\n\n", tag);
+ count_fail += 1;
+ if (stop_on_fail)
+ goto ERROR;
+ } else
+ logError(0, "%s SS TOTAL CX FORCE ADJV TEST:.................OK\n\n", tag);
+
+ kfree(thresholds_max);
+ kfree(total_adjvert);
+
+ } else
+ logError(0, "%s SS TOTAL CX FORCE ADJ TEST:.................SKIPPED\n", tag);
+ kfree(total_cx);
+ } else
+ logError(0, "%s SS TOTAL CX FORCE TEST:.................SKIPPED\n\n", tag);
+
+ /* ********************** SS SENSE CX ************************************/
+ /* SS CX1 SENSE TEST */
+ logError(0, "%s SS CX1 SENSE TEST:\n", tag);
+ if (todo->SelfSenseCx1 == 1) {
+
+ ret = parseProductionTestLimits(path_limits, SS_CX1_SENSE_MIN_MAX, &thresholds, &trows, &tcolumns);
+ if (ret < 0 || (trows != 1 || tcolumns != 2)) {
+ logError(1, "%s production_test_data: parseProductionTestLimits SS_CX1_SENSE_MIN_MAX failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+
+ container = (u16) ssCompData.s_cx1;
+ ret = checkLimitsMinMax(&container, 1, 1, thresholds[0], thresholds[1]); /* check the limits */
+ if (ret != OK) {
+ logError(1, "%s production_test_data: checkLimitsMinMax SS CX1 SENSE TEST failed... ERROR COUNT = %d\n", tag, ret);
+ count_fail += 1;
+ if (stop_on_fail)
+ goto ERROR;
+ } else
+ logError(0, "%s SS CX1 SENSE TEST:.................OK\n\n", tag);
+ kfree(thresholds);
+ } else
+ logError(0, "%s SS CX1 SENSE TEST:.................SKIPPED\n\n", tag);
+
+ /* SS CX2 SENSE TEST */
+ logError(0, "%s SS CX2 SENSE MIN MAX TEST:\n", tag);
+ if (todo->SelfSenseCx2 == 1) {
+ ret = parseProductionTestLimits(path_limits, SS_CX2_SENSE_MAP_MIN, &thresholds_min, &trows, &tcolumns); /* load the min thresholds */
+ if (ret < 0 || (trows != 1 || tcolumns != ssCompData.header.sense_node)) {
+ logError(1, "%s production_test_data: parseProductionTestLimits SS_CX2_SENSE_MAP_MIN failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+
+ ret = parseProductionTestLimits(path_limits, SS_CX2_SENSE_MAP_MAX, &thresholds_max, &trows, &tcolumns); /* load the max thresholds */
+ if (ret < 0 || (trows != 1 || tcolumns != ssCompData.header.sense_node)) {
+ logError(1, "%s production_test_data: parseProductionTestLimits SS_CX2_SENSE_MAP_MAX failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+
+ ret = checkLimitsMap(ssCompData.cx2_sn, 1, ssCompData.header.sense_node, thresholds_min, thresholds_max); /* check the values with thresholds */
+ if (ret != OK) {
+ logError(1, "%s production_test_data: checkLimitsMap SS CX2 SENSE failed... ERROR COUNT = %d\n", tag, ret);
+ logError(0, "%s SS CX2 SENSE MIN MAX TEST:.................FAIL\n\n", tag);
+ count_fail += 1;
+ if (stop_on_fail)
+ goto ERROR;
+ } else
+ logError(0, "%s SS CX2 SENSE MIN MAX TEST:.................OK\n\n", tag);
+
+ kfree(thresholds_min);
+ kfree(thresholds_max);
+ } else
+ logError(0, "%s SS CX2 SENSE MIN MAX TEST:.................SKIPPED\n", tag);
+
+ logError(0, "%s SS CX2 SENSE ADJ TEST:\n", tag);
+ if (todo->SelfSenseCx2Adj == 1) {
+ /* SS CX2 SENSE ADJH TEST */
+ logError(0, "%s SS CX2 SENSE ADJHORIZ TEST:\n", tag);
+ ret = computeAdjHoriz(ssCompData.ix2_sn, 1, ssCompData.header.sense_node, &adjhor);
+ if (ret < 0) {
+ logError(1, "%s production_test_data: computeAdjHoriz SS CX2 SENSE ADJH failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+ logError(0, "%s SS CX2 SENSE ADJH computed!\n", tag);
+
+ ret = parseProductionTestLimits(path_limits, 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)) {
+ logError(1, "%s production_test_data: parseProductionTestLimits SS_IX2_SENSE_MAP_MAX failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+
+ ret = checkLimitsMapAdj(adjhor, 1, ssCompData.header.sense_node - 1, thresholds_max); /* check the values with thresholds */
+ if (ret != OK) {
+ logError(1, "%s production_test_data: checkLimitsMapAdj SS CX2 SENSE ADJH failed... ERROR COUNT = %d\n", tag, ret);
+ logError(0, "%s SS CX2 SENSE ADJH TEST:.................FAIL\n\n", tag);
+ count_fail += 1;
+ if (stop_on_fail)
+ goto ERROR;
+ } else
+ logError(0, "%s SS CX2 SENSE ADJH TEST:.................OK\n", tag);
+
+ kfree(thresholds_max);
+ kfree(adjhor);
+ } else
+ logError(0, "%s SS CX2 SENSE ADJ TEST:.................SKIPPED\n\n", tag);
+
+ /* SS TOTAL CX SENSE */
+ logError(0, "%s SS TOTAL CX SENSE TEST:\n", tag);
+ if (todo->SelfSenseCxTotal == 1 || todo->SelfSenseCxTotalAdj == 1) {
+ ret = computeTotal(ssCompData.cx2_sn, ssCompData.s_cx1, 1, ssCompData.header.sense_node, CX1_WEIGHT, CX2_WEIGHT, &total_cx);
+ if (ret < 0) {
+ logError(1, "%s production_test_data: computeTotal Cx Sense failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+
+ logError(0, "%s SS TOTAL CX SENSE MIN MAX TEST:\n", tag);
+ if (todo->SelfSenseCxTotal == 1) {
+ ret = parseProductionTestLimits(path_limits, SS_TOTAL_CX_SENSE_MAP_MIN, &thresholds_min, &trows, &tcolumns); /* load the min thresholds */
+ if (ret < 0 || (trows != 1 || tcolumns != ssCompData.header.sense_node)) {
+ logError(1, "%s production_test_data: parseProductionTestLimits SS_TOTAL_CX_SENSE_MAP_MIN failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+
+ ret = parseProductionTestLimits(path_limits, SS_TOTAL_CX_SENSE_MAP_MAX, &thresholds_max, &trows, &tcolumns); /* load the max thresholds */
+ if (ret < 0 || (trows != 1 || tcolumns != ssCompData.header.sense_node)) {
+ logError(1, "%s production_test_data: parseProductionTestLimits SS_TOTAL_CX_SENSE_MAP_MAX failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+
+ ret = checkLimitsMapTotal(total_cx, 1, ssCompData.header.sense_node, thresholds_min, thresholds_max); /* check the values with thresholds */
+ if (ret != OK) {
+ logError(1, "%s production_test_data: checkLimitsMap SS TOTAL CX SENSE failed... ERROR COUNT = %d\n", tag, ret);
+ logError(0, "%s SS TOTAL CX SENSE MIN MAX TEST:.................FAIL\n\n", tag);
+ count_fail += 1;
+ if (stop_on_fail)
+ goto ERROR;
+ } else
+ logError(0, "%s SS TOTAL CX SENSE MIN MAX TEST:.................OK\n\n", tag);
+
+ kfree(thresholds_min);
+ kfree(thresholds_max);
+ } else
+ logError(0, "%s SS TOTAL CX SENSE MIN MAX TEST:.................SKIPPED\n", tag);
+
+ /* SS TOTAL IX SENSE ADJH TEST */
+ logError(0, "%s SS TOTAL CX SENSE ADJ TEST:\n", tag);
+ if (todo->SelfSenseCxTotalAdj == 1) {
+ logError(0, "%s SS TOTAL CX SENSE ADJHORIZ TEST:\n", tag);
+ ret = computeAdjHorizTotal(total_cx, 1, ssCompData.header.sense_node, &total_adjhor);
+ if (ret < 0) {
+ logError(1, "%s production_test_data: computeAdjHoriz SS TOTAL CX SENSE ADJH failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+ logError(0, "%s SS TOTAL CX SENSE ADJ HORIZ computed!\n", tag);
+
+ ret = parseProductionTestLimits(path_limits, SS_TOTAL_CX_SENSE_ADJH_MAP_MAX, &thresholds_max, &trows, &tcolumns); /* load the max thresholds */
+ if (ret < 0 || (trows != 1 || tcolumns != ssCompData.header.sense_node - 1)) {
+ logError(1, "%s production_test_data: parseProductionTestLimits SS_TOTAL_CX_SENSE_ADJH_MAP_MAX failed... ERROR %02X\n", tag, ERROR_PROD_TEST_DATA);
+ return (ret | ERROR_PROD_TEST_DATA);
+ }
+
+ ret = checkLimitsMapAdjTotal(total_adjhor, 1, ssCompData.header.sense_node - 1, thresholds_max); /* check the values with thresholds */
+ if (ret != OK) {
+ logError(1, "%s production_test_data: checkLimitsMapAdj SS TOTAL CX SENSE ADJH failed... ERROR COUNT = %d\n", tag, ret);
+ logError(0, "%s SS TOTAL CX SENSE ADJH TEST:.................FAIL\n\n", tag);
+ count_fail += 1;
+ if (stop_on_fail)
+ goto ERROR;
+ } else
+ logError(0, "%s SS TOTAL CX SENSE ADJH TEST:.................OK\n\n", tag);
+
+ kfree(thresholds_max);
+ kfree(total_adjhor);
+ } else
+ logError(0, "%s SS TOTAL CX SENSE ADJ TEST:.................SKIPPED\n", tag);
+ kfree(total_cx);
+ } else
+ logError(0, "%s SS TOTAL CX SENSE TEST:.................SKIPPED\n", tag);
+
+ /* SS compensation data are no usefull anymore */
+
+ kfree(ssCompData.ix2_fm);
+ kfree(ssCompData.ix2_sn);
+ kfree(ssCompData.cx2_fm);
+ kfree(ssCompData.cx2_sn);
+
+ERROR:
+ logError(0, "%s\n", tag);
+ if (count_fail == 0) {
+ logError(0, "%s SS IX CX testes finished!.................OK\n\n", tag);
+ return OK;
+ }
+ /* 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, ssCompData.header.force_node), 1, ssCompData.header.force_node);
+ print_frame_u8("SS Init Data Cx2_fm = ", array1dTo2d_u8(ssCompData.cx2_fm, ssCompData.header.force_node, ssCompData.header.force_node), 1, ssCompData.header.force_node);
+ 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_u8("SS Init Data Cx2_sn = ", array1dTo2d_u8(ssCompData.cx2_sn, ssCompData.header.sense_node, ssCompData.header.sense_node), 1, ssCompData.header.sense_node);
+ logError(0, "%s SS IX CX testes finished!.................FAILED fails_count = %d\n\n", tag, count_fail);
+ return (ERROR_TEST_CHECK_FAIL | ERROR_PROD_TEST_DATA);
+}
+
+int production_test_data(char *path_limits, int stop_on_fail, TestToDo *todo)
+{
+ int res = OK, ret;
+
+ if (todo == NULL) {
+ logError(1, "%s production_test_data: No TestToDo specified!! ERROR = %02X\n", tag, (ERROR_OP_NOT_ALLOW | ERROR_PROD_TEST_DATA));
+ return (ERROR_OP_NOT_ALLOW | ERROR_PROD_TEST_DATA);
+ }
+
+ logError(0, "%s DATA Production test is starting...\n", tag);
+
+ ret = production_test_ms_raw(path_limits, stop_on_fail, todo);
+ res |= ret;
+ if (ret < 0) {
+ logError(1, "%s production_test_data: production_test_ms_raw failed... ERROR = %02X\n", tag, ret);
+ if (stop_on_fail == 1)
+ goto END;
+ }
+
+ ret = production_test_ms_cx(path_limits, stop_on_fail, todo);
+ res |= ret;
+ if (res < 0) {
+ logError(1, "%s production_test_data: production_test_ms_cx failed... ERROR = %02X\n", tag, ret);
+ if (stop_on_fail == 1)
+ goto END;
+ }
+
+ ret = production_test_ss_raw(path_limits, stop_on_fail, todo);
+ res |= ret;
+ if (ret < 0) {
+ logError(1, "%s production_test_data: production_test_ss_raw failed... ERROR = %02X\n", tag, 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) {
+ logError(1, "%s production_test_data: production_test_ss_ix_cx failed... ERROR = %02X\n", tag, ret);
+ if (stop_on_fail == 1)
+ goto END;
+ }
+
+END:
+ if (res < OK)
+ logError(0, "%s DATA Production test failed!\n", tag);
+ else
+ logError(0, "%s DATA Production test finished!\n", tag);
+ return res;
+}
+
+int save_mp_flag(u32 signature)
+{
+ int res = -1, ret;
+ int i;
+ u8 cmd[6] = {FTS_CMD_WRITE_MP_FLAG, 0x00, 0x00, 0x00, 0x00, 0x00};
+
+ u32ToU8(signature, &cmd[2]);
+
+ logError(0, "%s Starting Saving Flag with signature = %08X ...\n", tag, signature);
+
+ for (i = 0; i < SAVE_FLAG_RETRY && res < OK; i++) {
+ logError(0, "%s Attempt number %d to save mp flag !\n", tag, i+1);
+ logError(0, "%s Command write flag sent...\n", tag);
+ res = fts_writeFwCmd(cmd, 6);
+ if (res >= OK)
+ res = save_cx_tuning();
+
+ }
+
+ ret = readChipInfo(1); /* need to update the MP Flag */
+ if (ret < OK) {
+ logError(1, "%s save_mp_flag: read chip info ERROR %08X\n", tag, ret);
+ }
+
+ res |= ret;
+ if (res < OK) {
+ logError(1, "%s save_mp_flag: ERROR %08X ...\n", tag, res);
+ return res;
+ }
+ logError(1, "%s Saving Flag DONE!\n", tag);
+ return OK;
+}
+
+int parseProductionTestLimits(char *path, char *label, int **data, int *row, int *column)
+{
+
+ int find = 0;
+ char *token = NULL;
+ int i = 0;
+ int j = 0;
+ int z = 0;
+
+ char *line = NULL;
+ int fd = -1;
+ char *buf = NULL;
+ int n, size, pointer = 0, ret;
+ char *data_file = NULL;
+#ifndef LIMITS_H_FILE
+ const struct firmware *fw = NULL;
+ struct device *dev = NULL;
+
+ dev = getDev();
+ if (dev != NULL)
+ fd = request_firmware(&fw, path, dev);
+#else
+ fd = 0;
+#endif
+
+ line = (char *)kmalloc(1800*sizeof(char), GFP_KERNEL);
+ buf = line;
+
+ if (fd == 0) {
+#ifndef LIMITS_H_FILE
+ size = fw->size;
+ data_file = (char *)fw->data;
+ logError(0, "%s Start to reading %s...\n", tag, path);
+#else
+ size = LIMITS_SIZE_NAME;
+ data_file = (char *)(LIMITS_ARRAY_NAME);
+#endif
+
+ logError(0, "%s The size of the limits file is %d bytes...\n", tag, 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 */
+ buf = line;
+ line += 1;
+ token = strsep(&line, ",");
+ if (strcmp(token, label) == 0) {
+ /* if the row is the wanted one i retrieve rows and columns info */
+ find = 1;
+ token = strsep(&line, ",");
+ if (token != NULL) {
+ sscanf(token, "%d", row);
+ logError(0, "%s Row = %d\n", tag, *row);
+ } else {
+ logError(1, "%s parseProductionTestLimits 1: ERROR %02X\n", tag, ERROR_FILE_PARSE);
+ /* release_firmware(fw); */
+ /* return ERROR_FILE_PARSE; */
+ ret = ERROR_FILE_PARSE;
+ goto END;
+ }
+ token = strsep(&line, ",");
+ if (token != NULL) {
+ sscanf(token, "%d", column);
+ logError(0, "%s Column = %d\n", tag, *column);
+ } else {
+ logError(1, "%s parseProductionTestLimits 2: ERROR %02X\n", tag, ERROR_FILE_PARSE);
+ /* release_firmware(fw); */
+ /* return ERROR_FILE_PARSE; */
+ ret = ERROR_FILE_PARSE;
+ goto END;
+ }
+
+ *data = (int *)kmalloc(((*row)*(*column))*sizeof(int), GFP_KERNEL);
+ /* allocate the memory for containing the data */
+ j = 0;
+ if (*data == NULL) {
+ logError(1, "%s parseProductionTestLimits: ERROR %02X\n", tag, ERROR_ALLOC);
+ /* release_firmware(fw); */
+ /* return ERROR_ALLOC; */
+ ret = ERROR_ALLOC;
+ goto END;
+ }
+
+ /* start to read the data */
+ for (i = 0; i < *row; i++) {
+ line = buf;
+ if (readLine(&data_file[pointer], &line, size-pointer, &n) < 0) {
+ logError(1, "%s parseProductionTestLimits : ERROR %02X\n", tag, ERROR_FILE_READ);
+ /* release_firmware(fw); */
+ /* return ERROR_FILE_READ; */
+ ret = ERROR_FILE_READ;
+ goto END;
+ }
+ pointer += n;
+ token = strsep(&line, ",");
+ for (z = 0; (z < *column) && (token != NULL); z++) {
+ sscanf(token, "%d", ((*data) + j));
+ j++;
+ token = strsep(&line, ",");
+ }
+ }
+ if (j == ((*row)*(*column))) { /* check that all the data are read */
+ logError(0, "%s READ DONE!\n", tag);
+ /* release_firmware(fw); */
+ /* return OK; */
+ ret = OK;
+ goto END;
+ }
+ logError(1, "%s parseProductionTestLimits 3: ERROR %02X\n", tag, ERROR_FILE_PARSE);
+ /* release_firmware(fw); */
+ /* return ERROR_FILE_PARSE; */
+ ret = ERROR_FILE_PARSE;
+ goto END;
+ }
+ }
+
+ }
+ logError(1, "%s parseProductionTestLimits: ERROR %02X\n", tag, ERROR_LABEL_NOT_FOUND);
+ ret = ERROR_LABEL_NOT_FOUND;
+END:
+#ifndef LIMITS_H_FILE
+ release_firmware(fw);
+#endif
+ return ret;
+
+ } else {
+ logError(1, "%s parseProductionTestLimits: ERROR %02X\n", tag, ERROR_FILE_NOT_FOUND);
+ return ERROR_FILE_NOT_FOUND;
+ }
+
+}
+
+int readLine(char *data, char **line, int size, int *n)
+{
+ int i = 0;
+ if (size < 1)
+ return 1;
+
+ while (data[i] != '\n' && i < size) {
+ *(*line + i) = data[i];
+ i++;
+ }
+ *n = i+1;
+ *(*line + i) = '\0';
+
+ return OK;
+
+}
diff --git a/drivers/input/touchscreen/st/fts_lib/ftsTest.h b/drivers/input/touchscreen/st/fts_lib/ftsTest.h
new file mode 100644
index 000000000000..93da901c9f42
--- /dev/null
+++ b/drivers/input/touchscreen/st/fts_lib/ftsTest.h
@@ -0,0 +1,158 @@
+/*
+
+**************************************************************************
+** STMicroelectronics **
+**************************************************************************
+** marco.cali@st.com **
+**************************************************************************
+* *
+* FTS API for MP test *
+* *
+**************************************************************************
+**************************************************************************
+
+*/
+
+#include "ftsSoftware.h"
+
+#define LIMITS_FILE "stm_fts_production_limits.csv"
+
+#define WAIT_FOR_FRESH_FRAMES 100 /* ms */
+#define WAIT_AFTER_SENSEOFF 50 /* ms */
+#define TIMEOUT_ITO_TEST_RESULT 200 /* ms */
+#define TIMEOUT_INITIALIZATION_TEST_RESULT 5000 /* ms */
+
+/* LABELS PRODUCTION TEST LIMITS FILE */
+#define MS_RAW_MIN_MAX "MS_RAW_DATA_MIN_MAX"
+#define MS_RAW_GAP "MS_RAW_DATA_GAP"
+#define MS_CX1_MIN_MAX "MS_TOUCH_ACTIVE_CX1_MIN_MAX"
+#define MS_CX2_MAP_MIN "MS_TOUCH_ACTIVE_CX2_MIN"
+#define MS_CX2_MAP_MAX "MS_TOUCH_ACTIVE_CX2_MAX"
+#define MS_CX2_ADJH_MAP_MAX "MS_TOUCH_ACTIVE_CX2_ADJ_HORIZONTAL"
+#define MS_CX2_ADJV_MAP_MAX "MS_TOUCH_ACTIVE_CX2_ADJ_VERTICAL"
+#define MS_TOTAL_CX_MAP_MIN "MS_TOUCH_ACTIVE_TOTAL_CX_MIN"
+#define MS_TOTAL_CX_MAP_MAX "MS_TOUCH_ACTIVE_TOTAL_CX_MAX"
+#define MS_TOTAL_CX_ADJH_MAP_MAX "MS_TOUCH_ACTIVE_TOTAL_CX_ADJ_HORIZONTAL"
+#define MS_TOTAL_CX_ADJV_MAP_MAX "MS_TOUCH_ACTIVE_TOTAL_CX_ADJ_VERTICAL"
+#define SS_RAW_FORCE_MIN_MAX "SS_RAW_DATA_FORCE_MIN_MAX"
+#define SS_RAW_SENSE_MIN_MAX "SS_RAW_DATA_SENSE_MIN_MAX"
+#define SS_RAW_FORCE_GAP "SS_RAW_DATA_FORCE_GAP"
+#define SS_RAW_SENSE_GAP "SS_RAW_DATA_SENSE_GAP"
+#define SS_IX1_FORCE_MIN_MAX "SS_TOUCH_ACTIVE_IX1_FORCE_MIN_MAX"
+#define SS_IX1_SENSE_MIN_MAX "SS_TOUCH_ACTIVE_IX1_SENSE_MIN_MAX"
+#define SS_CX1_FORCE_MIN_MAX "SS_TOUCH_ACTIVE_CX1_FORCE_MIN_MAX"
+#define SS_CX1_SENSE_MIN_MAX "SS_TOUCH_ACTIVE_CX1_SENSE_MIN_MAX"
+#define SS_IX2_FORCE_MAP_MIN "SS_TOUCH_ACTIVE_IX2_FORCE_MIN"
+#define SS_IX2_FORCE_MAP_MAX "SS_TOUCH_ACTIVE_IX2_FORCE_MAX"
+#define SS_IX2_SENSE_MAP_MIN "SS_TOUCH_ACTIVE_IX2_SENSE_MIN"
+#define SS_IX2_SENSE_MAP_MAX "SS_TOUCH_ACTIVE_IX2_SENSE_MAX"
+#define SS_IX2_FORCE_ADJV_MAP_MAX "SS_TOUCH_ACTIVE_IX2_ADJ_VERTICAL"
+#define SS_IX2_SENSE_ADJH_MAP_MAX "SS_TOUCH_ACTIVE_IX2_ADJ_HORIZONTAL"
+#define SS_CX2_FORCE_MAP_MIN "SS_TOUCH_ACTIVE_CX2_FORCE_MIN"
+#define SS_CX2_FORCE_MAP_MAX "SS_TOUCH_ACTIVE_CX2_FORCE_MAX"
+#define SS_CX2_SENSE_MAP_MIN "SS_TOUCH_ACTIVE_CX2_SENSE_MIN"
+#define SS_CX2_SENSE_MAP_MAX "SS_TOUCH_ACTIVE_CX2_SENSE_MAX"
+#define SS_CX2_FORCE_ADJV_MAP_MAX "SS_TOUCH_ACTIVE_CX2_ADJ_VERTICAL"
+#define SS_CX2_SENSE_ADJH_MAP_MAX "SS_TOUCH_ACTIVE_CX2_ADJ_HORIZONTAL"
+
+/* TOTAL SS */
+#define SS_TOTAL_IX_FORCE_MAP_MIN "SS_TOUCH_ACTIVE_TOTAL_IX_FORCE_MIN"
+#define SS_TOTAL_IX_FORCE_MAP_MAX "SS_TOUCH_ACTIVE_TOTAL_IX_FORCE_MAX"
+#define SS_TOTAL_IX_SENSE_MAP_MIN "SS_TOUCH_ACTIVE_TOTAL_IX_SENSE_MIN"
+#define SS_TOTAL_IX_SENSE_MAP_MAX "SS_TOUCH_ACTIVE_TOTAL_IX_SENSE_MAX"
+#define SS_TOTAL_IX_FORCE_ADJV_MAP_MAX "SS_TOUCH_ACTIVE_TOTAL_IX_ADJ_VERTICAL"
+#define SS_TOTAL_IX_SENSE_ADJH_MAP_MAX "SS_TOUCH_ACTIVE_TOTAL_IX_ADJ_HORIZONTAL"
+#define SS_TOTAL_CX_FORCE_MAP_MIN "SS_TOUCH_ACTIVE_TOTAL_CX_FORCE_MIN"
+#define SS_TOTAL_CX_FORCE_MAP_MAX "SS_TOUCH_ACTIVE_TOTAL_CX_FORCE_MAX"
+#define SS_TOTAL_CX_SENSE_MAP_MIN "SS_TOUCH_ACTIVE_TOTAL_CX_SENSE_MIN"
+#define SS_TOTAL_CX_SENSE_MAP_MAX "SS_TOUCH_ACTIVE_TOTAL_CX_SENSE_MAX"
+#define SS_TOTAL_CX_FORCE_ADJV_MAP_MAX "SS_TOUCH_ACTIVE_TOTAL_CX_ADJ_VERTICAL"
+#define SS_TOTAL_CX_SENSE_ADJH_MAP_MAX "SS_TOUCH_ACTIVE_TOTAL_CX_ADJ_HORIZONTAL"
+
+/* KEYS */
+#define MS_KEY_RAW_MIN_MAX "MS_KEY_RAW_DATA_MIN_MAX"
+#define MS_KEY_CX1_MIN_MAX "MS_KEY_CX1_MIN_MAX"
+#define MS_KEY_CX2_MAP_MIN "MS_KEY_CX2_MIN"
+#define MS_KEY_CX2_MAP_MAX "MS_KEY_CX2_MAX"
+#define MS_KEY_TOTAL_CX_MAP_MIN "MS_KEY_TOTAL_CX_MIN"
+#define MS_KEY_TOTAL_CX_MAP_MAX "MS_KEY_TOTAL_CX_MAX"
+
+/* CONSTANT TOTAL IX */
+#define SS_IX1_FORCE_W "SS_IX1_FORCE_W"
+#define SS_IX2_FORCE_W "SS_IX2_FORCE_W"
+#define SS_IX1_SENSE_W "SS_IX1_SENSE_W"
+#define SS_IX2_SENSE_W "SS_IX2_SENSE_W"
+
+#define SAVE_FLAG_RETRY 3
+
+typedef struct {
+ int MutualRaw;
+ int MutualRawGap;
+ int MutualCx1;
+ int MutualCx2;
+ int MutualCx2Adj;
+ int MutualCxTotal;
+ int MutualCxTotalAdj;
+
+ int MutualKeyRaw;
+ int MutualKeyCx1;
+ int MutualKeyCx2;
+ int MutualKeyCxTotal;
+
+ int SelfForceRaw;
+ int SelfForceRawGap;
+ int SelfForceIx1;
+ int SelfForceIx2;
+ int SelfForceIx2Adj;
+ int SelfForceIxTotal;
+ int SelfForceIxTotalAdj;
+ int SelfForceCx1;
+ int SelfForceCx2;
+ int SelfForceCx2Adj;
+ int SelfForceCxTotal;
+ int SelfForceCxTotalAdj;
+
+ int SelfSenseRaw;
+ int SelfSenseRawGap;
+ int SelfSenseIx1;
+ int SelfSenseIx2;
+ int SelfSenseIx2Adj;
+ int SelfSenseIxTotal;
+ int SelfSenseIxTotalAdj;
+ int SelfSenseCx1;
+ int SelfSenseCx2;
+ int SelfSenseCx2Adj;
+ int SelfSenseCxTotal;
+ int SelfSenseCxTotalAdj;
+
+} TestToDo;
+
+int computeAdjHoriz(u8 *data, int row, int column, u8 **result);
+int computeAdjHorizTotal(u16 *data, int row, int column, u16 **result);
+int computeAdjVert(u8 *data, int row, int column, u8 **result);
+int computeAdjVertTotal(u16 *data, int row, int column, u16 **result);
+int computeTotal(u8 *data, u8 main, int row, int column, int m, int n, u16 **result);
+int checkLimitsMinMax(short *data, int row, int column, int min, int max);
+int checkLimitsMap(u8 *data, int row, int column, int *min, int *max);
+int checkLimitsMapTotal(u16 *data, int row, int column, int *min, int *max);
+int checkLimitsMapAdj(u8 *data, int row, int column, int *max);
+int checkLimitsMapAdjTotal(u16 *data, int row, int column, int *max);
+int production_test_ito(void);
+int production_test_initialization(void);
+int ms_compensation_tuning(void);
+int ss_compensation_tuning(void);
+int lp_timer_calibration(void);
+int save_cx_tuning(void);
+int production_test_splited_initialization(int saveToFlash);
+int production_test_main(char *pathThresholds, int stop_on_fail,
+ int saveInit, TestToDo *todo, u32 signature);
+int production_test_ms_raw(char *path_limits, int stop_on_fail, TestToDo *todo);
+int production_test_ms_cx(char *path_limits, int stop_on_fail, TestToDo *todo);
+int production_test_ss_raw(char *path_limits, int stop_on_fail, TestToDo *todo);
+int production_test_ss_ix_cx(char *path_limits, int stop_on_fail, TestToDo *todo);
+int production_test_data(char *path_limits, int stop_on_fail, TestToDo *todo);
+int production_test_ms_key_cx(char *path_limits, int stop_on_fail, TestToDo *todo);
+int production_test_ms_key_raw(char *path_limits);
+int save_mp_flag(u32 signature);
+int parseProductionTestLimits(char *path, char *label, int **data, int *row, int *column);
+int readLine(char *data, char **line, int size, int *n);
diff --git a/drivers/input/touchscreen/st/fts_lib/ftsTime.c b/drivers/input/touchscreen/st/fts_lib/ftsTime.c
new file mode 100644
index 000000000000..03a2a39fe10b
--- /dev/null
+++ b/drivers/input/touchscreen/st/fts_lib/ftsTime.c
@@ -0,0 +1,84 @@
+/*
+
+**************************************************************************
+** STMicroelectronics **
+**************************************************************************
+** marco.cali@st.com **
+**************************************************************************
+* *
+* FTS Utility for mesuring/handling the time *
+* *
+**************************************************************************
+**************************************************************************
+
+*/
+
+#include "ftsCrossCompile.h"
+#include "ftsTime.h"
+
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/platform_device.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <stdarg.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/serio.h>
+#include <linux/time.h>
+#include <linux/pm.h>
+#include <linux/delay.h>
+#include <linux/ctype.h>
+#include <linux/gpio.h>
+#include <linux/i2c.h>
+#include <linux/i2c-dev.h>
+#include <linux/fs.h>
+#include <linux/uaccess.h>
+#include <linux/power_supply.h>
+#include <linux/firmware.h>
+#include <linux/regulator/consumer.h>
+#include <linux/of_gpio.h>
+/* #include <linux/sec_sysfs.h> */
+
+void startStopWatch(StopWatch *w)
+{
+ w->start = current_kernel_time();
+}
+
+void stopStopWatch(StopWatch *w)
+{
+ w->end = current_kernel_time();
+}
+
+int elapsedMillisecond(StopWatch *w)
+{
+ int result;
+
+ result = ((w->end.tv_sec - w->start.tv_sec)*1000) + (w->end.tv_nsec - w->start.tv_nsec) / 1000000;
+ return result;
+}
+
+int elapsedNanosecond(StopWatch *w)
+{
+ int result;
+
+ result = ((w->end.tv_sec - w->start.tv_sec)*1000000000) + (w->end.tv_nsec - w->start.tv_nsec);
+ return result;
+}
+
+char *timestamp(void)
+{
+ char *result = NULL;
+ result = (char *)kmalloc((1)*sizeof(char), GFP_KERNEL);
+ if (result == NULL)
+ return NULL;
+ result[0] = ' ';
+ return result;
+}
+
+void stdelay(unsigned long ms)
+{
+ msleep(ms);
+}
diff --git a/drivers/input/touchscreen/st/fts_lib/ftsTime.h b/drivers/input/touchscreen/st/fts_lib/ftsTime.h
new file mode 100644
index 000000000000..5eeca6eace97
--- /dev/null
+++ b/drivers/input/touchscreen/st/fts_lib/ftsTime.h
@@ -0,0 +1,29 @@
+/*
+
+**************************************************************************
+** STMicroelectronics **
+**************************************************************************
+** marco.cali@st.com **
+**************************************************************************
+* *
+* FTS Utility for mesuring/handling the time *
+* *
+**************************************************************************
+**************************************************************************
+
+*/
+
+#include "ftsCrossCompile.h"
+
+#include <linux/time.h>
+
+typedef struct {
+ struct timespec start, end;
+} StopWatch;
+
+void startStopWatch(StopWatch *w);
+void stopStopWatch(StopWatch *w);
+int elapsedMillisecond(StopWatch *w);
+int elapsedNanosecond(StopWatch *w);
+char *timestamp(void);
+void stdelay(unsigned long ms);
diff --git a/drivers/input/touchscreen/st/fts_lib/ftsTool.c b/drivers/input/touchscreen/st/fts_lib/ftsTool.c
new file mode 100644
index 000000000000..4c5d54f17ea7
--- /dev/null
+++ b/drivers/input/touchscreen/st/fts_lib/ftsTool.c
@@ -0,0 +1,706 @@
+/*
+
+**************************************************************************
+** STMicroelectronics **
+**************************************************************************
+** marco.cali@st.com **
+**************************************************************************
+* *
+* FTS Utility Functions *
+* *
+**************************************************************************
+**************************************************************************
+
+*/
+
+#include "ftsCompensation.h"
+#include "ftsCrossCompile.h"
+#include "ftsError.h"
+#include "ftsHardware.h"
+#include "ftsIO.h"
+#include "ftsSoftware.h"
+#include "ftsTime.h"
+#include "ftsTool.h"
+#include "../fts.h" /* needed for the PHONE_KEY define */
+
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/platform_device.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <stdarg.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/serio.h>
+#include <linux/init.h>
+#include <linux/pm.h>
+#include <linux/delay.h>
+#include <linux/ctype.h>
+#include <linux/fs.h>
+#include <linux/uaccess.h>
+#include <linux/power_supply.h>
+#include <linux/firmware.h>
+#include <linux/gpio.h>
+
+/* static char tag[8]="[ FTS ]\0"; */
+static int reset_gpio = GPIO_NOT_DEFINED;
+static int system_resetted_up;
+static int system_resetted_down;
+extern chipInfo ftsInfo;
+
+int readB2(u16 address, u8 *outBuf, int len)
+{
+ int remaining = len;
+ int toRead = 0;
+ int retry = 0;
+ int ret;
+ int event_to_search[3];
+ u8 *readEvent = (u8 *)kmalloc(FIFO_EVENT_SIZE*sizeof(u8), GFP_KERNEL);
+ u8 cmd[4] = { FTS_CMD_REQU_FW_CONF, 0x00, 0x00, (u8)len };
+
+ if (readEvent == NULL) {
+ logError(1, "%s readB2: ERROR %02X\n", tag, ERROR_ALLOC);
+ return ERROR_ALLOC;
+ }
+
+ u16ToU8_be(address, &cmd[1]);
+
+ logError(0, "%s %s", tag, printHex("Command B2 = ", cmd, 4));
+ do {
+ remaining = len;
+ ret = fts_writeFwCmd(cmd, 4);
+ if (ret < 0) {
+ logError(1, "%s readB2: ERROR %02X\n", tag, ERROR_I2C_W);
+ return ret;
+ } /* ask to the FW the data */
+ logError(0, "%s Command to FW sent!\n", tag);
+ event_to_search[0] = (int)EVENTID_FW_CONFIGURATION;
+
+ while (remaining > OK) {
+ event_to_search[1] = (int)((address & 0xFF00)>>8);
+ event_to_search[2] = (int) (address & 0x00FF);
+ if (remaining > B2_DATA_BYTES) {
+ toRead = B2_DATA_BYTES;
+ remaining -= B2_DATA_BYTES;
+ } else {
+ toRead = remaining;
+ remaining = 0;
+ }
+
+ ret = pollForEvent(event_to_search, 3, readEvent, GENERAL_TIMEOUT);
+ if (ret >= OK) { /* start the polling for reading the reply */
+ memcpy(outBuf, &readEvent[3], toRead);
+ retry = 0;
+ outBuf += toRead;
+
+ } else {
+ retry += 1;
+ break;
+ }
+ address += B2_DATA_BYTES;
+ }
+
+ } while (retry < B2_RETRY && retry != 0);
+
+ kfree(readEvent);
+ if (retry == B2_RETRY) {
+ logError(1, "%s readB2: ERROR %02X\n", tag, ERROR_TIMEOUT);
+ return ERROR_TIMEOUT;
+ }
+ logError(0, "%s B2 read %d bytes\n", tag, len);
+
+ return OK;
+}
+
+int readB2U16(u16 address, u8 *outBuf, int byteToRead)
+{
+
+ int remaining = byteToRead;
+ int toRead = 0;
+ int ret;
+
+ u8 *buff = (u8 *)kmalloc((B2_CHUNK + 1)*sizeof(u8), GFP_KERNEL);
+ if (buff == NULL) {
+ logError(1, "%s readB2U16: ERROR %02X\n", tag, ERROR_ALLOC);
+ return ERROR_ALLOC;
+ }
+
+ while (remaining > 0) {
+ if (remaining >= B2_CHUNK) {
+ toRead = B2_CHUNK;
+ remaining -= B2_CHUNK;
+ } else {
+ toRead = remaining;
+ remaining = 0;
+ }
+
+ ret = readB2(address, buff, toRead);
+ if (ret < 0)
+ return ret;
+ memcpy(outBuf, buff, toRead);
+
+ address += toRead;
+
+ outBuf += toRead;
+
+ }
+
+ kfree(buff);
+ return OK;
+}
+
+int releaseInformation(void)
+{
+ int ret;
+ u8 cmd[1] = { FTS_CMD_RELEASE_INFO };
+ int event_to_search[1];
+ u8 readEvent[FIFO_EVENT_SIZE];
+
+ event_to_search[0] = (int)EVENTID_RELEASE_INFO;
+
+ logError(0, "%s releaseInformation started... Chip INFO:\n", tag);
+
+ ret = fts_writeFwCmd(cmd, 1);
+ if (ret < OK) {
+ logError(1, "%s releaseInformation: ERROR %02X\n", tag, ret);
+ return ret;
+ }
+
+ ret = pollForEvent(event_to_search, 1, &readEvent[0], RELEASE_INFO_TIMEOUT);
+ /* start the polling for reading the reply */
+ if (ret < OK) {
+ logError(1, "%s releaseInformation: ERROR %02X\n", tag, ret);
+ return ret;
+ }
+
+ logError(0, "%s releaseInformation: Finished!\n", tag, ret);
+ return OK;
+
+}
+
+char *printHex(char *label, u8 *buff, int count)
+{
+ int i, offset;
+ char *result = NULL;
+
+ offset = strlen(label);
+ result = (char *)kmalloc(((offset + 3 * count) + 1)*sizeof(char), GFP_KERNEL);
+ if (result != NULL) {
+ strlcpy(result, label, sizeof(result));
+
+ for (i = 0; i < count; i++) {
+ snprintf(&result[offset + i * 3], 4, "%02X ", buff[i]);
+ }
+ strlcat(result, "\n", sizeof(result));
+ }
+ return result;
+}
+
+int pollForEvent(int *event_to_search, int event_bytes, u8 *readData, int time_to_wait)
+{
+ int i, find, retry, count_err;
+ int time_to_count;
+ int err_handling = OK;
+ StopWatch clock;
+
+ u8 cmd[1] = { FIFO_CMD_READONE };
+ char *temp = NULL;
+
+ find = 0;
+ retry = 0;
+ count_err = 0;
+ time_to_count = time_to_wait / TIMEOUT_RESOLUTION;
+
+ startStopWatch(&clock);
+ while (find != 1 && retry < time_to_count && fts_readCmd(cmd, 1, readData, FIFO_EVENT_SIZE) >= 0) {
+ /* Log of errors */
+ if (readData[0] == EVENTID_ERROR_EVENT) {
+ logError(1, "%s %s", tag, printHex("ERROR EVENT = ", readData, FIFO_EVENT_SIZE));
+ count_err++;
+ err_handling = errorHandler(readData, FIFO_EVENT_SIZE);
+ if ((err_handling&0xF0FF0000) == ERROR_HANDLER_STOP_PROC) {
+ logError(1, "%s pollForEvent: forced to be stopped! ERROR %08X\n", tag, err_handling);
+ return err_handling;
+ }
+ } else {
+ if (readData[0] != EVENTID_NO_EVENT) {
+ logError(1, "%s %s", tag, printHex("READ EVENT = ", readData, FIFO_EVENT_SIZE));
+ }
+ if (readData[0] == EVENTID_CONTROL_READY && event_to_search[0] != EVENTID_CONTROL_READY) {
+ logError(1, "%s pollForEvent: Unmanned Controller Ready Event! Setting reset flags...\n", tag);
+ setSystemResettedUp(1);
+ setSystemResettedDown(1);
+ }
+ }
+
+ find = 1;
+
+ for (i = 0; i < event_bytes; i++) {
+
+ if (event_to_search[i] != -1 && (int)readData[i] != event_to_search[i]) {
+ find = 0;
+ break;
+ }
+ }
+
+ retry++;
+ msleep(TIMEOUT_RESOLUTION);
+ }
+ stopStopWatch(&clock);
+ if ((retry >= time_to_count) && find != 1) {
+ logError(1, "%s pollForEvent: ERROR %02X\n", tag, ERROR_TIMEOUT);
+ return ERROR_TIMEOUT;
+ } else if (find == 1) {
+ temp = printHex("FOUND EVENT = ", readData, FIFO_EVENT_SIZE);
+ if (temp != NULL)
+ logError(0, "%s %s", tag, temp);
+ kfree(temp);
+ logError(0, "%s Event found in %d ms (%d iterations)! Number of errors found = %d\n", tag, elapsedMillisecond(&clock), retry, count_err);
+ return count_err;
+ }
+ logError(1, "%s pollForEvent: ERROR %02X\n", tag, ERROR_I2C_R);
+ return ERROR_I2C_R;
+}
+
+int flushFIFO(void)
+{
+
+ u8 cmd = FIFO_CMD_FLUSH; /* flush the FIFO */
+ if (fts_writeCmd(&cmd, 1) < 0) {
+ logError(1, "%s flushFIFO: ERROR %02X\n", tag, ERROR_I2C_W);
+ return ERROR_I2C_W;
+ }
+
+ logError(0, "%s FIFO flushed!\n", tag);
+ return OK;
+
+}
+
+int fts_disableInterrupt(void)
+{
+ u8 cmd[4] = { FTS_CMD_HW_REG_W, 0x00, 0x00, IER_DISABLE }; /* disable interrupt */
+ u16ToU8_be(IER_ADDR, &cmd[1]);
+
+ if (fts_writeCmd(cmd, 4) < OK) {
+ logError(1, "%s fts_disableInterrupt: ERROR %02X\n", tag, ERROR_I2C_W);
+ return ERROR_I2C_W;
+ }
+ logError(0, "%s Interrupt Disabled!\n", tag);
+ return OK;
+}
+
+int fts_enableInterrupt(void)
+{
+ u8 cmd[4] = { FTS_CMD_HW_REG_W, 0x00, 0x00, IER_ENABLE }; /* enable interrupt */
+ u16ToU8_be(IER_ADDR, &cmd[1]);
+ if (fts_writeCmd(cmd, 4) < 0) {
+ logError(1, "%s fts_enableInterrupt: ERROR %02X\n", tag, ERROR_I2C_W);
+ return ERROR_I2C_W;
+ }
+ logError(0, "%s Interrupt Enabled!\n", tag);
+ return OK;
+}
+
+int u8ToU16n(u8 *src, int src_length, u16 *dst)
+{
+ int i, j;
+
+ if (src_length % 2 != 0) {
+ return 0;
+ }
+ j = 0;
+ dst = (u16 *)kmalloc((src_length / 2)*sizeof(u16), GFP_KERNEL);
+ for (i = 0; i < src_length; i += 2) {
+ dst[j] = ((src[i+1] & 0x00FF) << 8) + (src[i] & 0x00FF);
+ j++;
+ }
+
+ return (src_length / 2);
+}
+
+int u8ToU16(u8 *src, u16 *dst)
+{
+ *dst = (u16)(((src[1] & 0x00FF) << 8) + (src[0] & 0x00FF));
+ return 0;
+}
+
+int u8ToU16_le(u8 *src, u16 *dst)
+{
+ *dst = (u16)(((src[0] & 0x00FF) << 8) + (src[1] & 0x00FF));
+ return 0;
+}
+
+int u16ToU8n(u16 *src, int src_length, u8 *dst)
+{
+ int i, j;
+ dst = (u8 *)kmalloc((2 * src_length)*sizeof(u8), GFP_KERNEL);
+ j = 0;
+ for (i = 0; i < src_length; i++) {
+ dst[j] = (u8) (src[i] & 0xFF00)>>8;
+ dst[j+1] = (u8) (src[i] & 0x00FF);
+ j += 2;
+ }
+
+ return src_length * 2;
+
+}
+
+int u16ToU8(u16 src, u8 *dst)
+{
+ dst[0] = (u8)((src & 0xFF00) >> 8);
+ dst[1] = (u8)(src & 0x00FF);
+ return 0;
+}
+
+int u16ToU8_be(u16 src, u8 *dst)
+{
+ dst[0] = (u8)((src & 0xFF00) >> 8);
+ dst[1] = (u8)(src & 0x00FF);
+ return 0;
+}
+
+int u16ToU8_le(u16 src, u8 *dst)
+{
+ dst[1] = (u8)((src & 0xFF00) >> 8);
+ dst[0] = (u8)(src & 0x00FF);
+ return 0;
+}
+
+int u8ToU32(u8 *src, u32 *dst)
+{
+ *dst = (u32)(((src[3] & 0x000000FF) << 24) + ((src[2] & 0x000000FF) << 16) + ((src[1] & 0x000000FF) << 8) + (src[0] & 0x000000FF));
+ return 0;
+}
+
+int u32ToU8(u32 src, u8 *dst)
+{
+ dst[3] = (u8)((src & 0xFF000000) >> 24);
+ dst[2] = (u8)((src & 0x00FF0000) >> 16);
+ dst[1] = (u8)((src & 0x0000FF00) >> 8);
+ dst[0] = (u8)(src & 0x000000FF);
+ return 0;
+}
+
+int attempt_function(int(*code)(void), unsigned long wait_before_retry, int retry_count)
+{
+ int result;
+ int count = 0;
+
+ do {
+ result = code();
+ count++;
+ msleep(wait_before_retry);
+ } while (count < retry_count && result < 0);
+
+ if (count == retry_count)
+ return (result | ERROR_TIMEOUT);
+ else
+ return result;
+
+}
+
+void setResetGpio(int gpio)
+{
+ reset_gpio = gpio;
+ logError(1, "%s setResetGpio: reset_gpio = %d\n", tag, reset_gpio);
+}
+
+int fts_system_reset(void)
+{
+ u8 readData[FIFO_EVENT_SIZE];
+ int event_to_search;
+ int res = -1;
+ int i;
+ u8 cmd[4] = { FTS_CMD_HW_REG_W, 0x00, 0x00, SYSTEM_RESET_VALUE };
+ event_to_search = (int)EVENTID_CONTROL_READY;
+
+ u16ToU8_be(SYSTEM_RESET_ADDRESS, &cmd[1]);
+ logError(0, "%s System resetting...\n", tag);
+ for (i = 0; i < SYSTEM_RESET_RETRY && res < 0; i++) {
+
+ if (reset_gpio == GPIO_NOT_DEFINED) {
+ res = fts_writeCmd(cmd, 4);
+ } else {
+ gpio_set_value(reset_gpio, 0);
+ msleep(10);
+ gpio_set_value(reset_gpio, 1);
+ res = OK;
+ }
+ if (res < OK) {
+ logError(1, "%s fts_system_reset: ERROR %02X\n", tag, ERROR_I2C_W);
+ } else {
+ res = pollForEvent(&event_to_search, 1, readData, GENERAL_TIMEOUT);
+ if (res < OK) {
+ logError(1, "%s fts_system_reset: ERROR %02X\n", tag, res);
+ }
+ }
+ }
+ if (res < OK) {
+ logError(1, "%s fts_system_reset...failed after 3 attempts: ERROR %02X\n", tag, (res | ERROR_SYSTEM_RESET_FAIL));
+ return (res | ERROR_SYSTEM_RESET_FAIL);
+ }
+ logError(0, "%s System reset DONE!\n", tag);
+ system_resetted_down = 1;
+ system_resetted_up = 1;
+ return OK;
+
+}
+
+int isSystemResettedDown(void)
+{
+ return system_resetted_down;
+}
+
+int isSystemResettedUp(void)
+{
+ return system_resetted_up;
+}
+
+void setSystemResettedDown(int val)
+{
+ system_resetted_down = val;
+}
+
+void setSystemResettedUp(int val)
+{
+ system_resetted_up = val;
+}
+
+int senseOn(void)
+{
+ int ret;
+ u8 cmd[1] = { FTS_CMD_MS_MT_SENSE_ON };
+
+ ret = fts_writeFwCmd(cmd, 1);
+ if (ret < OK) {
+ logError(1, "%s senseOn: ERROR %02X\n", tag, ERROR_SENSE_ON_FAIL);
+ return (ret|ERROR_SENSE_ON_FAIL);
+ }
+
+ logError(0, "%s senseOn: SENSE ON\n", tag);
+ return OK;
+}
+
+int senseOff(void)
+{
+ int ret;
+ u8 cmd[1] = { FTS_CMD_MS_MT_SENSE_OFF };
+
+ ret = fts_writeFwCmd(cmd, 1);
+ if (ret < OK) {
+ logError(1, "%s senseOff: ERROR %02X\n", tag, ERROR_SENSE_OFF_FAIL);
+ return (ret | ERROR_SENSE_OFF_FAIL);
+ }
+
+ logError(0, "%s senseOff: SENSE OFF\n", tag);
+ return OK;
+
+}
+
+int keyOn(void)
+{
+ int ret;
+ u8 cmd[1] = { FTS_CMD_MS_KEY_ON };
+
+ ret = fts_writeFwCmd(cmd, 1);
+ if (ret < OK) {
+ logError(1, "%s keyOn: ERROR %02X\n", tag, ERROR_SENSE_ON_FAIL);
+ return (ret | ERROR_SENSE_ON_FAIL);
+ }
+
+ logError(0, "%s keyOn: KEY ON\n", tag);
+ return OK;
+
+}
+
+int keyOff(void)
+{
+ int ret;
+ u8 cmd[1] = { FTS_CMD_MS_KEY_OFF };
+
+ ret = fts_writeFwCmd(cmd, 1);
+ if (ret < OK) {
+ logError(1, "%s keyOff: ERROR %02X\n", tag, ERROR_SENSE_OFF_FAIL);
+ return (ret | ERROR_SENSE_OFF_FAIL);
+ }
+
+ logError(0, "%s keyOff: KEY OFF\n", tag);
+ return OK;
+
+}
+
+int cleanUp(int enableTouch)
+{
+ int res;
+
+ logError(0, "%s cleanUp: system reset...\n", tag);
+ res = fts_system_reset();
+ if (res < OK)
+ return res;
+ if (enableTouch) {
+ logError(0, "%s cleanUp: enabling touches...\n", tag);
+ res = senseOn();
+ if (res < OK)
+ return res;
+#ifdef PHONE_KEY
+ res = keyOn();
+ if (res < OK)
+ return res;
+#endif
+ logError(0, "%s cleanUp: enabling interrupts...\n", tag);
+ res = fts_enableInterrupt();
+ if (res < OK)
+ return res;
+ }
+ return OK;
+
+}
+
+int checkEcho(u8 *cmd, int size)
+{
+ int ret, i;
+ int event_to_search[size+1];
+ u8 readData[FIFO_EVENT_SIZE];
+
+ if ((ftsInfo.u32_echoEn & 0x00000001) != ECHO_ENABLED) {
+ logError(1, "%s ECHO Not Enabled!\n", tag);
+ return OK;
+ }
+ if (size < 1) {
+ logError(1, "%s checkEcho: Error Size = %d not valid! or ECHO not Enabled! ERROR %08X\n", tag, size, ERROR_OP_NOT_ALLOW);
+ return ERROR_OP_NOT_ALLOW;
+ }
+ if ((size+2) > FIFO_EVENT_SIZE)
+ size = FIFO_EVENT_SIZE-2;
+ /* Echo event EC xx xx xx xx xx xx fifo_status therefore for command
+ *with more than 6 bytes will echo only the first 6
+ */
+ event_to_search[0] = EVENTID_ECHO;
+ for (i = 1; i <= size; i++) {
+ event_to_search[i] = cmd[i-1];
+ }
+ ret = pollForEvent(event_to_search, size+1, readData, GENERAL_TIMEOUT);
+ if (ret < OK) {
+ logError(1, "%s checkEcho: Echo Event not found! ERROR %02X\n", tag, ret);
+ return (ret | ERROR_CHECK_ECHO_FAIL);
+ }
+
+ logError(0, "%s ECHO OK!\n", tag);
+ return OK;
+}
+
+int featureEnableDisable(int on_off, u8 feature)
+{
+ int ret;
+ u8 cmd[2] = { 0x00, feature };
+
+ if (on_off == FEAT_ENABLE) {
+ cmd[0] = FTS_CMD_FEATURE_ENABLE;
+ logError(0, "%s featureEnableDisable: Enabling feature %02X ...\n", tag, feature);
+ } else {
+ cmd[0] = FTS_CMD_FEATURE_DISABLE;
+ logError(0, "%s featureEnableDisable: Disabling feature %02X ...\n", tag, feature);
+ }
+
+ ret = fts_writeCmd(cmd, 2); /* not use writeFwCmd because this function can be called also during interrupt enable and should be fast */
+ if (ret < OK) {
+ logError(1, "%s featureEnableDisable: ERROR %02X\n", tag, ret);
+ return (ret | ERROR_FEATURE_ENABLE_DISABLE);
+ }
+
+ logError(0, "%s featureEnableDisable: DONE!\n", tag);
+ return OK;
+
+}
+
+short **array1dTo2d_short(short *data, int size, int columns)
+{
+
+ int i;
+ short **matrix = (short **)kmalloc(((int)(size / columns))*sizeof(short *), GFP_KERNEL);
+ if (matrix != NULL) {
+ for (i = 0; i < (int)(size / columns); i++) {
+ matrix[i] = (short *)kmalloc(columns*sizeof(short), GFP_KERNEL);
+ }
+
+ for (i = 0; i < size; i++)
+ matrix[i / columns][i % columns] = data[i];
+ }
+
+ return matrix;
+}
+
+u8 **array1dTo2d_u8(u8 *data, int size, int columns)
+{
+
+ int i;
+ u8 **matrix = (u8 **)kmalloc(((int)(size / columns))*sizeof(u8 *), GFP_KERNEL);
+ if (matrix != NULL) {
+ for (i = 0; i < (int)(size / columns); i++) {
+ matrix[i] = (u8 *)kmalloc(columns*sizeof(u8), GFP_KERNEL);
+ }
+
+ for (i = 0; i < size; i++)
+ matrix[i / columns][i % columns] = data[i];
+ }
+
+ return matrix;
+}
+
+void print_frame_short(char *label, short **matrix, int row, int column)
+{
+ int i, j;
+ logError(0, "%s %s\n", tag, label);
+ for (i = 0; i < row; i++) {
+ logError(0, "%s ", tag);
+ for (j = 0; j < column; j++) {
+ printk("%d ", matrix[i][j]);
+ }
+ logError(0, "\n");
+ kfree(matrix[i]);
+ }
+}
+
+void print_frame_u8(char *label, u8 **matrix, int row, int column)
+{
+ int i, j;
+ logError(0, "%s %s\n", tag, label);
+ for (i = 0; i < row; i++) {
+ logError(0, "%s ", tag);
+ for (j = 0; j < column; j++) {
+ printk("%d ", matrix[i][j]);
+ }
+ logError(0, "\n");
+ kfree(matrix[i]);
+ }
+}
+
+void print_frame_u32(char *label, u32 **matrix, int row, int column)
+{
+ int i, j;
+ logError(0, "%s %s\n", tag, label);
+ for (i = 0; i < row; i++) {
+ logError(0, "%s ", tag);
+ for (j = 0; j < column; j++) {
+ printk("%d ", matrix[i][j]);
+ }
+ logError(0, "\n");
+ kfree(matrix[i]);
+ }
+}
+
+void print_frame_int(char *label, int **matrix, int row, int column)
+{
+ int i, j;
+ logError(0, "%s %s\n", tag, label);
+ for (i = 0; i < row; i++) {
+ logError(0, "%s ", tag);
+ for (j = 0; j < column; j++) {
+ printk("%d ", matrix[i][j]);
+ }
+ logError(0, "\n");
+ kfree(matrix[i]);
+ }
+}
diff --git a/drivers/input/touchscreen/st/fts_lib/ftsTool.h b/drivers/input/touchscreen/st/fts_lib/ftsTool.h
new file mode 100644
index 000000000000..a90e79fc5607
--- /dev/null
+++ b/drivers/input/touchscreen/st/fts_lib/ftsTool.h
@@ -0,0 +1,64 @@
+/*
+
+**************************************************************************
+** STMicroelectronics **
+**************************************************************************
+** marco.cali@st.com **
+**************************************************************************
+* *
+* FTS Utility Functions *
+* *
+**************************************************************************
+**************************************************************************
+
+*/
+#define GPIO_NOT_DEFINED -1
+
+#define TIMEOUT_RESOLUTION 10 /* ms */
+#define GENERAL_TIMEOUT (50*TIMEOUT_RESOLUTION) /* ms */
+#define RELEASE_INFO_TIMEOUT (15*TIMEOUT_RESOLUTION) /* ms */
+
+#define FEAT_ENABLE 1
+#define FEAT_DISABLE 0
+
+#define SYSTEM_RESET_RETRY 3
+
+#define B2_RETRY 2
+
+int readB2(u16 address, u8 *outBuf, int len);
+int readB2U16(u16 address, u8 *outBuf, int byteToRead);
+int releaseInformation(void);
+char *printHex(char *label, u8 *buff, int count);
+int pollForEvent(int *event_to_search, int event_bytes, u8 *readData, int time_to_wait);
+int fts_disableInterrupt(void);
+int fts_enableInterrupt(void);
+int u8ToU16(u8 *src, u16 *dst);
+int u8ToU16_le(u8 *src, u16 *dst);
+int u8ToU16n(u8 *src, int src_length, u16 *dst);
+int u16ToU8(u16 src, u8 *dst);
+int u16ToU8_le(u16 src, u8 *dst);
+int u16ToU8_be(u16 src, u8 *dst);
+int u16ToU8n(u16 *src, int src_length, u8 *dst);
+int u8ToU32(u8 *src, u32 *dst);
+int u32ToU8(u32 src, u8 *dst);
+int attempt_function(int(*code)(void), unsigned long wait_before_retry, int retry_count);
+void setResetGpio(int gpio);
+int fts_system_reset(void);
+int isSystemResettedUp(void);
+int isSystemResettedDown(void);
+void setSystemResettedUp(int val);
+void setSystemResettedDown(int val);
+int senseOn(void);
+int senseOff(void);
+int keyOn(void);
+int keyOff(void);
+int featureEnableDisable(int on_off, u8 feature);
+int checkEcho(u8 *cmd, int size);
+void print_frame_short(char *label, short **matrix, int row, int column);
+short **array1dTo2d_short(short *data, int size, int columns);
+u8 **array1dTo2d_u8(u8 *data, int size, int columns);
+void print_frame_u8(char *label, u8 **matrix, int row, int column);
+void print_frame_u32(char *label, u32 **matrix, int row, int column);
+void print_frame_int(char *label, int **matrix, int row, int column);
+int cleanUp(int enableTouch);
+int flushFIFO(void);
diff --git a/drivers/input/touchscreen/st/fts_limits.h b/drivers/input/touchscreen/st/fts_limits.h
new file mode 100644
index 000000000000..d3be1a2b1e1a
--- /dev/null
+++ b/drivers/input/touchscreen/st/fts_limits.h
@@ -0,0 +1,10 @@
+#ifndef FTS_LIMITS_H
+#define FTS_LIMITS_H
+/* This is an auto generated header file
+* --->Remember to change the name of the two variables!<--- */
+const uint32_t myArray2_size;
+
+const uint8_t myArray2[] = {
+};
+
+#endif