Update kernel to ab/13436313

Change-Id: I28b8626dd9918e85fb0be83d7533c68e304ddd12
diff --git a/BUILD.bazel b/BUILD.bazel
new file mode 100644
index 0000000..a7ffc06
--- /dev/null
+++ b/BUILD.bazel
@@ -0,0 +1,42 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+load("//build/kernel/kleaf:kernel.bzl", "kernel_module")
+
+filegroup(
+    name = "sec.kconfig",
+    srcs = [
+        "Kconfig",
+    ],
+    visibility = [
+        "//private/devices/google:__subpackages__",
+        "//private/google-modules/soc/gs:__pkg__",
+    ],
+)
+
+kernel_module(
+    name = "sec",
+    srcs = glob([
+        "**/*.c",
+        "**/*.h",
+    ]) + [
+        "Kbuild",
+        "//private/google-modules/display/common:headers",
+        "//private/google-modules/display/samsung:headers",
+        "//private/google-modules/display/samsung/include:headers",
+        "//private/google-modules/soc/gs:gs_soc_headers",
+        "//private/google-modules/touch/common:headers",
+    ],
+    outs = [
+        "sec_touch.ko",
+    ],
+    kernel_build = "//private/devices/google/common:kernel",
+    visibility = [
+        "//private/devices/google:__subpackages__",
+        "//private/google-modules/soc/gs:__pkg__",
+    ],
+    deps = [
+        "//private/google-modules/display/common/gs_drm",
+        "//private/google-modules/display/samsung:display.samsung",
+        "//private/google-modules/touch/common:touch.common",
+    ],
+)
diff --git a/Kbuild b/Kbuild
new file mode 100644
index 0000000..b4b0eda
--- /dev/null
+++ b/Kbuild
@@ -0,0 +1,11 @@
+# SPDX-License-Identifier: GPL-2.0
+
+ccflags-y += -I$(srctree)/../private/google-modules/display
+ccflags-y += -I$(srctree)/../private/google-modules/display/common/include
+ccflags-y += -I$(srctree)/../private/google-modules/display/samsung/include/uapi
+ccflags-y += -I$(srctree)/../private/google-modules/touch/common
+ccflags-y += -I$(srctree)/../private/google-modules/touch/common/include
+
+obj-$(CONFIG_TOUCHSCREEN_SEC_TS)   += sec_touch.o
+sec_touch-objs   += sec_ts.o sec_ts_fw.o sec_ts_fn.o sec_cmd.o \
+	sec_ts_only_vendor.o
diff --git a/Kconfig b/Kconfig
new file mode 100644
index 0000000..26af351
--- /dev/null
+++ b/Kconfig
@@ -0,0 +1,23 @@
+#
+# Samsung Electronics TOUCH driver configuration
+#
+
+config TOUCHSCREEN_SEC_TS
+        tristate "Samsung Electronics Touchscreen"
+        depends on I2C || SPI
+        select TOUCHSCREEN_HEATMAP
+        help
+          Say Y here if you want support for SEC touchscreen controllers.
+          If unsure, say N.
+
+          To compile this driver as a module, choose M here: the
+          module will be called sec_ts.
+
+config TOUCHSCREEN_SEC_TS_GLOVEMODE
+        tristate "Samsung Electronics Touchscreen"
+        depends on I2C
+        help
+          Say Y here if you have a Samsung Electronics Touchscreen and want to enable
+          support for the built-in touchscreen.
+
+          If unsure, say N.
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..fcda0a6
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: GPL-2.0
+
+KERNEL_SRC ?= /lib/modules/$(shell uname -r)/build
+M ?= $(shell pwd)
+
+EXTRA_CFLAGS	+= -DDYNAMIC_DEBUG_MODULE
+EXTRA_SYMBOLS	+= $(OUT_DIR)/../private/google-modules/display/common/gs_drm/Module.symvers
+EXTRA_SYMBOLS	+= $(OUT_DIR)/../private/google-modules/display/samsung/Module.symvers
+EXTRA_SYMBOLS	+= $(OUT_DIR)/../private/google-modules/touch/common/Module.symvers
+
+modules modules_install clean:
+	$(MAKE) -C $(KERNEL_SRC) M=$(M) \
+	EXTRA_CFLAGS="$(EXTRA_CFLAGS)" KBUILD_EXTRA_SYMBOLS="$(EXTRA_SYMBOLS)" $(@)
diff --git a/sec_cmd.c b/sec_cmd.c
new file mode 100644
index 0000000..0b9e93e
--- /dev/null
+++ b/sec_cmd.c
@@ -0,0 +1,585 @@
+/*
+ * sec_cmd.c - samsung factory command driver
+ *
+ * Copyright (C) 2014 Samsung Electronics
+ *
+ * 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 "sec_cmd.h"
+
+#if defined USE_SEC_CMD_QUEUE
+static void sec_cmd_store_function(struct sec_cmd_data *data);
+#endif
+
+void sec_cmd_set_cmd_exit(struct sec_cmd_data *data)
+{
+	atomic_set(&data->cmd_is_running, 0);
+
+#ifdef USE_SEC_CMD_QUEUE
+	mutex_lock(&data->fifo_lock);
+	if (kfifo_len(&data->cmd_queue)) {
+		pr_info("%s %s: do next cmd, left cmd[%d]\n", SECLOG, __func__,
+			(int)(kfifo_len(&data->cmd_queue) /
+			      sizeof(struct command)));
+		mutex_unlock(&data->fifo_lock);
+
+		atomic_set(&data->cmd_is_running, 1);
+
+		data->cmd_state = SEC_CMD_STATUS_RUNNING;
+		sec_cmd_store_function(data);
+
+	} else {
+		mutex_unlock(&data->fifo_lock);
+	}
+#endif
+}
+
+void sec_cmd_set_default_result(struct sec_cmd_data *data)
+{
+	char delim = ':';
+
+	memset(data->cmd_result, 0x00, SEC_CMD_RESULT_STR_LEN);
+	memcpy(data->cmd_result, data->cmd, SEC_CMD_STR_LEN);
+	strncat(data->cmd_result, &delim, 1);
+	memset(data->cmd_result_2, 0x00, SEC_CMD_RESULT_STR_LEN);
+	memcpy(data->cmd_result_2, data->cmd, SEC_CMD_STR_LEN);
+	strncat(data->cmd_result_2, &delim, 1);
+}
+
+void sec_cmd_set_cmd_result(struct sec_cmd_data *data, char *buff, int len)
+{
+	strlcat(data->cmd_result, buff, SEC_CMD_RESULT_STR_LEN);
+}
+
+void sec_cmd_set_cmd_result_2(struct sec_cmd_data *data, char *buff, int len)
+{
+	strlcat(data->cmd_result_2, buff, SEC_CMD_RESULT_STR_LEN);
+}
+
+#ifndef USE_SEC_CMD_QUEUE
+static ssize_t cmd_store(struct device *dev,
+		struct device_attribute *devattr, const char *buf, size_t count)
+{
+	struct sec_cmd_data *data = dev_get_drvdata(dev);
+	char *cur, *start, *end;
+	char buff[SEC_CMD_STR_LEN] = { 0 };
+	size_t len;
+	struct sec_cmd *sec_cmd_ptr = NULL;
+	char delim = ',';
+	bool cmd_found = false;
+	unsigned int i, param_cnt = 0;
+
+	if (!data) {
+		pr_err("%s %s: No platform data found\n", SECLOG, __func__);
+		return -EINVAL;
+	}
+
+	if (count >= SEC_CMD_STR_LEN) {
+		pr_err("%s %s: cmd length is over (%s,%d)!!\n",
+		       SECLOG, __func__, buf, (int)count);
+		return -EINVAL;
+	}
+
+	if (atomic_cmpxchg(&data->cmd_is_running, 0, 1)) {
+		pr_err("%s %s: other cmd is running.\n", SECLOG, __func__);
+		return -EBUSY;
+	}
+
+	data->cmd_state = SEC_CMD_STATUS_RUNNING;
+	for (i = 0; i < ARRAY_SIZE(data->cmd_param); i++)
+		data->cmd_param[i] = 0;
+
+	len = count;
+	if (*(buf + len - 1) == '\n')
+		len--;
+
+	memset(data->cmd, 0x00, ARRAY_SIZE(data->cmd));
+	memcpy(data->cmd, buf, len);
+
+	cur = strchr(buf, (int)delim);
+	if (cur)
+		memcpy(buff, buf, cur - buf);
+	else
+		memcpy(buff, buf, len);
+
+	pr_debug("%s %s: COMMAND = %s\n", SECLOG, __func__, buff);
+
+	/* find command */
+	list_for_each_entry(sec_cmd_ptr, &data->cmd_list_head, list) {
+		if (!strncmp(buff, sec_cmd_ptr->cmd_name, SEC_CMD_STR_LEN)) {
+			cmd_found = true;
+			break;
+		}
+	}
+
+	/* set not_support_cmd */
+	if (!cmd_found) {
+		list_for_each_entry(sec_cmd_ptr, &data->cmd_list_head, list) {
+			if (!strncmp("not_support_cmd", sec_cmd_ptr->cmd_name,
+				SEC_CMD_STR_LEN))
+				break;
+		}
+	}
+
+	/* parsing parameters */
+	if (cur && cmd_found) {
+		cur++;
+		start = cur;
+		memset(buff, 0x00, ARRAY_SIZE(buff));
+
+		do {
+			if (*cur == delim || cur - buf == len) {
+				end = cur;
+				memcpy(buff, start, end - start);
+				*(buff +
+				  strnlen(buff, ARRAY_SIZE(buff))) = '\0';
+				if (kstrtoint(buff, 10,
+					      data->cmd_param + param_cnt) < 0)
+					goto err_out;
+				start = cur + 1;
+				memset(buff, 0x00, ARRAY_SIZE(buff));
+				param_cnt++;
+			}
+			cur++;
+		} while ((cur - buf <= len) && (param_cnt < SEC_CMD_PARAM_NUM));
+	}
+
+	if (cmd_found) {
+		pr_info("%s %s: cmd = %s",
+			SECLOG, __func__, sec_cmd_ptr->cmd_name);
+		for (i = 0; i < param_cnt; i++) {
+			if (i == 0)
+				pr_cont(" param =");
+			pr_cont(" %d", data->cmd_param[i]);
+		}
+		pr_cont("\n");
+	} else {
+		pr_info("%s %s: cmd = %s(%s)\n",
+			SECLOG, __func__, buff, sec_cmd_ptr->cmd_name);
+	}
+
+	sec_cmd_ptr->cmd_func(data);
+	sec_cmd_set_cmd_exit(data);
+
+err_out:
+	return count;
+}
+
+#else	/* defined USE_SEC_CMD_QUEUE */
+static void sec_cmd_store_function(struct sec_cmd_data *data)
+{
+	char *cur, *start, *end;
+	char buff[SEC_CMD_STR_LEN] = { 0 };
+	int len, i;
+	struct sec_cmd *sec_cmd_ptr = NULL;
+	char delim = ',';
+	bool cmd_found = false;
+	int param_cnt = 0;
+	int ret;
+	const char *buf;
+	size_t count;
+	struct command cmd = { {0} };
+
+	if (!data) {
+		pr_err("%s %s: No platform data found\n", SECLOG, __func__);
+		return;
+	}
+
+	mutex_lock(&data->fifo_lock);
+	if (kfifo_len(&data->cmd_queue)) {
+		ret = kfifo_out(&data->cmd_queue, &cmd, sizeof(struct command));
+		if (!ret) {
+			pr_err("%s %s: kfifo_out failed, it seems empty, ret=%d\n",
+			       SECLOG, __func__, ret);
+			mutex_unlock(&data->fifo_lock);
+			return;
+		}
+	} else {
+		pr_err("%s %s: left cmd is nothing\n", SECLOG, __func__);
+		mutex_unlock(&data->fifo_lock);
+		return;
+	}
+	mutex_unlock(&data->fifo_lock);
+
+	buf = cmd.cmd;
+	count = strlen(buf);
+
+	for (i = 0; i < (int)ARRAY_SIZE(data->cmd_param); i++)
+		data->cmd_param[i] = 0;
+
+	len = (int)count;
+	if (*(buf + len - 1) == '\n')
+		len--;
+
+	memset(data->cmd, 0x00, ARRAY_SIZE(data->cmd));
+	memcpy(data->cmd, buf, len);
+
+	cur = strchr(buf, (int)delim);
+	if (cur)
+		memcpy(buff, buf, cur - buf);
+	else
+		memcpy(buff, buf, len);
+
+	pr_debug("%s %s: COMMAND : %s\n", SECLOG, __func__, buff);
+
+	/* find command */
+	list_for_each_entry(sec_cmd_ptr, &data->cmd_list_head, list) {
+		if (!strncmp(buff, sec_cmd_ptr->cmd_name, SEC_CMD_STR_LEN)) {
+			cmd_found = true;
+			break;
+		}
+	}
+
+	/* set not_support_cmd */
+	if (!cmd_found) {
+		list_for_each_entry(sec_cmd_ptr, &data->cmd_list_head, list) {
+			if (!strncmp("not_support_cmd", sec_cmd_ptr->cmd_name,
+				SEC_CMD_STR_LEN))
+				break;
+		}
+	}
+
+	/* parsing parameters */
+	if (cur && cmd_found) {
+		cur++;
+		start = cur;
+		memset(buff, 0x00, ARRAY_SIZE(buff));
+
+		do {
+			if (*cur == delim || cur - buf == len) {
+				end = cur;
+				memcpy(buff, start, end - start);
+				*(buff +
+				  strnlen(buff, ARRAY_SIZE(buff))) = '\0';
+				if (kstrtoint(buff, 10,
+					      data->cmd_param + param_cnt) < 0)
+					return;
+				start = cur + 1;
+				memset(buff, 0x00, ARRAY_SIZE(buff));
+				param_cnt++;
+			}
+			cur++;
+		} while ((cur - buf <= len) && (param_cnt < SEC_CMD_PARAM_NUM));
+	}
+
+	if (cmd_found) {
+		pr_info("%s %s: cmd = %s",
+			SECLOG, __func__, sec_cmd_ptr->cmd_name);
+		for (i = 0; i < param_cnt; i++) {
+			if (i == 0)
+				pr_cont(" param =");
+			pr_cont(" %d", data->cmd_param[i]);
+		}
+		pr_cont("\n");
+	} else {
+		pr_info("%s %s: cmd = %s(%s)\n",
+			SECLOG, __func__, buff, sec_cmd_ptr->cmd_name);
+	}
+
+	sec_cmd_ptr->cmd_func(data);
+
+}
+
+static ssize_t cmd_store(struct device *dev,
+			     struct device_attribute *devattr,
+			     const char *buf, size_t count)
+{
+	struct sec_cmd_data *data = dev_get_drvdata(dev);
+	struct command cmd = { {0} };
+	int queue_size;
+
+	if (!data) {
+		pr_err("%s %s: No platform data found\n", SECLOG, __func__);
+		return -EINVAL;
+	}
+
+	if (count >= SEC_CMD_STR_LEN) {
+		pr_err("%s %s: cmd length is over (%s,%d)!!\n", SECLOG,
+			__func__, buf, (int)count);
+		return -EINVAL;
+	}
+
+	strlcpy(cmd.cmd, buf, sizeof(cmd.cmd));
+
+	mutex_lock(&data->fifo_lock);
+	queue_size = (kfifo_len(&data->cmd_queue) / sizeof(struct command));
+
+	if (kfifo_avail(&data->cmd_queue) && (queue_size < SEC_CMD_MAX_QUEUE)) {
+		kfifo_in(&data->cmd_queue, &cmd, sizeof(struct command));
+		pr_info("%s %s: push cmd: %s\n", SECLOG, __func__, cmd.cmd);
+	} else {
+		pr_err("%s %s: cmd_queue is full!!\n", SECLOG, __func__);
+
+		kfifo_reset(&data->cmd_queue);
+		pr_err("%s %s: cmd_queue is reset!!\n", SECLOG, __func__);
+		mutex_unlock(&data->fifo_lock);
+
+		atomic_set(&data->cmd_is_running, 0);
+
+		return -ENOSPC;
+	}
+
+	if (atomic_cmpxchg(&data->cmd_is_running, 0, 1)) {
+		pr_err("%s %s: other cmd is running. Wait until previous cmd is done[%d]\n",
+			SECLOG, __func__,
+			(int)(kfifo_len(&data->cmd_queue) /
+			      sizeof(struct command)));
+		mutex_unlock(&data->fifo_lock);
+
+		return -EBUSY;
+	}
+
+	mutex_unlock(&data->fifo_lock);
+
+	data->cmd_state = SEC_CMD_STATUS_RUNNING;
+	sec_cmd_store_function(data);
+
+	return count;
+}
+#endif
+
+static ssize_t cmd_status_show(struct device *dev,
+				 struct device_attribute *devattr, char *buf)
+{
+	struct sec_cmd_data *data = dev_get_drvdata(dev);
+	char buff[16] = { 0 };
+
+	if (!data) {
+		pr_err("%s %s: No platform data found\n", SECLOG, __func__);
+		return -EINVAL;
+	}
+
+	if (data->cmd_state == SEC_CMD_STATUS_WAITING)
+		snprintf(buff, sizeof(buff), "WAITING");
+
+	else if (data->cmd_state == SEC_CMD_STATUS_RUNNING)
+		snprintf(buff, sizeof(buff), "RUNNING");
+
+	else if (data->cmd_state == SEC_CMD_STATUS_OK)
+		snprintf(buff, sizeof(buff), "OK");
+
+	else if (data->cmd_state == SEC_CMD_STATUS_FAIL)
+		snprintf(buff, sizeof(buff), "FAIL");
+
+	else if (data->cmd_state == SEC_CMD_STATUS_NOT_APPLICABLE)
+		snprintf(buff, sizeof(buff), "NOT_APPLICABLE");
+
+	pr_debug("%s %s: %d, %s\n", SECLOG, __func__, data->cmd_state, buff);
+
+	return snprintf(buf, SEC_CMD_BUF_SIZE, "%s\n", buff);
+}
+
+static ssize_t cmd_result_show(struct device *dev,
+				 struct device_attribute *devattr, char *buf)
+{
+	struct sec_cmd_data *data = dev_get_drvdata(dev);
+	int size;
+
+	if (!data) {
+		pr_err("%s %s: No platform data found\n", SECLOG, __func__);
+		return -EINVAL;
+	}
+
+	data->cmd_state = SEC_CMD_STATUS_WAITING;
+	pr_info("%s %s: %s\n", SECLOG, __func__, data->cmd_result);
+	size = snprintf(buf, SEC_CMD_RESULT_STR_LEN, "%s\n", data->cmd_result);
+
+	sec_cmd_set_cmd_exit(data);
+
+	return size;
+}
+
+static ssize_t cmd_result_2_show(struct device *dev,
+				 struct device_attribute *devattr, char *buf)
+{
+	struct sec_cmd_data *data = dev_get_drvdata(dev);
+	int size;
+
+	if (!data) {
+		pr_err("%s %s: No platform data found\n", SECLOG, __func__);
+		return -EINVAL;
+	}
+
+	data->cmd_state = SEC_CMD_STATUS_WAITING;
+	pr_info("%s %s: %s\n", SECLOG, __func__, data->cmd_result_2);
+	size = snprintf(buf, SEC_CMD_RESULT_STR_LEN, "%s\n",
+			data->cmd_result_2);
+
+	sec_cmd_set_cmd_exit(data);
+
+	return size;
+}
+
+static ssize_t cmd_list_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct sec_cmd_data *data = dev_get_drvdata(dev);
+	struct sec_cmd *sec_cmd_ptr = NULL;
+	char *buffer = NULL;
+	char buffer_name[SEC_CMD_STR_LEN];
+	int ret = 0;
+
+	buffer = kzalloc(data->cmd_buffer_size + 30, GFP_KERNEL);
+	if (!buffer) {
+		pr_err("%s %s: No sec_cmd_list buffer\n", SECLOG, __func__);
+		return -EINVAL;
+	}
+
+	snprintf(buffer, 30, "++factory command list++\n");
+
+	list_for_each_entry(sec_cmd_ptr, &data->cmd_list_head, list) {
+		if (strncmp(sec_cmd_ptr->cmd_name, "not_support_cmd", 15)) {
+			snprintf(buffer_name, SEC_CMD_STR_LEN, "%s\n",
+				 sec_cmd_ptr->cmd_name);
+			strncat(buffer, buffer_name, SEC_CMD_STR_LEN);
+		}
+	}
+
+	ret = snprintf(buf, SEC_CMD_BUF_SIZE, "%s\n", buffer);
+	kfree(buffer);
+
+	return ret;
+}
+
+static DEVICE_ATTR_WO(cmd);
+static DEVICE_ATTR_RO(cmd_status);
+static DEVICE_ATTR_RO(cmd_result);
+static DEVICE_ATTR_RO(cmd_result_2);
+static DEVICE_ATTR_RO(cmd_list);
+
+static struct attribute *sec_fac_attrs[] = {
+	&dev_attr_cmd.attr,
+	&dev_attr_cmd_status.attr,
+	&dev_attr_cmd_result.attr,
+	&dev_attr_cmd_result_2.attr,
+	&dev_attr_cmd_list.attr,
+	NULL,
+};
+
+static struct attribute_group sec_fac_attr_group = {
+	.attrs = sec_fac_attrs,
+};
+
+
+int sec_cmd_init(struct sec_cmd_data *data, struct sec_cmd *cmds,
+			int len, int devt)
+{
+	const char *dev_name;
+	int ret, i;
+
+	INIT_LIST_HEAD(&data->cmd_list_head);
+
+	data->cmd_buffer_size = 0;
+	for (i = 0; i < len; i++) {
+		list_add_tail(&cmds[i].list, &data->cmd_list_head);
+		if (cmds[i].cmd_name)
+			data->cmd_buffer_size += strlen(cmds[i].cmd_name) + 1;
+	}
+
+	atomic_set(&data->cmd_is_running, 0);
+
+#ifdef USE_SEC_CMD_QUEUE
+	if (kfifo_alloc(&data->cmd_queue,
+		SEC_CMD_MAX_QUEUE * sizeof(struct command), GFP_KERNEL)) {
+		pr_err("%s %s: failed to alloc queue for cmd\n",
+		       SECLOG, __func__);
+		goto err_alloc_queue;
+	}
+	mutex_init(&data->fifo_lock);
+#endif
+
+	if (devt == SEC_CLASS_DEVT_TSP) {
+		dev_name = SEC_CLASS_DEV_NAME_TSP;
+
+	} else if (devt == SEC_CLASS_DEVT_TKEY) {
+		dev_name = SEC_CLASS_DEV_NAME_TKEY;
+
+	} else if (devt == SEC_CLASS_DEVT_WACOM) {
+		dev_name = SEC_CLASS_DEV_NAME_WACOM;
+
+	} else {
+		pr_err("%s %s: not defined devt=%d\n", SECLOG, __func__, devt);
+		goto err_get_dev_name;
+	}
+
+#ifdef CONFIG_SEC_SYSFS
+	data->fac_dev = sec_device_create(data, dev_name);
+#else
+	data->fac_dev = device_create(sec_class, NULL, devt, data, dev_name);
+#endif
+	if (IS_ERR(data->fac_dev)) {
+		pr_err("%s %s: failed to create device for the sysfs\n",
+		       SECLOG, __func__);
+		goto err_sysfs_device;
+	}
+
+	dev_set_drvdata(data->fac_dev, data);
+
+	ret = sysfs_create_group(&data->fac_dev->kobj, &sec_fac_attr_group);
+	if (ret < 0) {
+		pr_err("%s %s: failed to create sysfs group\n",
+		       SECLOG, __func__);
+		goto err_sysfs_group;
+	}
+
+	return 0;
+
+	sysfs_remove_group(&data->fac_dev->kobj, &sec_fac_attr_group);
+err_sysfs_group:
+#ifdef CONFIG_SEC_SYSFS
+	sec_device_destroy(data->fac_dev->devt);
+#else
+	device_destroy(sec_class, devt);
+#endif
+err_sysfs_device:
+err_get_dev_name:
+#ifdef USE_SEC_CMD_QUEUE
+	mutex_destroy(&data->fifo_lock);
+	kfifo_free(&data->cmd_queue);
+err_alloc_queue:
+#endif
+	list_del(&data->cmd_list_head);
+	return -ENODEV;
+}
+
+void sec_cmd_exit(struct sec_cmd_data *data, int devt)
+{
+#ifdef USE_SEC_CMD_QUEUE
+	struct command cmd = { {0} };
+	int ret;
+#endif
+
+	pr_info("%s %s", SECLOG, __func__);
+	sysfs_remove_group(&data->fac_dev->kobj, &sec_fac_attr_group);
+	dev_set_drvdata(data->fac_dev, NULL);
+#ifdef CONFIG_SEC_SYSFS
+	sec_device_destroy(data->fac_dev->devt);
+#else
+	device_destroy(sec_class, devt);
+#endif
+#ifdef USE_SEC_CMD_QUEUE
+	mutex_lock(&data->fifo_lock);
+	while (kfifo_len(&data->cmd_queue)) {
+		ret = kfifo_out(&data->cmd_queue, &cmd, sizeof(struct command));
+		if (!ret) {
+			pr_err("%s %s: kfifo_out failed, it seems empty, ret=%d\n",
+			       SECLOG, __func__, ret);
+		}
+		pr_info("%s %s: remove pending commands: %s",
+			SECLOG, __func__, cmd.cmd);
+	}
+	mutex_unlock(&data->fifo_lock);
+	mutex_destroy(&data->fifo_lock);
+	kfifo_free(&data->cmd_queue);
+#endif
+	list_del(&data->cmd_list_head);
+}
+
+MODULE_DESCRIPTION("Samsung factory command");
+MODULE_LICENSE("GPL");
+
+
diff --git a/sec_cmd.h b/sec_cmd.h
new file mode 100644
index 0000000..1a75c49
--- /dev/null
+++ b/sec_cmd.h
@@ -0,0 +1,164 @@
+
+#ifndef _SEC_CMD_H_
+#define _SEC_CMD_H_
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/device.h>
+#include <linux/workqueue.h>
+#include <linux/stat.h>
+#include <linux/err.h>
+#include <linux/input.h>
+#ifdef CONFIG_SEC_SYSFS
+#include <linux/sec_sysfs.h>
+#endif
+
+#ifndef CONFIG_SEC_FACTORY
+#include <linux/kfifo.h>
+#endif
+
+#ifndef CONFIG_SEC_SYSFS
+extern struct class *sec_class;
+#endif
+
+#define SEC_CLASS_DEVT_TSP		10
+#define SEC_CLASS_DEVT_TKEY		11
+#define SEC_CLASS_DEVT_WACOM		12
+
+#define SEC_CLASS_DEV_NAME_TSP		"tsp"
+#define SEC_CLASS_DEV_NAME_TKEY		"sec_touchkey"
+#define SEC_CLASS_DEV_NAME_WACOM	"sec_epen"
+
+#define SEC_CMD(name, func)		.cmd_name = name, .cmd_func = func
+
+#define SEC_CMD_BUF_SIZE		(4096 - 1)
+#define SEC_CMD_STR_LEN			256
+#define SEC_CMD_RESULT_STR_LEN		(4096 - 1)
+#define SEC_CMD_PARAM_NUM		8
+
+struct sec_cmd {
+	struct list_head	list;
+	const char		*cmd_name;
+	void			(*cmd_func)(void *device_data);
+};
+
+enum SEC_CMD_STATUS {
+	SEC_CMD_STATUS_WAITING = 0,
+	SEC_CMD_STATUS_RUNNING,		// = 1
+	SEC_CMD_STATUS_OK,		// = 2
+	SEC_CMD_STATUS_FAIL,		// = 3
+	SEC_CMD_STATUS_NOT_APPLICABLE,	// = 4
+};
+
+#ifdef USE_SEC_CMD_QUEUE
+#define SEC_CMD_MAX_QUEUE	10
+
+struct command {
+	char	cmd[SEC_CMD_STR_LEN];
+};
+#endif
+
+struct sec_cmd_data {
+	struct device		*fac_dev;
+	struct list_head	cmd_list_head;
+	u8			cmd_state;
+	char			cmd[SEC_CMD_STR_LEN];
+	int			cmd_param[SEC_CMD_PARAM_NUM];
+	char			cmd_result[SEC_CMD_RESULT_STR_LEN];
+	char			cmd_result_2[SEC_CMD_RESULT_STR_LEN];
+	int			cmd_buffer_size;
+	atomic_t		cmd_is_running;
+#ifdef USE_SEC_CMD_QUEUE
+	struct kfifo		cmd_queue;
+	struct mutex		fifo_lock;
+#endif
+};
+
+extern void sec_cmd_set_cmd_exit(struct sec_cmd_data *data);
+extern void sec_cmd_set_default_result(struct sec_cmd_data *data);
+extern void sec_cmd_set_cmd_result(struct sec_cmd_data *data, char *buff,
+				   int len);
+extern void sec_cmd_set_cmd_result_2(struct sec_cmd_data *data, char *buff,
+				   int len);
+extern int sec_cmd_init(struct sec_cmd_data *data,
+				struct sec_cmd *cmds, int len, int devt);
+extern void sec_cmd_exit(struct sec_cmd_data *data, int devt);
+
+/*
+ * sec Log
+ */
+#define SECLOG			"[sec_input]"
+#define INPUT_LOG_BUF_SIZE	512
+
+#ifdef CONFIG_SEC_DEBUG_TSP_LOG
+#include <linux/sec_debug.h>
+
+#define input_dbg(mode, dev, fmt, ...)					       \
+({									       \
+	static char input_log_buf[INPUT_LOG_BUF_SIZE];			       \
+	snprintf(input_log_buf, sizeof(input_log_buf), "%s %s", SECLOG, fmt);  \
+	dev_dbg(dev, input_log_buf, ## __VA_ARGS__);			       \
+	if (mode) {							       \
+		if (dev)						       \
+			snprintf(input_log_buf, sizeof(input_log_buf), "%s %s",\
+					dev_driver_string(dev), dev_name(dev));\
+		else							       \
+			snprintf(input_log_buf, sizeof(input_log_buf), "NULL");\
+		sec_debug_tsp_log_msg(input_log_buf, fmt, ## __VA_ARGS__);     \
+	}								       \
+})
+#define input_info(mode, dev, fmt, ...)					       \
+({									       \
+	static char input_log_buf[INPUT_LOG_BUF_SIZE];			       \
+	snprintf(input_log_buf, sizeof(input_log_buf), "%s %s", SECLOG, fmt);  \
+	dev_info(dev, input_log_buf, ## __VA_ARGS__);			       \
+	if (mode) {							       \
+		if (dev)						       \
+			snprintf(input_log_buf, sizeof(input_log_buf), "%s %s",\
+					dev_driver_string(dev), dev_name(dev));\
+		else							       \
+			snprintf(input_log_buf, sizeof(input_log_buf), "NULL");\
+		sec_debug_tsp_log_msg(input_log_buf, fmt, ## __VA_ARGS__);     \
+	}								       \
+})
+#define input_err(mode, dev, fmt, ...)					       \
+({									       \
+	static char input_log_buf[INPUT_LOG_BUF_SIZE];			       \
+	snprintf(input_log_buf, sizeof(input_log_buf), "%s %s", SECLOG, fmt);  \
+	dev_err(dev, input_log_buf, ## __VA_ARGS__);			       \
+	if (mode) {							       \
+		if (dev)						       \
+			snprintf(input_log_buf, sizeof(input_log_buf), "%s %s",\
+					dev_driver_string(dev), dev_name(dev));\
+		else							       \
+			snprintf(input_log_buf, sizeof(input_log_buf), "NULL");\
+		sec_debug_tsp_log_msg(input_log_buf, fmt, ## __VA_ARGS__);     \
+	}								       \
+})
+#define input_log_fix() {}
+#else
+#define input_dbg(mode, dev, fmt, ...)					       \
+({									       \
+	static char input_log_buf[INPUT_LOG_BUF_SIZE];			       \
+	snprintf(input_log_buf, sizeof(input_log_buf), "%s %s", SECLOG, fmt);  \
+	dev_dbg(dev, input_log_buf, ## __VA_ARGS__);			       \
+})
+#define input_info(mode, dev, fmt, ...)					       \
+({									       \
+	static char input_log_buf[INPUT_LOG_BUF_SIZE];			       \
+	snprintf(input_log_buf, sizeof(input_log_buf), "%s %s", SECLOG, fmt);  \
+	dev_info(dev, input_log_buf, ## __VA_ARGS__);			       \
+})
+#define input_err(mode, dev, fmt, ...)					       \
+({									       \
+	static char input_log_buf[INPUT_LOG_BUF_SIZE];			       \
+	snprintf(input_log_buf, sizeof(input_log_buf), "%s %s", SECLOG, fmt);  \
+	dev_err(dev, input_log_buf, ## __VA_ARGS__);			       \
+})
+#define input_log_fix() {}
+#endif
+
+#endif /* _SEC_CMD_H_ */
+
+
diff --git a/sec_ts.c b/sec_ts.c
new file mode 100644
index 0000000..de1870b
--- /dev/null
+++ b/sec_ts.c
@@ -0,0 +1,6410 @@
+/* drivers/input/touchscreen/sec_ts.c
+ *
+ * Copyright (C) 2011 Samsung Electronics Co., Ltd.
+ * http://www.samsungsemi.com/
+ *
+ * Core file for Samsung TSC driver
+ *
+ * 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.
+ */
+
+struct sec_ts_data *tsp_info;
+
+#include "sec_ts.h"
+#include <samsung/exynos_drm_connector.h>
+
+#if IS_ENABLED(CONFIG_GS_DRM_PANEL_UNIFIED)
+#include <gs_drm/gs_drm_connector.h>
+#endif
+
+/* init the kfifo for health check. */
+#define SEC_TS_HC_KFIFO_LEN 4 /* must be power of 2. */
+DEFINE_KFIFO(hc_fifo, struct sec_ts_health_check, SEC_TS_HC_KFIFO_LEN);
+
+/* init the kfifo for debug used. */
+#define SEC_TS_DEBUG_KFIFO_LEN 4 /* must be power of 2. */
+DEFINE_KFIFO(debug_fifo, struct sec_ts_coordinate, SEC_TS_DEBUG_KFIFO_LEN);
+static struct sec_ts_coordinate last_coord[SEC_TS_DEBUG_KFIFO_LEN];
+
+/* Switch GPIO values */
+#define SEC_SWITCH_GPIO_VALUE_SLPI_MASTER	1
+#define SEC_SWITCH_GPIO_VALUE_AP_MASTER		0
+
+struct sec_ts_data *ts_dup;
+
+#ifndef CONFIG_SEC_SYSFS
+/* Declare extern sec_class */
+struct class *sec_class;
+#endif
+
+#ifdef USE_POWER_RESET_WORK
+static void sec_ts_reset_work(struct work_struct *work);
+#endif
+static void sec_ts_fw_update_work(struct work_struct *work);
+static void sec_ts_suspend_work(struct work_struct *work);
+static void sec_ts_resume_work(struct work_struct *work);
+#ifdef USE_CHARGER_WORK
+static void sec_ts_charger_work(struct work_struct *work);
+#endif
+
+#ifdef USE_OPEN_CLOSE
+static int sec_ts_input_open(struct input_dev *dev);
+static void sec_ts_input_close(struct input_dev *dev);
+#endif
+
+static int register_panel_bridge(struct sec_ts_data *ts);
+static void unregister_panel_bridge(struct drm_bridge *bridge);
+
+int sec_ts_read_information(struct sec_ts_data *ts);
+
+#ifndef I2C_INTERFACE
+u32 sec_ts_spi_delay(u8 reg, u32 data_len)
+{
+	u32 delay_us = 100;
+
+	switch (reg) {
+	case SEC_TS_READ_TOUCH_RAWDATA:
+		delay_us = 500;
+		break;
+#if IS_ENABLED(CONFIG_TOUCHSCREEN_HEATMAP)
+	case SEC_TS_CMD_HEATMAP_READ:
+		delay_us = 500;
+		break;
+#endif
+	case SEC_TS_CMD_CUSTOMLIB_READ_PARAM:
+		delay_us = min(120 + (data_len >> 2), (u32) 500);
+		break;
+	case SEC_TS_READ_ALL_EVENT:
+		delay_us = 550;
+		break;
+	case SEC_TS_READ_CSRAM_RTDP_DATA:
+		delay_us = 550;
+		break;
+	case SEC_TS_CAAT_READ_STORED_DATA:
+		delay_us = 550;
+		break;
+	case SEC_TS_CMD_FLASH_READ_DATA:
+		delay_us = 2000;
+		break;
+	case SEC_TS_READ_FIRMWARE_INTEGRITY:
+		delay_us = 20*1000;
+		break;
+	case SEC_TS_READ_SELFTEST_RESULT:
+		delay_us = 4000;
+		break;
+	}
+
+	usleep_range(delay_us, delay_us + 1);
+
+	return delay_us;
+}
+
+int sec_ts_spi_post_delay(u8 reg)
+{
+	switch (reg) {
+	case SEC_TS_READ_TOUCH_RAWDATA:
+	case SEC_TS_CMD_FLASH_READ_DATA:
+	case SEC_TS_READ_SELFTEST_RESULT:
+		return 500;
+	default: return 0;
+	}
+}
+#endif
+
+int sec_ts_write(struct sec_ts_data *ts, u8 reg, u8 *data, int len)
+{
+	u8 *buf;
+	int ret;
+	unsigned char retry;
+#ifdef I2C_INTERFACE
+	struct i2c_msg msg;
+#else
+	struct spi_message msg;
+	struct spi_transfer transfer[1] = { { 0 } };
+	unsigned int i;
+	unsigned int spi_len = 0;
+	unsigned char checksum = 0x0;
+#endif
+
+	if (ts->power_status == SEC_TS_STATE_POWER_OFF) {
+		input_err(true, &ts->client->dev,
+			"%s: POWER_STATUS: OFF\n", __func__);
+		goto err;
+	}
+
+#ifdef I2C_INTERFACE
+	if (len + 1 > sizeof(ts->io_write_buf)) {
+		input_err(true, &ts->client->dev,
+			"%s: len is larger than buffer size\n", __func__);
+		return -EINVAL;
+	}
+#else
+	/* add 3 zero stuffing tx bytes at last */
+	if (SEC_TS_SPI_HEADER_SIZE + 1 + len + SEC_TS_SPI_CHECKSUM_SIZE + 3 >
+		sizeof(ts->io_write_buf)) {
+		input_err(true, &ts->client->dev,
+			"%s: len is larger than buffer size\n", __func__);
+		return -EINVAL;
+	}
+#endif
+
+	mutex_lock(&ts->io_mutex);
+
+	buf = ts->io_write_buf;
+#ifdef I2C_INTERFACE
+	buf[0] = reg;
+	memcpy(buf + 1, data, len);
+
+	msg.addr = ts->client->addr;
+	msg.flags = 0;
+	msg.len = len + 1;
+	msg.buf = buf;
+#else
+
+	buf[0] = SEC_TS_SPI_SYNC_CODE;
+	buf[1] = ((len + 1) >> 8) & 0xFF;
+	buf[2] = (len + 1) & 0xFF;
+	buf[3] = 0x00;
+	buf[4] = 0x00;
+	buf[5] = reg;
+	memcpy(buf + SEC_TS_SPI_HEADER_SIZE + 1, data, len);
+
+	spi_len = SEC_TS_SPI_HEADER_SIZE + 1 + len;
+	// spi_len = SPI header size(5)+register(1)+data size(len)
+	for (i = 0; i < spi_len ; i++)
+		checksum += buf[i];
+	buf[spi_len++] = checksum;
+	// spi_len += checksum(1)
+
+	spi_message_init(&msg);
+
+	/* add 3 zero stuffing tx bytes at last */
+	memset(ts->io_write_buf + spi_len, 0x00, 3);
+	/* spi transfer size should be multiple of 4
+	 **/
+	spi_len = (spi_len + 3) & ~3;
+	transfer[0].len = spi_len;
+	transfer[0].tx_buf = buf;
+	transfer[0].rx_buf = NULL;
+	spi_message_add_tail(&transfer[0], &msg);
+
+#ifdef SEC_TS_DEBUG_IO
+	input_info(true, &ts->client->dev, "%s: ", __func__);
+//	for (i = 0; i < SEC_TS_SPI_HEADER_SIZE + 1 + len + 1; i++)
+	for (i = 0; i < 8; i++)
+		input_info(true, &ts->client->dev, "%X ", buf[i]);
+	input_info(true, &ts->client->dev, "\n");
+#endif
+
+#endif
+
+	for (retry = 0; retry < SEC_TS_IO_RETRY_CNT; retry++) {
+#ifdef I2C_INTERFACE
+		if ((ret = i2c_transfer(ts->client->adapter, &msg, 1)) == 1)
+			break;
+#else
+		if ((ret = spi_sync(ts->client, &msg)) == 0)
+			break;
+#endif
+
+		if (ts->power_status == SEC_TS_STATE_POWER_OFF) {
+			input_err(true, &ts->client->dev,
+				  "%s: POWER_STATUS: OFF, retry: %d\n",
+				  __func__, retry);
+			mutex_unlock(&ts->io_mutex);
+			goto err;
+		}
+
+		usleep_range(1 * 1000, 1 * 1000);
+
+		if (retry > 1) {
+			input_err(true, &ts->client->dev,
+				  "%s: retry %d\n", __func__, retry + 1);
+			ts->comm_err_count++;
+		}
+	}
+
+	mutex_unlock(&ts->io_mutex);
+
+	if (retry == SEC_TS_IO_RETRY_CNT) {
+		input_err(true, &ts->client->dev,
+			  "%s: write over retry limit\n", __func__);
+		ret = -EIO;
+#ifdef USE_POR_AFTER_I2C_RETRY
+		if (ts->probe_done && !ts->reset_is_on_going)
+			schedule_delayed_work(&ts->reset_work,
+				msecs_to_jiffies(TOUCH_RESET_DWORK_TIME));
+#endif
+	}
+
+#ifdef I2C_INTERFACE
+	if (ret == 1)
+#else
+	if (ret == 0)
+#endif
+		return 0;
+err:
+	return -EIO;
+}
+
+static int sec_ts_read_internal(struct sec_ts_data *ts, u8 reg,
+			     u8 *data, int len, bool dma_safe)
+{
+	u8 *buf;
+	int ret;
+	unsigned char retry;
+#ifdef I2C_INTERFASCE
+	struct i2c_msg msg[2];
+#else
+	struct spi_message msg;
+	struct spi_transfer transfer[1] = { { 0 } };
+	u32 spi_delay_us = 0;
+	unsigned int i;
+	unsigned int spi_write_len = 0, spi_read_len = 0;
+	unsigned char write_checksum = 0x0, read_checksum = 0x0;
+	int copy_size = 0, copy_cur = 0;
+#endif
+	int remain = len;
+
+	if (ts->power_status == SEC_TS_STATE_POWER_OFF) {
+		input_err(true, &ts->client->dev,
+			"%s: POWER_STATUS: OFF\n", __func__);
+		goto err;
+	}
+
+#ifndef I2C_INTERFACE
+	/* add 3 zero stuffing tx bytes at last */
+	if (SEC_TS_SPI_HEADER_SIZE + 1 + SEC_TS_SPI_CHECKSUM_SIZE + 3 >
+		sizeof(ts->io_write_buf)) {
+		input_err(true, &ts->client->dev,
+			"%s: len is larger than buffer size\n", __func__);
+		return -EINVAL;
+	}
+#endif
+
+	if (len > sizeof(ts->io_read_buf) && dma_safe == false) {
+		input_err(true, &ts->client->dev,
+			"%s: len %d over pre-allocated size %d\n",
+			__func__, len, IO_PREALLOC_READ_BUF_SZ);
+		return -ENOSPC;
+	}
+
+	mutex_lock(&ts->io_mutex);
+
+	buf = ts->io_write_buf;
+#ifdef I2C_INTERFACE
+	buf[0] = reg;
+
+	msg[0].addr = ts->client->addr;
+	msg[0].flags = 0;
+	msg[0].len = 1;
+	msg[0].buf = buf;
+
+	msg[1].addr = ts->client->addr;
+	msg[1].flags = I2C_M_RD;
+	msg[1].len = len;
+	if (dma_safe == false)
+		msg[1].buf = ts->io_read_buf;
+	else
+		msg[1].buf = data;
+#else
+
+	buf[0] = SEC_TS_SPI_SYNC_CODE;
+	buf[1] = 0x00;
+	buf[2] = 0x01;
+	buf[3] = (len >> 8) & 0xFF;
+	buf[4] = len & 0xFF;
+	buf[5] = reg;
+
+	spi_write_len = SEC_TS_SPI_HEADER_SIZE + 1;
+	for (i = 0; i < spi_write_len; i++)
+		write_checksum += buf[i];
+	buf[spi_write_len] = write_checksum;
+	spi_write_len += SEC_TS_SPI_CHECKSUM_SIZE;
+	/* add 3 zero stuffing tx bytes at last */
+	memset(ts->io_write_buf + spi_write_len, 0x00, 3);
+	spi_write_len = (spi_write_len + 3) & ~3;
+
+	spi_read_len = len +
+		SEC_TS_SPI_READ_HEADER_SIZE + SEC_TS_SPI_CHECKSUM_SIZE;
+	spi_read_len = (spi_read_len + 3) & ~3;
+#endif
+	if (len <= ts->io_burstmax) {
+#ifdef I2C_INTERFACE
+		for (retry = 0; retry < SEC_TS_IO_RETRY_CNT; retry++) {
+			ret = i2c_transfer(ts->client->adapter, msg, 2);
+			if (ret == 2)
+				break;
+
+			usleep_range(1 * 1000, 1 * 1000);
+			if (ts->power_status == SEC_TS_STATE_POWER_OFF) {
+				input_err(true, &ts->client->dev,
+					  "%s: POWER_STATUS: OFF, retry: %d\n",
+					  __func__, retry);
+				mutex_unlock(&ts->io_mutex);
+				goto err;
+			}
+
+			if (retry > 1) {
+				input_err(true, &ts->client->dev,
+					"%s: retry %d\n", __func__, retry + 1);
+				ts->comm_err_count++;
+			}
+		}
+		if (ret == 2 && dma_safe == false)
+			memcpy(data,
+			       ts->io_read_buf[SEC_TS_SPI_READ_HEADER_SIZE],
+			       len);
+#else
+		for (retry = 0; retry < SEC_TS_IO_RETRY_CNT; retry++) {
+			spi_message_init(&msg);
+			// spi transfer size should be multiple of 4
+			transfer[0].len = spi_write_len;
+			transfer[0].tx_buf = buf;
+			transfer[0].rx_buf = NULL;
+			spi_message_add_tail(&transfer[0], &msg);
+
+			ret = spi_sync(ts->client, &msg);
+#ifdef SEC_TS_DEBUG_IO
+			input_info(true, &ts->client->dev,
+				"%s: spi write buf %X %X %X %X %X %X %X\n",
+				__func__, buf[0], buf[1], buf[2],
+				buf[3], buf[4], buf[5], buf[6]);
+#endif
+			// write fail
+			if (ret != 0) {
+				ret = -EIO;
+
+				input_err(true, &ts->client->dev,
+					"%s: spi write retry %d\n",
+					__func__, retry + 1);
+				ts->comm_err_count++;
+
+				usleep_range(1 * 1000, 1 * 1000);
+				if (ts->power_status ==
+					SEC_TS_STATE_POWER_OFF) {
+					input_err(true, &ts->client->dev,
+						"%s: POWER_STATUS: OFF, retry: %d\n",
+						__func__, retry);
+					mutex_unlock(&ts->io_mutex);
+					goto err;
+				}
+
+				if (retry == SEC_TS_IO_RETRY_CNT - 1) {
+					input_err(true, &ts->client->dev,
+						"%s: write reg retry over retry limit, skip read\n",
+						__func__);
+					goto skip_spi_read;
+				}
+
+				continue;
+			}
+
+			spi_delay_us = sec_ts_spi_delay(reg, len);
+
+			// read sequence start
+			spi_message_init(&msg);
+			transfer[0].len = spi_read_len;
+			transfer[0].tx_buf = NULL;
+			transfer[0].rx_buf = ts->io_read_buf;
+			spi_message_add_tail(&transfer[0], &msg);
+			ret = spi_sync(ts->client, &msg);
+
+			for (i = 0, read_checksum = 0x0;
+				i < (SEC_TS_SPI_READ_HEADER_SIZE + len);
+				i++)
+				read_checksum += ts->io_read_buf[i];
+
+#ifdef SEC_TS_DEBUG_IO
+			input_info(true, &ts->client->dev, "%s: ", __func__);
+//			for (i = 0; i < spi_read_len; i++)
+			for (i = 0; i < 8; i++)
+				input_info(true, &ts->client->dev,
+					"%X ",
+					ts->io_read_buf[i]);
+			input_info(true, &ts->client->dev,
+				"\n%s: checksum = %X",
+				__func__, read_checksum);
+#endif
+			// read fail
+			if (ret != 0 ||
+				ts->io_read_buf[0] != SEC_TS_SPI_SYNC_CODE ||
+				reg != ts->io_read_buf[5] ||
+				// ts->io_read_buf[6] != SEC_TS_SPI_CMD_OK ||
+				read_checksum !=
+					ts->io_read_buf[
+						SEC_TS_SPI_READ_HEADER_SIZE +
+					len]) {
+
+				ret = -EIO;
+
+				/*
+				 * For LP idle state from AOD to normal screen-on,
+				 * T-IC needs one SPI cmds to wake-up.
+				 * Therefore, change the log level to warning
+				 * for this intended behavir.
+				 */
+				if (!completion_done(&ts->bus_resumed) &&
+					reg == SEC_TS_CMD_CHG_SYSMODE) {
+					dev_warn(&ts->client->dev,
+						"%s: wake-up touch(#%d) by 0x%02X cmd delay_us(%d)\n",
+						__func__, retry + 1, reg, spi_delay_us);
+				} else {
+					input_err(true, &ts->client->dev,
+						"%s: retry %d for 0x%02X size(%d) delay_us(%d)\n",
+						__func__, retry + 1, reg, len, spi_delay_us);
+						ts->comm_err_count++;
+				}
+
+				usleep_range(1 * 1000, 1 * 1000);
+				if (ts->power_status ==
+					SEC_TS_STATE_POWER_OFF) {
+					input_err(true, &ts->client->dev,
+						"%s: POWER_STATUS: OFF, retry: %d\n",
+						__func__, retry);
+					mutex_unlock(&ts->io_mutex);
+					goto err;
+				}
+				continue;
+			} else
+				break;
+		}
+		if (ret == 0)
+			memcpy(data, ts->io_read_buf +
+			       SEC_TS_SPI_READ_HEADER_SIZE, len);
+
+		usleep_range(sec_ts_spi_post_delay(reg),
+			     sec_ts_spi_post_delay(reg) + 1);
+
+#endif //I2C_INTERFACE
+	} else {
+		/*
+		 * read buffer is 256 byte. do not support long buffer over
+		 * than 256. So, try to separate reading data about 256 bytes.
+		 **/
+#ifdef I2C_INTERFACE
+		for (retry = 0; retry < SEC_TS_IO_RETRY_CNT; retry++) {
+			ret = i2c_transfer(ts->client->adapter, msg, 1);
+			if (ret == 1)
+				break;
+
+			usleep_range(1 * 1000, 1 * 1000);
+			if (ts->power_status == SEC_TS_STATE_POWER_OFF) {
+				input_err(true, &ts->client->dev,
+					"%s: POWER_STATUS: OFF, retry: %d\n",
+					__func__, retry);
+				mutex_unlock(&ts->io_mutex);
+				goto err;
+			}
+
+			if (retry > 1) {
+				input_err(true, &ts->client->dev,
+					"%s: retry %d\n",
+					__func__, retry + 1);
+				ts->comm_err_count++;
+			}
+		}
+
+		do {
+			if (remain > ts->io_burstmax)
+				msg[1].len = ts->io_burstmax;
+			else
+				msg[1].len = remain;
+
+			remain -= ts->io_burstmax;
+
+			for (retry = 0; retry < SEC_TS_IO_RETRY_CNT; retry++) {
+				ret = i2c_transfer(ts->client->adapter,
+						   &msg[1], 1);
+				if (ret == 1)
+					break;
+				usleep_range(1 * 1000, 1 * 1000);
+				if (ts->power_status ==
+					SEC_TS_STATE_POWER_OFF) {
+					input_err(true, &ts->client->dev,
+						"%s: POWER_STATUS: OFF, retry: %d\n",
+						__func__, retry);
+					mutex_unlock(&ts->io_mutex);
+					goto err;
+				}
+
+				if (retry > 1) {
+					input_err(true, &ts->client->dev,
+						"%s: retry %d\n",
+						__func__, retry + 1);
+					ts->comm_err_count++;
+				}
+			}
+
+			msg[1].buf += msg[1].len;
+
+		} while (remain > 0);
+
+		if (ret == 1 && dma_safe == false)
+			memcpy(data, ts->io_read_buf, len);
+#else
+		for (retry = 0; retry < SEC_TS_IO_RETRY_CNT; retry++) {
+			spi_message_init(&msg);
+			// spi transfer size should be multiple of 4
+			transfer[0].len = spi_write_len;
+			transfer[0].tx_buf = buf;
+			transfer[0].rx_buf = NULL;
+			spi_message_add_tail(&transfer[0], &msg);
+
+			ret = spi_sync(ts->client, &msg);
+
+			// write fail
+			if (ret != 0) {
+				ret = -EIO;
+
+				input_err(true, &ts->client->dev,
+					"%s: spi write retry %d\n",
+					__func__, retry + 1);
+				ts->comm_err_count++;
+
+				usleep_range(1 * 1000, 1 * 1000);
+
+				if (ts->power_status ==
+					SEC_TS_STATE_POWER_OFF) {
+					input_err(true, &ts->client->dev,
+						"%s: POWER_STATUS: OFF, retry: %d\n",
+						__func__, retry);
+					mutex_unlock(&ts->io_mutex);
+					goto err;
+				}
+
+				if (retry == SEC_TS_IO_RETRY_CNT - 1) {
+					input_err(true, &ts->client->dev,
+						"%s: write reg retry over retry limit, skip read\n",
+						__func__);
+					goto skip_spi_read;
+				}
+
+				continue;
+			}
+
+			sec_ts_spi_delay(reg, len);
+
+			copy_size = 0;
+			remain = spi_read_len;
+			do {
+				if (remain > ts->io_burstmax)
+					copy_cur = ts->io_burstmax;
+				else
+					copy_cur = remain;
+
+				spi_message_init(&msg);
+
+				transfer[0].len = copy_cur;
+				transfer[0].tx_buf = NULL;
+				transfer[0].rx_buf =
+					&ts->io_read_buf[copy_size];
+				// CS needs to stay low until read seq. is done
+				transfer[0].cs_change =
+					(remain > ts->io_burstmax) ? 1 : 0;
+
+				spi_message_add_tail(&transfer[0], &msg);
+
+				copy_size += copy_cur;
+				remain -= copy_cur;
+
+				ret = spi_sync(ts->client, &msg);
+#ifdef SEC_TS_DEBUG_IO
+				input_info(true, &ts->client->dev,
+					"%s: ", __func__);
+				for (i = 0; i < 8; i++)
+					input_info(true,
+						   &ts->client->dev, "%X ",
+						   ts->io_read_buf[i]);
+				input_info(true, &ts->client->dev,
+					"\n%s: checksum = %X",
+					__func__, read_checksum);
+#endif
+
+				if (ret != 0) {
+					ret = -EIO;
+
+					input_err(true, &ts->client->dev,
+						"%s: retry %d\n",
+						__func__, retry + 1);
+					ts->comm_err_count++;
+
+					usleep_range(1 * 1000, 1 * 1000);
+					if (ts->power_status
+						== SEC_TS_STATE_POWER_OFF) {
+						input_err(true,
+							&ts->client->dev,
+							"%s: POWER_STATUS: OFF, retry: %d\n",
+							__func__, retry);
+						mutex_unlock(&ts->io_mutex);
+						goto err;
+					}
+					break;
+				}
+			} while (remain > 0);
+			if (ret != 0) { // read fail, retry
+				ret = -EIO;
+				continue;
+			}
+
+			for (i = 0, read_checksum = 0x0;
+				i < SEC_TS_SPI_READ_HEADER_SIZE + len; i++)
+				read_checksum += ts->io_read_buf[i];
+			//read success
+			if (ts->io_read_buf[0] == SEC_TS_SPI_SYNC_CODE &&
+				// ts->io_read_buf[6] == SEC_TS_SPI_CMD_OK &&
+				reg == ts->io_read_buf[5] &&
+				read_checksum ==
+				ts->io_read_buf[SEC_TS_SPI_READ_HEADER_SIZE +
+				len])
+				break;
+			//read data fail
+			else if (ts->io_read_buf[6]
+				 == SEC_TS_SPI_CMD_UNKNOWN ||
+				 ts->io_read_buf[6]
+				 == SEC_TS_SPI_CMD_BAD_PARAM) {
+				input_info(true, &ts->client->dev,
+					"%s: CMD_NG cmd(M) = %X, cmd(S) = %X, cmd_result = %X\n",
+					__func__, reg, ts->io_read_buf[5],
+					ts->io_read_buf[6]);
+				ret = -EIO;
+				continue;
+			} else {
+				input_info(true, &ts->client->dev,
+					"%s: spi fail, ret %d, sync code %X, reg(M) %X, reg(S) %X, cmd_result %X, chksum(M) %X, chksum(S) %X\n",
+					__func__, ret, ts->io_read_buf[0],
+					reg, ts->io_read_buf[5],
+					ts->io_read_buf[6], read_checksum,
+					ts->io_read_buf[
+						SEC_TS_SPI_READ_HEADER_SIZE +
+					len]);
+				ret = -EIO;
+				continue;
+			}
+		}
+		if (ret == 0)
+			memcpy(data, ts->io_read_buf +
+				SEC_TS_SPI_READ_HEADER_SIZE, len);
+
+		usleep_range(sec_ts_spi_post_delay(reg),
+			     sec_ts_spi_post_delay(reg) + 1);
+#endif
+	}
+skip_spi_read:
+	mutex_unlock(&ts->io_mutex);
+
+	if (retry == SEC_TS_IO_RETRY_CNT) {
+		input_err(true, &ts->client->dev,
+			"%s: read reg(%#x) over retry limit, comm_err_count %d, io_err_count %d\n",
+			__func__, reg, ts->comm_err_count, ts->io_err_count);
+		ret = -EIO;
+		ts->io_err_count++;
+#ifdef USE_POR_AFTER_I2C_RETRY
+		if (ts->probe_done && !ts->reset_is_on_going)
+			schedule_delayed_work(&ts->reset_work,
+				msecs_to_jiffies(TOUCH_RESET_DWORK_TIME));
+#endif
+
+	} else
+		ts->io_err_count = 0;
+
+	/*
+	 * Do hw reset if continuously failed over SEC_TS_IO_RESET_CNT times
+	 * except for FW update process.
+	 */
+	if (ts->io_err_count >= SEC_TS_IO_RESET_CNT &&
+	    (ts->bus_refmask & SEC_TS_BUS_REF_FW_UPDATE) == 0) {
+		ts->hw_reset_count++;
+		ts->io_err_count = 0;
+		sec_ts_system_reset(ts, RESET_MODE_HW, false, true);
+	}
+
+	return ret;
+
+err:
+	return -EIO;
+}
+
+static int sec_ts_write_burst_internal(struct sec_ts_data *ts,
+					   u8 *data, int len, bool dma_safe)
+{
+	int ret;
+	int retry;
+#ifndef I2C_INTERFACE
+	struct spi_message msg;
+	struct spi_transfer transfer[1] = { { 0 } };
+	unsigned int i;
+	unsigned int spi_len = 0;
+	unsigned char checksum = 0x0;
+#endif
+
+#ifdef I2C_INTERFACE
+	if (len > sizeof(ts->io_write_buf) && dma_safe == false) {
+		input_err(true, &ts->client->dev,
+			"%s: len %d over pre-allocated size %d\n",
+			__func__, len, sizeof(ts->io_write_buf));
+		return -ENOSPC;
+	}
+#else
+	/* add 3 zero stuffing tx bytes at last */
+	if (SEC_TS_SPI_HEADER_SIZE + len + SEC_TS_SPI_CHECKSUM_SIZE + 3 >
+		sizeof(ts->io_write_buf)) {
+		input_err(true, &ts->client->dev,
+			"%s: len is larger than buffer size\n", __func__);
+		return -EINVAL;
+	}
+#endif
+
+	mutex_lock(&ts->io_mutex);
+#ifdef I2C_INTERFACE
+	if (dma_safe == false) {
+		memcpy(ts->io_write_buf, data, len);
+		data = ts->io_write_buf;
+	}
+#else
+
+	ts->io_write_buf[0] = SEC_TS_SPI_SYNC_CODE;
+	ts->io_write_buf[1] = (len >> 8) & 0xFF;
+	ts->io_write_buf[2] = len & 0xFF;
+	ts->io_write_buf[3] = 0x0;
+	ts->io_write_buf[4] = 0x0;
+
+	memcpy(ts->io_write_buf + SEC_TS_SPI_HEADER_SIZE, data, len);
+
+
+	spi_len = SEC_TS_SPI_HEADER_SIZE + len;
+	for (i = 0; i < spi_len; i++)
+		checksum += ts->io_write_buf[i];
+
+	ts->io_write_buf[spi_len] = checksum;
+	spi_len += SEC_TS_SPI_CHECKSUM_SIZE;
+
+	spi_message_init(&msg);
+
+	/* add 3 zero stuffing tx bytes at last */
+	memset(ts->io_write_buf + spi_len, 0x00, 3);
+	spi_len = (spi_len + 3) & ~3;
+	transfer[0].len = spi_len;
+	transfer[0].tx_buf = ts->io_write_buf;
+	transfer[0].rx_buf = NULL;
+	spi_message_add_tail(&transfer[0], &msg);
+
+#ifdef SEC_TS_DEBUG_IO
+	input_info(true, &ts->client->dev, "%s:\n", __func__);
+	for (i = 0; i < spi_len; i++)
+		input_info(true, &ts->client->dev, "%X ", ts->io_write_buf[i]);
+	input_info(true, &ts->client->dev, "\n");
+#endif
+
+#endif
+
+	for (retry = 0; retry < SEC_TS_IO_RETRY_CNT; retry++) {
+#ifdef I2C_INTERFACE
+		if ((ret = i2c_master_send(ts->client, data, len)) == len)
+			break;
+#else
+		if ((ret = spi_sync(ts->client, &msg)) == 0)
+			break;
+#endif
+
+		usleep_range(1 * 1000, 1 * 1000);
+
+		if (retry > 1) {
+			input_err(true, &ts->client->dev,
+				  "%s: retry %d\n", __func__, retry + 1);
+			ts->comm_err_count++;
+		}
+	}
+
+	mutex_unlock(&ts->io_mutex);
+	if (retry == SEC_TS_IO_RETRY_CNT) {
+		input_err(true, &ts->client->dev,
+			  "%s: write over retry limit\n", __func__);
+		ret = -EIO;
+	}
+
+	return ret;
+}
+
+static int sec_ts_read_bulk_internal(struct sec_ts_data *ts,
+					 u8 *data, int len, bool dma_safe)
+{
+	int ret;
+	unsigned char retry;
+	int remain = len;
+#ifdef I2C_INTERFACE
+	struct i2c_msg msg;
+#else
+	struct spi_message msg;
+	struct spi_transfer transfer[1] = { { 0 } };
+	unsigned int i;
+	unsigned int spi_len = 0;
+	unsigned char checksum = 0x0;
+	int copy_size = 0, copy_cur = 0;
+	int retry_msg = 0;
+#endif
+
+	if (len > sizeof(ts->io_read_buf) && dma_safe == false) {
+		input_err(true, &ts->client->dev,
+			  "%s: len %d over pre-allocated size %d\n", __func__,
+			  len, sizeof(ts->io_read_buf));
+		return -ENOSPC;
+	}
+
+	mutex_lock(&ts->io_mutex);
+
+#ifdef I2C_INTERFACE
+	msg.addr = ts->client->addr;
+	msg.flags = I2C_M_RD;
+	msg.len = len;
+	if (dma_safe == false)
+		msg.buf = ts->io_read_buf;
+	else
+		msg.buf = data;
+
+	do {
+		if (remain > ts->io_burstmax)
+			msg.len = ts->io_burstmax;
+		else
+			msg.len = remain;
+
+		remain -= ts->io_burstmax;
+
+		for (retry = 0; retry < SEC_TS_IO_RETRY_CNT; retry++) {
+			ret = i2c_transfer(ts->client->adapter, &msg, 1);
+			if (ret == 1)
+				break;
+			usleep_range(1 * 1000, 1 * 1000);
+
+			if (retry > 1) {
+				input_err(true, &ts->client->dev,
+					  "%s: retry %d\n",
+					  __func__, retry + 1);
+				ts->comm_err_count++;
+			}
+		}
+
+		if (retry == SEC_TS_IO_RETRY_CNT) {
+			input_err(true, &ts->client->dev,
+				  "%s: read over retry limit\n", __func__);
+			ret = -EIO;
+			break;
+		}
+
+		msg.buf += msg.len;
+
+	} while (remain > 0);
+
+	if (ret == 1 && dma_safe == false)
+		memcpy(data, ts->io_read_buf, len);
+#else
+retry_message:
+	remain = spi_len = (SEC_TS_SPI_READ_HEADER_SIZE + len +
+			    SEC_TS_SPI_CHECKSUM_SIZE + 3) & ~3;
+	do {
+		if (remain > ts->io_burstmax)
+			copy_cur = ts->io_burstmax;
+		else
+			copy_cur = remain;
+
+		spi_message_init(&msg);
+		transfer[0].len = copy_cur;
+		transfer[0].tx_buf = NULL;
+		transfer[0].rx_buf = &ts->io_read_buf[copy_size];
+		/* CS needs to stay low until read seq. is done
+		 */
+		transfer[0].cs_change = (remain > ts->io_burstmax) ? 1 : 0;
+
+		spi_message_add_tail(&transfer[0], &msg);
+
+		copy_size += copy_cur;
+		remain -= copy_cur;
+
+		for (retry = 0; retry < SEC_TS_IO_RETRY_CNT; retry++) {
+			ret = spi_sync(ts->client, &msg);
+			if (ret == 0)
+				break;
+
+			usleep_range(1 * 1000, 1 * 1000);
+			if (ts->power_status == SEC_TS_STATE_POWER_OFF) {
+				input_err(true, &ts->client->dev,
+					  "%s: POWER_STATUS: OFF, retry: %d\n",
+					  __func__, retry);
+				mutex_unlock(&ts->io_mutex);
+				goto err;
+			}
+
+			if (retry > 1) {
+				input_err(true, &ts->client->dev,
+					"%s: retry %d\n", __func__, retry + 1);
+				ts->comm_err_count++;
+			}
+		}
+	} while (remain > 0);
+
+	for (i = 0, checksum = 0; i < SEC_TS_SPI_READ_HEADER_SIZE + len; i++)
+		checksum += ts->io_read_buf[i];
+
+	if (ret == 0 && ts->io_read_buf[0] == SEC_TS_SPI_SYNC_CODE &&
+		checksum == ts->io_read_buf[SEC_TS_SPI_READ_HEADER_SIZE + len])
+		memcpy(data, ts->io_read_buf + SEC_TS_SPI_READ_HEADER_SIZE,
+		       len);
+	else {
+		input_info(true, &ts->client->dev,
+			   "%s: spi fail, ret %d, sync code %X, reg(S) %X, chksum(M) %X, chksum(S) %X\n",
+			__func__, ret, ts->io_read_buf[0], ts->io_read_buf[5],
+			checksum,
+			ts->io_read_buf[SEC_TS_SPI_READ_HEADER_SIZE + len]);
+		if (retry_msg++ < SEC_TS_IO_RETRY_CNT)
+			goto retry_message;
+	}
+#endif
+	mutex_unlock(&ts->io_mutex);
+
+#ifdef I2C_INTERFACE
+	if (ret == 1)
+#else
+	if (ret == 0)
+#endif
+		return 0;
+err:
+	return -EIO;
+}
+
+/* Wrapper API for read and write */
+int sec_ts_read(struct sec_ts_data *ts, u8 reg, u8 *data, int len)
+{
+	return sec_ts_read_internal(ts, reg, data, len, false);
+}
+
+int sec_ts_read_heap(struct sec_ts_data *ts, u8 reg, u8 *data, int len)
+{
+	return sec_ts_read_internal(ts, reg, data, len, true);
+}
+
+int sec_ts_write_burst(struct sec_ts_data *ts, u8 *data, int len)
+{
+	return sec_ts_write_burst_internal(ts, data, len, false);
+}
+
+int sec_ts_write_burst_heap(struct sec_ts_data *ts, u8 *data, int len)
+{
+	return sec_ts_write_burst_internal(ts, data, len, true);
+}
+
+int sec_ts_read_bulk(struct sec_ts_data *ts, u8 *data, int len)
+{
+	return sec_ts_read_bulk_internal(ts, data, len, false);
+}
+
+int sec_ts_read_bulk_heap(struct sec_ts_data *ts, u8 *data, int len)
+{
+	return sec_ts_read_bulk_internal(ts, data, len, true);
+}
+
+static int sec_ts_read_from_customlib(struct sec_ts_data *ts, u8 *data, int len)
+{
+	int ret;
+
+	ret = sec_ts_write(ts, SEC_TS_CMD_CUSTOMLIB_READ_PARAM, data, 2);
+	if (ret < 0)
+		input_err(true, &ts->client->dev,
+			"%s: fail to write custom library command\n", __func__);
+
+	usleep_range(100, 100);
+
+	ret = sec_ts_read(ts, SEC_TS_CMD_CUSTOMLIB_READ_PARAM, (u8 *)data, len);
+	if (ret < 0)
+		input_err(true, &ts->client->dev,
+			"%s: fail to read custom library command\n", __func__);
+
+	return ret;
+}
+
+#if defined(CONFIG_TOUCHSCREEN_DUMP_MODE)
+#include <linux/sec_debug.h>
+extern struct tsp_dump_callbacks dump_callbacks;
+static struct delayed_work *p_ghost_check;
+
+static void sec_ts_check_rawdata(struct work_struct *work)
+{
+	struct sec_ts_data *ts = container_of(work, struct sec_ts_data,
+					      ghost_check.work);
+
+	if (ts->tsp_dump_lock == 1) {
+		input_err(true, &ts->client->dev,
+			  "%s: ignored ## already checking..\n", __func__);
+		return;
+	}
+	if (ts->power_status == SEC_TS_STATE_POWER_OFF) {
+		input_err(true, &ts->client->dev,
+			  "%s: ignored ## IC is power off\n", __func__);
+		return;
+	}
+
+	ts->tsp_dump_lock = 1;
+	input_info(true, &ts->client->dev, "%s: start ##\n", __func__);
+	sec_ts_run_rawdata_all((void *)ts, false);
+	msleep(100);
+
+	input_info(true, &ts->client->dev, "%s: done ##\n", __func__);
+	ts->tsp_dump_lock = 0;
+
+}
+
+static void dump_tsp_log(void)
+{
+	pr_info("%s: %s %s: start\n", SEC_TS_NAME, SECLOG, __func__);
+
+#ifdef CONFIG_BATTERY_SAMSUNG
+	if (lpcharge == 1) {
+		pr_err("%s: %s %s: ignored ## lpm charging Mode!!\n",
+		       SEC_TS_NAME, SECLOG, __func__);
+		return;
+	}
+#endif
+
+	if (p_ghost_check == NULL) {
+		pr_err("%s: %s %s: ignored ## tsp probe fail!!\n",
+		       SEC_TS_NAME, SECLOG, __func__);
+		return;
+	}
+	schedule_delayed_work(p_ghost_check, msecs_to_jiffies(100));
+}
+#endif
+
+
+void sec_ts_delay(unsigned int ms)
+{
+	if (ms < 20)
+		usleep_range(ms * 1000, ms * 1000);
+	else
+		msleep(ms);
+}
+
+int sec_ts_wait_for_ready(struct sec_ts_data *ts, unsigned int ack)
+{
+	return sec_ts_wait_for_ready_with_count(ts, ack,
+						SEC_TS_WAIT_RETRY_CNT);
+}
+
+int sec_ts_wait_for_ready_with_count(struct sec_ts_data *ts, unsigned int ack,
+				     unsigned int count)
+{
+	int rc = -1;
+	int retry = 0;
+	u8 tBuff[SEC_TS_EVENT_BUFF_SIZE] = {0,};
+
+	while (retry < count) {
+		if (sec_ts_read(ts, SEC_TS_READ_ONE_EVENT, tBuff,
+			SEC_TS_EVENT_BUFF_SIZE) >= 0) {
+			if (((tBuff[0] >> 2) & 0xF) == TYPE_STATUS_EVENT_INFO) {
+				if (tBuff[1] == ack) {
+					rc = 0;
+					break;
+				}
+			} else if (((tBuff[0] >> 2) & 0xF) ==
+				   TYPE_STATUS_EVENT_VENDOR_INFO) {
+				if (tBuff[1] == ack) {
+					rc = 0;
+					break;
+				}
+			}
+		}
+		sec_ts_delay(20);
+		retry++;
+	}
+	if (retry == count)
+		input_err(true, &ts->client->dev, "%s: Time Over\n",
+			__func__);
+
+	input_info(true, &ts->client->dev,
+		"%s: %02X, %02X, %02X, %02X, %02X, %02X, %02X, %02X [%d]\n",
+		__func__, tBuff[0], tBuff[1], tBuff[2], tBuff[3],
+		tBuff[4], tBuff[5], tBuff[6], tBuff[7], retry);
+
+	return rc;
+}
+
+int sec_ts_read_calibration_report(struct sec_ts_data *ts)
+{
+	int ret;
+
+	memset(ts->cali_report, 0, sizeof(ts->cali_report));
+	ret = sec_ts_read(ts, SEC_TS_READ_CALIBRATION_REPORT,
+		ts->cali_report, sizeof(ts->cali_report));
+	if (ret < 0) {
+		input_err(true, &ts->client->dev,
+			  "%s: failed to read, %d\n", __func__, ret);
+		return ret;
+	}
+
+	input_info(true, &ts->client->dev,
+		"%s: count: %d, pass cnt: %d, fail cnt: %d, status: %X, param ver: %X %X %X %X\n",
+		__func__, ts->cali_report_try_cnt, ts->cali_report_pass_cnt,
+		ts->cali_report_fail_cnt, ts->cali_report_status,
+		ts->cali_report_param_ver[0], ts->cali_report_param_ver[1],
+		ts->cali_report_param_ver[2], ts->cali_report_param_ver[3]);
+
+	return ts->cali_report_status;
+}
+
+#define PTFLIB_ENCODED_ENABLED_OFFSET_LSB	0xA0
+#define PTFLIB_ENCODED_ENABLED_OFFSET_MSB	0x00
+#define PTFLIB_ENCODED_ENABLED_TRUE		0x01
+#define PTFLIB_ENCODED_ENABLED_FALSE		0x00
+static int sec_ts_ptflib_reinit(struct sec_ts_data *ts)
+{
+	u8 r_data[2] = {0x00, 0x00};
+	u8 w_data[6] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+	int ret = 0;
+
+	/* Check whether encoded heatmap is inited in custom library. */
+	r_data[0] = PTFLIB_ENCODED_ENABLED_OFFSET_LSB;
+	r_data[1] = PTFLIB_ENCODED_ENABLED_OFFSET_MSB;
+        ret = sec_ts_read_from_customlib(ts, r_data, 2);
+	if (ret < 0) {
+		input_err(true, &ts->client->dev,
+			  "%s: Read encoded heatmap's inited failed.\n",
+			  __func__);
+		return -EIO;
+	}
+
+	if (r_data[1] != 0x01) {
+		input_err(true, &ts->client->dev,
+			  "%s: Encoded heatmap was not initialized.\n",
+			  __func__);
+		return -EIO;
+	}
+
+	/* Return if encoded heatmap is already enabled. */
+	if (r_data[0] == 0x01) {
+		input_info(true, &ts->client->dev,
+			   "%s: Encoded heatmap is already enabled.\n",
+			   __func__);
+		return 0;
+	}
+
+	/* Enable encoded heatmap. */
+	w_data[0] = PTFLIB_ENCODED_ENABLED_OFFSET_LSB;
+	w_data[1] = PTFLIB_ENCODED_ENABLED_OFFSET_MSB;
+	w_data[2] = PTFLIB_ENCODED_ENABLED_TRUE;
+	ret = sec_ts_write(ts, SEC_TS_CMD_CUSTOMLIB_WRITE_PARAM, w_data, 3);
+	if (ret < 0) {
+		input_err(true, &ts->client->dev,
+			  "%s: ptlib - Writing encoded heatmap's enabled register failed.\n",
+			  __func__);
+		return -EIO;
+	}
+
+	/* Check whether encoded heatmap is enabled in customlib. */
+	r_data[0] = PTFLIB_ENCODED_ENABLED_OFFSET_LSB;
+	r_data[1] = PTFLIB_ENCODED_ENABLED_OFFSET_MSB;
+	ret = sec_ts_read_from_customlib(ts, r_data, 2);
+	if (ret < 0) {
+		input_err(true, &ts->client->dev,
+			  "%s: ptlib - Read encoded heatmap's enabled status failed.\n",
+			  __func__);
+		return -EIO;
+	}
+
+	if (r_data[0] != PTFLIB_ENCODED_ENABLED_TRUE) {
+		input_err(true, &ts->client->dev,
+			  "%s: ptlib - Enabling encoded heatmap failed.\n",
+				  __func__);
+		return -EIO;
+	}
+
+	return 0;
+}
+
+#define PTFLIB_GRIP_ENABLED_OFFSET_LSB	0x80
+#define PTFLIB_GRIP_ENABLED_OFFSET_MSB	0x00
+static int sec_ts_ptflib_grip_prescreen_enable(struct sec_ts_data *ts,
+					       int grip_prescreen_mode) {
+	u8 r_data[2] = {0x00, 0x00};
+	u8 w_data[3] = {0x00, 0x00, 0x00};
+	int result;
+
+	input_info(true, &ts->client->dev, "%s: set mode %d.\n",
+	    __func__, grip_prescreen_mode);
+
+	if (grip_prescreen_mode < GRIP_PRESCREEN_OFF ||
+	    grip_prescreen_mode > GRIP_PRESCREEN_MODE_3) {
+		input_err(true, &ts->client->dev,
+		    "%s: invalid grip_prescreen_mode value %d.\n",
+		    __func__, grip_prescreen_mode);
+		return -EINVAL;
+	}
+
+	w_data[0] = PTFLIB_GRIP_ENABLED_OFFSET_LSB;
+	w_data[1] = PTFLIB_GRIP_ENABLED_OFFSET_MSB;
+	w_data[2] = grip_prescreen_mode;
+	result = ts->sec_ts_write(ts, SEC_TS_CMD_CUSTOMLIB_WRITE_PARAM,
+	    w_data, 3);
+	if (result < 0) {
+		input_err(true, &ts->client->dev,
+		    "%s: Write grip_prescreen_mode register failed.\n",
+		    __func__);
+		return -EIO;
+	}
+
+	r_data[0] = PTFLIB_GRIP_ENABLED_OFFSET_LSB;
+	r_data[1] = PTFLIB_GRIP_ENABLED_OFFSET_MSB;
+	result = ts->sec_ts_read_customlib(ts, r_data, 2);
+	if (result < 0) {
+		input_err(true, &ts->client->dev,
+		    "%s: Read grip_prescreen_mode register failed.\n",
+		    __func__);
+		return -EIO;
+	}
+
+	if (r_data[0] != grip_prescreen_mode) {
+		input_err(true, &ts->client->dev,
+		    "%s: Configure grip_prescreen_mode register failed %d.\n",
+		    __func__, r_data[0]);
+		return -EIO;
+	}
+
+	return 0;
+}
+
+#define PTFLIB_GRIP_PRESCREEN_TIMEOUT_OFFSET_LSB	0x9A
+#define PTFLIB_GRIP_PRESCREEN_TIMEOUT_OFFSET_MSB	0x00
+static int sec_ts_ptflib_grip_prescreen_timeout(struct sec_ts_data *ts,
+					        int grip_prescreen_timeout) {
+	u8 r_data[2] = {0x00, 0x00};
+	u8 w_data[4] = {0x00, 0x00, 0x00, 0x00};
+	u16 timeout;
+	int result;
+
+	input_info(true, &ts->client->dev, "%s: set timeout %d.\n",
+	    __func__, grip_prescreen_timeout);
+
+	if (grip_prescreen_timeout < GRIP_PRESCREEN_TIMEOUT_MIN ||
+	    grip_prescreen_timeout > GRIP_PRESCREEN_TIMEOUT_MAX) {
+		input_err(true, &ts->client->dev,
+		    "%s: invalid grip_prescreen_timeout value %d.\n",
+		    __func__, grip_prescreen_timeout);
+		return -EINVAL;
+	}
+
+	w_data[0] = PTFLIB_GRIP_PRESCREEN_TIMEOUT_OFFSET_LSB;
+	w_data[1] = PTFLIB_GRIP_PRESCREEN_TIMEOUT_OFFSET_MSB;
+	w_data[2] = grip_prescreen_timeout & 0xFF;
+	w_data[3] = (grip_prescreen_timeout >> 8) & 0xFF;
+	result = ts->sec_ts_write(ts, SEC_TS_CMD_CUSTOMLIB_WRITE_PARAM,
+	    w_data, 4);
+	if (result < 0) {
+		input_err(true, &ts->client->dev,
+		    "%s: Write grip_prescreen_timeout register failed.\n",
+		    __func__);
+		return -EIO;
+	}
+
+	r_data[0] = PTFLIB_GRIP_PRESCREEN_TIMEOUT_OFFSET_LSB;
+	r_data[1] = PTFLIB_GRIP_PRESCREEN_TIMEOUT_OFFSET_MSB;
+	result = ts->sec_ts_read_customlib(ts, r_data, 2);
+	if (result < 0) {
+		input_err(true, &ts->client->dev,
+		    "%s: Read grip_prescreen_timeout register failed.\n",
+		    __func__);
+		return -EIO;
+	}
+
+	timeout = le16_to_cpup((uint16_t *) r_data);
+	if (timeout != grip_prescreen_timeout) {
+		input_err(true, &ts->client->dev,
+		    "%s: Configure grip_prescreen_timeout register failed %d.\n",
+		    __func__, timeout);
+		return -EIO;
+	}
+
+	return 0;
+}
+
+#define PTFLIB_GRIP_PRESCREEN_FRAMES_OFFSET_LSB	0x9C
+#define PTFLIB_GRIP_PRESCREEN_FRAMES_OFFSET_MSB	0x00
+static int sec_ts_ptflib_get_grip_prescreen_frames(struct sec_ts_data *ts) {
+	u8 r_data[4] = {0x00, 0x00, 0x00, 0x00};
+	int result;
+
+	r_data[0] = PTFLIB_GRIP_PRESCREEN_FRAMES_OFFSET_LSB;
+	r_data[1] = PTFLIB_GRIP_PRESCREEN_FRAMES_OFFSET_MSB;
+	result = ts->sec_ts_read_customlib(ts, r_data, sizeof(r_data));
+	if (result < 0) {
+		input_err(true, &ts->client->dev,
+		    "%s: Read grip prescreen frames register failed.\n",
+		    __func__);
+		return -EIO;
+	}
+
+	return le32_to_cpup((uint32_t *) r_data);
+}
+
+static int sec_ts_ptflib_decoder(struct sec_ts_data *ts, const u16 *in_array,
+				 const int in_array_size, u16 *out_array,
+				 const int out_array_max_size)
+{
+	const u16 ESCAPE_MASK = 0xF000;
+	const u16 ESCAPE_BIT = 0x8000;
+
+	int i;
+	int j;
+	int out_array_size = 0;
+	u16 prev_word = 0;
+	u16 repetition = 0;
+
+	for (i = 0; i < in_array_size; i++) {
+		u16 curr_word = in_array[i];
+		if ((curr_word & ESCAPE_MASK) == ESCAPE_BIT) {
+			repetition = (curr_word & ~ESCAPE_MASK) - 1;
+			if (out_array_size + repetition > out_array_max_size)
+				break;
+
+			for (j = 0; j < repetition; j++) {
+				*out_array++ = prev_word;
+				out_array_size++;
+			}
+		} else {
+			if (out_array_size >= out_array_max_size)
+				break;
+
+			*out_array++ = curr_word;
+			out_array_size++;
+			prev_word = curr_word;
+		}
+	}
+
+	if (i != in_array_size || out_array_size != out_array_max_size) {
+		input_info(true, &ts->client->dev,
+			   "%s: %d (in=%d, out=%d, rep=%d, out_max=%d).\n",
+			   __func__, i, in_array_size, out_array_size,
+			   repetition, out_array_max_size);
+		return -1;
+	}
+
+	return out_array_size;
+}
+
+static void sec_ts_reinit(struct sec_ts_data *ts)
+{
+	u8 w_data[2] = {0x00, 0x00};
+	int ret = 0;
+
+	input_info(true, &ts->client->dev,
+		"%s : charger=0x%x, Cover=0x%x, Power mode=0x%x\n",
+		__func__, ts->charger_mode, ts->touch_functions,
+		ts->lowpower_status);
+
+	/* charger mode */
+	if (ts->charger_mode != SEC_TS_BIT_CHARGER_MODE_NO) {
+		w_data[0] = ts->charger_mode;
+		ret = ts->sec_ts_write(ts, SET_TS_CMD_SET_CHARGER_MODE,
+				       (u8 *)&w_data[0], 1);
+		if (ret < 0)
+			input_err(true, &ts->client->dev,
+				  "%s: Failed to send command(0x%x)",
+				__func__, SET_TS_CMD_SET_CHARGER_MODE);
+	}
+
+	/* Cover mode */
+	if (ts->touch_functions & SEC_TS_BIT_SETFUNC_COVER) {
+		w_data[0] = ts->cover_cmd;
+		ret = sec_ts_write(ts, SEC_TS_CMD_SET_COVERTYPE,
+				   (u8 *)&w_data[0], 1);
+		if (ret < 0)
+			input_err(true, &ts->client->dev,
+				"%s: Failed to send command(0x%x)",
+				__func__, SEC_TS_CMD_SET_COVERTYPE);
+
+		ret = sec_ts_write(ts, SEC_TS_CMD_SET_TOUCHFUNCTION,
+				   (u8 *)&(ts->touch_functions), 2);
+		if (ret < 0)
+			input_err(true, &ts->client->dev,
+				"%s: Failed to send command(0x%x)",
+				__func__, SEC_TS_CMD_SET_TOUCHFUNCTION);
+	}
+
+	#ifdef SEC_TS_SUPPORT_CUSTOMLIB
+	if (ts->use_customlib)
+		sec_ts_set_custom_library(ts);
+	#endif
+
+	/* Power mode */
+	if (ts->lowpower_status == TO_LOWPOWER_MODE) {
+		w_data[0] = (ts->lowpower_mode &
+			     SEC_TS_MODE_LOWPOWER_FLAG) >> 1;
+		ret = sec_ts_write(ts, SEC_TS_CMD_WAKEUP_GESTURE_MODE,
+				   (u8 *)&w_data[0], 1);
+		if (ret < 0)
+			input_err(true, &ts->client->dev,
+				"%s: Failed to send command(0x%x)",
+				__func__, SEC_TS_CMD_WAKEUP_GESTURE_MODE);
+
+		w_data[0] = TO_LOWPOWER_MODE;
+		ret = sec_ts_write(ts, SEC_TS_CMD_SET_POWER_MODE,
+				   (u8 *)&w_data[0], 1);
+		if (ret < 0)
+			input_err(true, &ts->client->dev,
+				"%s: Failed to send command(0x%x)",
+				__func__, SEC_TS_CMD_SET_POWER_MODE);
+
+		sec_ts_delay(50);
+
+		if (ts->lowpower_mode & SEC_TS_MODE_CUSTOMLIB_AOD) {
+			int i, ret;
+			u8 data[10] = {0x02, 0};
+
+			for (i = 0; i < 4; i++) {
+				data[i * 2 + 2] = ts->rect_data[i] & 0xFF;
+				data[i * 2 + 3] =
+					(ts->rect_data[i] >> 8) & 0xFF;
+			}
+
+			ret = ts->sec_ts_write(ts,
+					SEC_TS_CMD_CUSTOMLIB_WRITE_PARAM,
+					&data[0], 10);
+			if (ret < 0)
+				input_err(true, &ts->client->dev,
+					"%s: Failed to write offset\n",
+					__func__);
+
+			ret = ts->sec_ts_write(ts,
+				SEC_TS_CMD_CUSTOMLIB_NOTIFY_PACKET, NULL, 0);
+			if (ret < 0)
+				input_err(true, &ts->client->dev,
+					"%s: Failed to send notify\n",
+					__func__);
+
+		}
+
+	} else {
+
+		sec_ts_set_grip_type(ts, ONLY_EDGE_HANDLER);
+
+		if (ts->dex_mode) {
+			input_info(true, &ts->client->dev,
+				   "%s: set dex mode\n", __func__);
+			ret = ts->sec_ts_write(ts, SEC_TS_CMD_SET_DEX_MODE,
+					       &ts->dex_mode, 1);
+			if (ret < 0)
+				input_err(true, &ts->client->dev,
+					"%s: failed to set dex mode %x\n",
+					__func__, ts->dex_mode);
+		}
+
+		if (ts->brush_mode) {
+			input_info(true, &ts->client->dev,
+				   "%s: set brush mode\n", __func__);
+			ret = ts->sec_ts_write(ts, SEC_TS_CMD_SET_BRUSH_MODE,
+					       &ts->brush_mode, 1);
+			if (ret < 0)
+				input_err(true, &ts->client->dev,
+					"%s: failed to set brush mode\n",
+					__func__);
+		}
+
+		if (ts->touchable_area) {
+			input_info(true, &ts->client->dev,
+				   "%s: set 16:9 mode\n", __func__);
+			ret = ts->sec_ts_write(ts,
+					SEC_TS_CMD_SET_TOUCHABLE_AREA,
+					&ts->touchable_area, 1);
+			if (ret < 0)
+				input_err(true, &ts->client->dev,
+					"%s: failed to set 16:9 mode\n",
+					__func__);
+		}
+
+	}
+}
+
+#if IS_ENABLED(CONFIG_TOUCHSCREEN_HEATMAP)
+/* Update a state machine used to toggle control of the touch IC's motion
+ * filter.
+ */
+static void update_motion_filter(struct sec_ts_data *ts, unsigned long touch_id)
+{
+	/* Motion filter timeout, in milliseconds */
+	const u32 mf_timeout_ms = 500;
+	u8 next_state;
+	/* Count the active touches */
+	u8 touches = hweight32(touch_id);
+
+	if (ts->use_default_mf)
+		return;
+
+	/* Determine the next filter state. The motion filter is enabled by
+	 * default and it is disabled while a single finger is touching the
+	 * screen. If another finger is touched down or if a timeout expires,
+	 * the motion filter is reenabled and remains enabled until all fingers
+	 * are lifted.
+	 */
+	next_state = ts->mf_state;
+	switch (ts->mf_state) {
+	case SEC_TS_MF_FILTERED:
+		if (touches == 1) {
+			next_state = SEC_TS_MF_UNFILTERED;
+			ts->mf_downtime = ktime_get();
+		}
+		break;
+	case SEC_TS_MF_UNFILTERED:
+		if (touches == 0) {
+			next_state = SEC_TS_MF_FILTERED;
+		} else if (touches > 1 ||
+			   ktime_after(ktime_get(),
+				       ktime_add_ms(ts->mf_downtime,
+						    mf_timeout_ms))) {
+			next_state = SEC_TS_MF_FILTERED_LOCKED;
+		}
+		break;
+	case SEC_TS_MF_FILTERED_LOCKED:
+		if (touches == 0)
+			next_state = SEC_TS_MF_FILTERED;
+		break;
+	}
+
+	/* Send command to update filter state */
+	if ((next_state == SEC_TS_MF_UNFILTERED) !=
+	    (ts->mf_state == SEC_TS_MF_UNFILTERED)) {
+		int ret;
+		u8 para;
+
+		pr_debug("%s: setting motion filter = %s.\n", __func__,
+			 (next_state == SEC_TS_MF_UNFILTERED) ?
+			 "false" : "true");
+		para = (next_state == SEC_TS_MF_UNFILTERED) ? 0x01 : 0x00;
+		ret = ts->sec_ts_write(ts, SEC_TS_CMD_SET_CONT_REPORT,
+				       &para, 1);
+		if (ret < 0) {
+			input_err(true, &ts->client->dev,
+			 "%s: write reg %#x para %#x failed, returned %i\n",
+			__func__, SEC_TS_CMD_SET_CONT_REPORT, para, ret);
+		}
+	}
+	ts->mf_state = next_state;
+}
+
+static bool read_heatmap_raw(struct v4l2_heatmap *v4l2)
+{
+	struct sec_ts_data *ts = container_of(v4l2, struct sec_ts_data, v4l2);
+	struct sec_ts_plat_data *pdata = ts->plat_data;
+	int result;
+	int max_x = v4l2->format.width;
+	int max_y = v4l2->format.height;
+
+	if (ts->v4l2_mutual_strength_updated &&
+	    ts->mutual_strength_heatmap.size_x == max_x &&
+	    ts->mutual_strength_heatmap.size_y == max_y) {
+		memcpy(v4l2->frame, ts->mutual_strength_heatmap.data,
+		       max_x * max_y * 2);
+		ts->v4l2_mutual_strength_updated = false;
+		return true;
+	}
+
+	if (ts->tsp_dump_lock == 1) {
+		input_info(true, &ts->client->dev,
+			"%s: drop this because raw data reading by others\n",
+			__func__);
+		return false;
+	}
+
+	if (pdata->heatmap_mode == HEATMAP_PARTIAL) {
+		strength_t heatmap_value;
+		int heatmap_x, heatmap_y;
+		/* index for through the heatmap buffer read over the bus */
+		unsigned int local_i;
+		/* final position of the heatmap value in the full frame */
+		unsigned int frame_i;
+		unsigned int num_elements;
+		u8 enable;
+		struct heatmap_report report = {0};
+
+		if (!pdata->is_heatmap_enabled) {
+			result = sec_ts_read(ts,
+				SEC_TS_CMD_HEATMAP_ENABLE, &enable, 1);
+			if (result < 0) {
+				input_err(true, &ts->client->dev,
+					  "%s: read reg %#x failed, returned %i\n",
+					  __func__,
+					  SEC_TS_CMD_HEATMAP_ENABLE, result);
+				return false;
+			}
+
+			if (!enable) {
+				enable = 1;
+				result = sec_ts_write(ts,
+					SEC_TS_CMD_HEATMAP_ENABLE, &enable, 1);
+				if (result < 0)
+					input_err(true, &ts->client->dev,
+						"%s: enable local heatmap failed, returned %i\n",
+						__func__, result);
+				else
+					pdata->is_heatmap_enabled = true;
+				/*
+				 * After local heatmap enabled, it takes
+				 * `1/SCAN_RATE` time to make data ready. But,
+				 * we don't want to wait here to cause
+				 * overhead. Just drop this and wait for next
+				 * reading.
+				 */
+				return false;
+			} else {
+				ts->plat_data->is_heatmap_enabled = true;
+			}
+		}
+
+		result = sec_ts_read(ts, SEC_TS_CMD_HEATMAP_READ,
+			(uint8_t *) &report, sizeof(report));
+		if (result < 0) {
+			input_err(true, &ts->client->dev,
+				 "%s: read failed, returned %i\n",
+				__func__, result);
+			return false;
+		}
+
+		num_elements = report.size_x * report.size_y;
+		if (num_elements > LOCAL_HEATMAP_WIDTH * LOCAL_HEATMAP_HEIGHT) {
+			input_err(true, &ts->client->dev,
+				"Unexpected heatmap size: %i x %i",
+				report.size_x, report.size_y);
+				return false;
+		}
+
+		/*
+		 * Set all to zero, will only write to non-zero locations
+		 * in the loop.
+		 */
+		memset(v4l2->frame, 0, v4l2->format.sizeimage);
+		/* populate the data buffer, rearranging into final locations */
+		for (local_i = 0; local_i < num_elements; local_i++) {
+			/* big-endian order raw data into heatmap data type */
+			be16_to_cpus(&report.data[local_i]);
+			heatmap_value = report.data[local_i];
+
+			if (heatmap_value == 0) {
+				/*
+				 * Already initialized to zero. More
+				 * importantly, samples around edges may go out
+				 * of bounds.
+				 * If their value is zero, this is ok.
+				 */
+				continue;
+			}
+			heatmap_x = report.offset_x + (local_i % report.size_x);
+			heatmap_y = report.offset_y + (local_i / report.size_x);
+
+			if (heatmap_x < 0 || heatmap_x >= max_x ||
+				heatmap_y < 0 || heatmap_y >= max_y) {
+				input_err(true, &ts->client->dev,
+					"Invalid x or y: (%i, %i), value=%i, ending loop\n",
+					heatmap_x, heatmap_y,
+					heatmap_value);
+					return false;
+			}
+			frame_i = heatmap_y * max_x + heatmap_x;
+			v4l2->frame[frame_i] = heatmap_value;
+		}
+	} else if (pdata->heatmap_mode == HEATMAP_FULL) {
+		int i, j, index = 0;
+		int ret = 0;
+		u8 type;
+
+		if (!ts->heatmap_buff) {
+			ts->heatmap_buff = kmalloc(
+				sizeof(strength_t) * max_x * max_y, GFP_KERNEL);
+			if (!ts->heatmap_buff) {
+				input_err(true, &ts->client->dev,
+				"%s: alloc heatmap_buff failed\n", __func__);
+				return false;
+			}
+		}
+
+		ret = sec_ts_read(ts,
+			SEC_TS_CMD_MUTU_RAW_TYPE, &ts->ms_frame_type, 1);
+		if (ret < 0) {
+			input_err(true, &ts->client->dev,
+				"%s: read rawdata type failed\n",
+				__func__);
+			return false;
+		}
+
+		/* Check raw type is TYPE_SIGNAL_DATA */
+		if (ts->ms_frame_type != TYPE_SIGNAL_DATA) {
+			input_info(true, &ts->client->dev,
+				"%s: ms_frame_type change from %#x\n",
+				__func__, ts->ms_frame_type);
+
+			/* Check raw type is TYPE_INVALID_DATA */
+			if (ts->ms_frame_type != TYPE_INVALID_DATA) {
+				type = TYPE_INVALID_DATA;
+				ret = sec_ts_write(ts,
+					SEC_TS_CMD_MUTU_RAW_TYPE, &type, 1);
+				if (ret < 0) {
+					input_err(true, &ts->client->dev,
+						"%s: recover rawdata type failed\n",
+						__func__);
+					return false;
+				}
+				ts->ms_frame_type = type;
+			}
+
+			/* Set raw type to TYPE_SIGNAL_DATA */
+			type = TYPE_SIGNAL_DATA;
+			ret = sec_ts_write(ts, SEC_TS_CMD_MUTU_RAW_TYPE,
+				&type, 1);
+			if (ret < 0) {
+				input_err(true, &ts->client->dev,
+					"%s: Set rawdata type failed\n",
+					__func__);
+				return false;
+			}
+			ts->ms_frame_type = type;
+
+			/*
+			 * If raw type change, need to wait 50 ms to read data
+			 * back. But, we don't wanto to wait here to cause
+			 * overhead. Just drop this and wait for next reading.
+			 */
+			return false;
+		}
+
+		ret = sec_ts_read_heap(ts, SEC_TS_READ_TOUCH_RAWDATA,
+			(u8 *)ts->heatmap_buff,
+			sizeof(strength_t) * max_x * max_y);
+		if (ret < 0) {
+			input_err(true, &ts->client->dev,
+				"%s: Read delta frame failed\n", __func__);
+			return false;
+		}
+
+		/* big-endian order raw data into heatmap data type */
+		for (i = max_y - 1; i >= 0; i--)
+			for (j = max_x - 1; j >= 0 ; j--)
+				v4l2->frame[index++] = be16_to_cpup(
+					ts->heatmap_buff + (j * max_y) + i);
+	} else
+		return false;
+
+	return true;
+}
+#endif
+
+#ifdef SEC_TS_SUPPORT_CUSTOMLIB
+/* WARNING: touch_offload does not currently support the custom library
+ * interface!
+ * TODO: when custom library support is enabled, ensure that the output is
+ * routed through touch_offload.
+ */
+static void sec_ts_handle_lib_status_event(struct sec_ts_data *ts,
+				struct sec_ts_event_status *p_event_status)
+{
+	if ((p_event_status->stype == TYPE_STATUS_EVENT_CUSTOMLIB_INFO) &&
+	    (p_event_status->status_id == SEC_TS_EVENT_CUSTOMLIB_FORCE_KEY)) {
+		if (ts->power_status == SEC_TS_STATE_POWER_ON) {
+			if (p_event_status->status_data_1 &
+			    SEC_TS_CUSTOMLIB_EVENT_PRESSURE_TOUCHED) {
+				ts->all_force_count++;
+				ts->scrub_id =
+					CUSTOMLIB_EVENT_TYPE_PRESSURE_TOUCHED;
+			} else {
+				if (ts->scrub_id ==
+				    CUSTOMLIB_EVENT_TYPE_AOD_HOMEKEY_PRESS) {
+					input_report_key(ts->input_dev,
+							 KEY_HOMEPAGE,
+							 0);
+					ts->scrub_id =
+				CUSTOMLIB_EVENT_TYPE_AOD_HOMEKEY_RELEASE;
+				} else {
+					ts->scrub_id =
+					CUSTOMLIB_EVENT_TYPE_PRESSURE_RELEASED;
+				}
+			}
+
+			input_report_key(ts->input_dev,
+					 KEY_BLACK_UI_GESTURE, 1);
+		} else {
+			if (p_event_status->status_data_1 &
+			    SEC_TS_CUSTOMLIB_EVENT_PRESSURE_RELEASED) {
+				input_report_key(ts->input_dev,
+						 KEY_HOMEPAGE, 0);
+				input_report_key(ts->input_dev,
+						 KEY_BLACK_UI_GESTURE, 1);
+				ts->scrub_id =
+				CUSTOMLIB_EVENT_TYPE_AOD_HOMEKEY_RLS_NO_HAPTIC;
+				input_sync(ts->input_dev);
+				haptic_homekey_release();
+			} else {
+				input_report_key(ts->input_dev,
+						 KEY_HOMEPAGE, 1);
+				input_sync(ts->input_dev);
+				ts->scrub_id =
+					CUSTOMLIB_EVENT_TYPE_AOD_HOMEKEY_PRESS;
+				haptic_homekey_press();
+				ts->all_force_count++;
+			}
+		}
+
+		ts->scrub_x =
+			((p_event_status->status_data_4 >> 4) & 0xF) << 8 |
+			(p_event_status->status_data_3 & 0xFF);
+		ts->scrub_y =
+			((p_event_status->status_data_4 >> 0) & 0xF) << 8 |
+			(p_event_status->status_data_2 & 0xFF);
+
+		input_info(true, &ts->client->dev, "%s: PRESSURE[%d]\n",
+			   __func__, ts->scrub_id);
+
+		input_sync(ts->input_dev);
+		input_report_key(ts->input_dev, KEY_BLACK_UI_GESTURE, 0);
+	}
+}
+#endif
+
+
+#ifdef SEC_TS_HC_KFIFO_LEN
+inline void sec_ts_hc_update_and_push(struct sec_ts_data *ts, struct sec_ts_health_check *hc)
+{
+	hc->int_ktime = ts->timestamp;
+	hc->int_idx = ts->int_cnt;
+	hc->coord_idx = ts->coord_event_cnt;
+	hc->status_idx = ts->status_event_cnt;
+	hc->active_bit = ts->tid_touch_state;
+
+	if (kfifo_is_full(&hc_fifo))
+		kfifo_skip(&hc_fifo);
+	kfifo_in(&hc_fifo, hc, 1);
+}
+
+inline void sec_ts_hc_dump(struct sec_ts_data *ts)
+{
+	int i, len;
+	s64 delta;
+	s64 sec_delta;
+	u32 ms_delta;
+	ktime_t current_time = ktime_get();
+	struct sec_ts_health_check last_hc[SEC_TS_HC_KFIFO_LEN];
+
+	len = kfifo_out_peek(&hc_fifo, last_hc, kfifo_size(&hc_fifo));
+	if (!len) {
+		input_err(true, &ts->client->dev, "%s: failed to peek hc\n",
+			  __func__);
+		return;
+	}
+	for (i = 0 ; i < len; i++) {
+		sec_delta = 0;
+		ms_delta = 0;
+		delta = ktime_ms_delta(current_time, last_hc[i].int_ktime);
+		if (delta > 0)
+			sec_delta = div_u64_rem(delta, MSEC_PER_SEC, &ms_delta);
+
+		input_info(true, &ts->client->dev,
+			"dump-int: #%llu(%llu.%u): S#%llu%s C#%llu(0x%lx)%s.\n",
+			last_hc[i].int_idx,
+			sec_delta, ms_delta,
+			last_hc[i].status_idx,
+			(last_hc[i].status_updated) ? "(+)" : "   ",
+			last_hc[i].coord_idx,
+			last_hc[i].active_bit,
+			(last_hc[i].coord_updated) ? "(+)" : ""
+			);
+	}
+}
+#else
+#define sec_ts_hc_update_and_push(ts, hc) do {} while (0)
+#define sec_ts_hc_dump(ts) do {} while (0)
+#endif /* #ifdef SEC_TS_HC_KFIFO_LEN */
+
+#ifdef SEC_TS_DEBUG_KFIFO_LEN
+inline void sec_ts_kfifo_push_coord(struct sec_ts_data *ts, u8 slot)
+{
+	if (slot < MAX_SUPPORT_TOUCH_COUNT) {
+		/*
+		 * Use kfifo as circular buffer by skipping one element
+		 * when fifo is full.
+		 */
+		if (kfifo_is_full(&debug_fifo))
+			kfifo_skip(&debug_fifo);
+		kfifo_in(&debug_fifo, &ts->coord[slot], 1);
+	}
+}
+
+inline void sec_ts_kfifo_pop_all_coords(struct sec_ts_data *ts)
+{
+	int __maybe_unused len;
+	/*
+	 * Keep coords without pop-out to support different timing
+	 * print-out by each caller.
+	 */
+	len = kfifo_out_peek(&debug_fifo, last_coord, kfifo_size(&debug_fifo));
+}
+
+inline void sec_ts_debug_dump(struct sec_ts_data *ts)
+{
+	int i;
+	s64 delta;
+	s64 sec_longest_duration;
+	u32 ms_longest_duration;
+	s64 sec_delta_down;
+	u32 ms_delta_down;
+	s64 sec_delta_duration;
+	u32 ms_delta_duration;
+	s32 px_delta_x, px_delta_y;
+	ktime_t current_time = ktime_get();
+
+	sec_longest_duration = div_u64_rem(ts->longest_duration,
+				MSEC_PER_SEC, &ms_longest_duration);
+
+	sec_ts_kfifo_pop_all_coords(ts);
+	for (i = 0 ; i < ARRAY_SIZE(last_coord) ; i++) {
+		if (last_coord[i].action == SEC_TS_COORDINATE_ACTION_NONE) {
+			input_dbg(true, &ts->client->dev,
+				"dump: #%d: N/A!\n", last_coord[i].id);
+			continue;
+		}
+		sec_delta_down = -1;
+		ms_delta_down = 0;
+		/* calculate the delta of finger down from current time. */
+		delta = ktime_ms_delta(current_time, last_coord[i].ktime_pressed);
+		if (delta > 0)
+			sec_delta_down = div_u64_rem(delta, MSEC_PER_SEC, &ms_delta_down);
+
+		/* calculate the delta of finger duration between finger up and down. */
+		sec_delta_duration = -1;
+		ms_delta_duration = 0;
+		px_delta_x = 0;
+		px_delta_y = 0;
+		if (last_coord[i].action == SEC_TS_COORDINATE_ACTION_RELEASE) {
+			delta = ktime_ms_delta(last_coord[i].ktime_released,
+					last_coord[i].ktime_pressed);
+			if (delta > 0) {
+				sec_delta_duration = div_u64_rem(delta, MSEC_PER_SEC,
+									&ms_delta_duration);
+				px_delta_x = last_coord[i].x - last_coord[i].x_pressed;
+				px_delta_y = last_coord[i].y - last_coord[i].y_pressed;
+			}
+		}
+		input_info(true, &ts->client->dev,
+			"dump: #%d: %lld.%u(%lld.%u) D(%d, %d).\n",
+			last_coord[i].id,
+			sec_delta_down, ms_delta_down,
+			sec_delta_duration, ms_delta_duration,
+			px_delta_x, px_delta_y);
+		input_dbg(true, &ts->client->dev,
+			"dump-dbg: #%d: (%d, %d) (%d, %d).\n",
+			last_coord[i].id,
+			last_coord[i].x_pressed, last_coord[i].y_pressed,
+			last_coord[i].x, last_coord[i].y);
+	}
+	input_info(true, &ts->client->dev,
+		"dump: i/o %u, comm %u, reset %u, longest %lld.%u.\n",
+		ts->io_err_count, ts->comm_err_count, ts->hw_reset_count,
+		sec_longest_duration, ms_longest_duration);
+	input_info(true, &ts->client->dev,
+		"dump: cnt %u, active %u, wet %u, palm %u.\n",
+		ts->pressed_count, ts->touch_count, ts->wet_count, ts->palm_count);
+}
+#else
+#define sec_ts_kfifo_push_coord(ts, slot) do {} while (0)
+#define sec_ts_kfifo_pop_all_coords(ts) do {} while (0)
+#define sec_ts_debug_dump(ts) do {} while (0)
+#endif /* #ifdef SEC_TS_DEBUG_KFIFO_LEN */
+
+static void sec_ts_handle_coord_event(struct sec_ts_data *ts,
+				struct sec_ts_event_coordinate *p_event_coord)
+{
+	u8 t_id;
+
+	if (ts->input_closed) {
+		input_err(true, &ts->client->dev, "%s: device is closed\n",
+			__func__);
+		return;
+	}
+
+	t_id = (p_event_coord->tid - 1);
+
+	if (t_id < MAX_SUPPORT_TOUCH_COUNT + MAX_SUPPORT_HOVER_COUNT) {
+		ts->coord[t_id].id = t_id;
+		ts->coord[t_id].action = p_event_coord->tchsta;
+		ts->coord[t_id].x = (p_event_coord->x_11_4 << 4) |
+					(p_event_coord->x_3_0);
+		ts->coord[t_id].y = (p_event_coord->y_11_4 << 4) |
+					(p_event_coord->y_3_0);
+		ts->coord[t_id].z = p_event_coord->z &
+					SEC_TS_PRESSURE_MAX;
+		ts->coord[t_id].ttype = p_event_coord->ttype_3_2 << 2 |
+					p_event_coord->ttype_1_0 << 0;
+		ts->coord[t_id].major = p_event_coord->major *
+						ts->plat_data->mm2px;
+		ts->coord[t_id].minor = p_event_coord->minor *
+						ts->plat_data->mm2px;
+
+		if (!ts->coord[t_id].palm &&
+			(ts->coord[t_id].ttype == SEC_TS_TOUCHTYPE_PALM))
+			ts->palm_count++;
+
+		ts->coord[t_id].palm =
+			(ts->coord[t_id].ttype == SEC_TS_TOUCHTYPE_PALM);
+
+		ts->coord[t_id].grip =
+			(ts->coord[t_id].ttype == SEC_TS_TOUCHTYPE_GRIP);
+
+		ts->coord[t_id].left_event = p_event_coord->left_event;
+
+		if (ts->coord[t_id].x > ts->plat_data->max_x) {
+			input_info(true, &ts->client->dev,
+				"%s: unexpected FW x-coord(%u)!\n", __func__, ts->coord[t_id].x);
+			ts->coord[t_id].x = ts->plat_data->max_x;
+		}
+		if (ts->coord[t_id].y > ts->plat_data->max_y) {
+			input_info(true, &ts->client->dev,
+				"%s: unexpected FW y-coord(%u)!\n", __func__, ts->coord[t_id].y);
+			ts->coord[t_id].y = ts->plat_data->max_y;
+		}
+		if (ts->coord[t_id].z <= 0)
+			ts->coord[t_id].z = 1;
+
+#if IS_ENABLED(CONFIG_TOUCHSCREEN_OFFLOAD)
+		ts->offload.coords[t_id].x = ts->coord[t_id].x;
+		ts->offload.coords[t_id].y = ts->coord[t_id].y;
+		ts->offload.coords[t_id].major = ts->coord[t_id].major;
+		ts->offload.coords[t_id].minor = ts->coord[t_id].minor;
+		ts->offload.coords[t_id].pressure = ts->coord[t_id].z;
+		ts->offload.coords[t_id].rotation = 0;
+#endif
+
+		if ((ts->coord[t_id].ttype ==
+		     SEC_TS_TOUCHTYPE_NORMAL) ||
+		    (ts->coord[t_id].ttype ==
+		     SEC_TS_TOUCHTYPE_PALM) ||
+		    (ts->coord[t_id].ttype ==
+		     SEC_TS_TOUCHTYPE_GRIP) ||
+		    (ts->coord[t_id].ttype ==
+		     SEC_TS_TOUCHTYPE_WET) ||
+		    (ts->coord[t_id].ttype ==
+		     SEC_TS_TOUCHTYPE_GLOVE)) {
+
+			if (ts->coord[t_id].action == SEC_TS_COORDINATE_ACTION_RELEASE) {
+				s64 ms_delta;
+
+				ts->coord[t_id].ktime_released = ktime_get();
+				ms_delta = ktime_ms_delta(ts->coord[t_id].ktime_released,
+							ts->coord[t_id].ktime_pressed);
+				if (ts->longest_duration < ms_delta)
+					ts->longest_duration = ms_delta;
+
+				if (ts->touch_count > 0)
+					ts->touch_count--;
+				if (ts->touch_count == 0 ||
+					ts->tid_touch_state == 0) {
+					ts->check_multi = 0;
+				}
+				__clear_bit(t_id, &ts->tid_palm_state);
+				__clear_bit(t_id, &ts->tid_grip_state);
+				__clear_bit(t_id, &ts->tid_touch_state);
+
+#if IS_ENABLED(CONFIG_TOUCHSCREEN_OFFLOAD)
+				ts->offload.coords[t_id].status =
+					COORD_STATUS_INACTIVE;
+				if (!ts->offload.offload_running) {
+#endif
+				input_mt_slot(ts->input_dev, t_id);
+				if (ts->plat_data->support_mt_pressure)
+					input_report_abs(ts->input_dev,
+						ABS_MT_PRESSURE, 0);
+				input_mt_report_slot_state(ts->input_dev,
+					MT_TOOL_FINGER, 0);
+
+				if (ts->touch_count == 0 ||
+					ts->tid_touch_state == 0) {
+					input_report_key(ts->input_dev,
+						BTN_TOUCH, 0);
+					input_report_key(ts->input_dev,
+						BTN_TOOL_FINGER, 0);
+				}
+#if IS_ENABLED(CONFIG_TOUCHSCREEN_OFFLOAD)
+				}
+#endif
+			} else if (ts->coord[t_id].action ==
+					SEC_TS_COORDINATE_ACTION_PRESS) {
+				ts->coord[t_id].ktime_pressed = ktime_get();
+				ts->pressed_count++;
+				ts->touch_count++;
+				if ((ts->touch_count > 4) &&
+					(ts->check_multi == 0)) {
+					ts->check_multi = 1;
+					ts->multi_count++;
+				}
+				ts->all_finger_count++;
+
+				ts->coord[t_id].x_pressed = ts->coord[t_id].x;
+				ts->coord[t_id].y_pressed = ts->coord[t_id].y;
+				ts->max_z_value = max_t(unsigned int,
+							ts->coord[t_id].z,
+							ts->max_z_value);
+				ts->min_z_value = min_t(unsigned int,
+							ts->coord[t_id].z,
+							ts->min_z_value);
+				ts->sum_z_value +=
+						(unsigned int)ts->coord[t_id].z;
+
+				__set_bit(t_id, &ts->tid_touch_state);
+				__clear_bit(t_id, &ts->tid_palm_state);
+				__clear_bit(t_id, &ts->tid_grip_state);
+				if (ts->coord[t_id].palm)
+					__set_bit(t_id, &ts->tid_palm_state);
+				else if (ts->coord[t_id].grip)
+					__set_bit(t_id, &ts->tid_grip_state);
+
+#if IS_ENABLED(CONFIG_TOUCHSCREEN_OFFLOAD)
+				ts->offload.coords[t_id].status =
+					COORD_STATUS_FINGER;
+				if (!ts->offload.offload_running) {
+#endif
+				input_mt_slot(ts->input_dev, t_id);
+				if (ts->coord[t_id].palm)
+					input_mt_report_slot_state(
+						ts->input_dev, MT_TOOL_PALM, 1);
+				else if (ts->coord[t_id].grip)
+					input_mt_report_slot_state(
+						ts->input_dev, MT_TOOL_PALM, 1);
+				else
+					input_mt_report_slot_state(
+						ts->input_dev,
+						MT_TOOL_FINGER, 1);
+
+				input_report_key(ts->input_dev, BTN_TOUCH, 1);
+				input_report_key(ts->input_dev,
+							BTN_TOOL_FINGER, 1);
+
+				input_report_abs(ts->input_dev,
+					ABS_MT_POSITION_X, ts->coord[t_id].x);
+				input_report_abs(ts->input_dev,
+					ABS_MT_POSITION_Y, ts->coord[t_id].y);
+				input_report_abs(ts->input_dev,
+						ABS_MT_TOUCH_MAJOR,
+						ts->coord[t_id].major);
+				input_report_abs(ts->input_dev,
+						ABS_MT_TOUCH_MINOR,
+						ts->coord[t_id].minor);
+#ifdef ABS_MT_CUSTOM
+				if (ts->brush_mode)
+					input_report_abs(ts->input_dev,
+						ABS_MT_CUSTOM,
+						(ts->coord[t_id].z << 1) |
+							ts->coord[t_id].palm);
+				else
+					input_report_abs(ts->input_dev,
+						ABS_MT_CUSTOM,
+						(BRUSH_Z_DATA << 1) |
+							ts->coord[t_id].palm);
+#endif
+				if (ts->plat_data->support_mt_pressure)
+					input_report_abs(ts->input_dev,
+						ABS_MT_PRESSURE,
+						ts->coord[t_id].z);
+
+#if IS_ENABLED(CONFIG_TOUCHSCREEN_OFFLOAD)
+				}
+#endif
+			} else if (ts->coord[t_id].action ==
+					SEC_TS_COORDINATE_ACTION_MOVE) {
+
+				ts->coord[t_id].mcount++;
+
+#ifdef SW_GLOVE
+				if ((ts->coord[t_id].ttype ==
+					SEC_TS_TOUCHTYPE_GLOVE) &&
+				    !ts->touchkey_glove_mode_status) {
+					ts->touchkey_glove_mode_status = true;
+				} else if ((ts->coord[t_id].ttype !=
+						SEC_TS_TOUCHTYPE_GLOVE) &&
+					   ts->touchkey_glove_mode_status) {
+					ts->touchkey_glove_mode_status = false;
+				}
+#endif
+				__set_bit(t_id, &ts->tid_touch_state);
+				__clear_bit(t_id, &ts->tid_palm_state);
+				__clear_bit(t_id, &ts->tid_grip_state);
+				if (ts->coord[t_id].palm)
+					__set_bit(t_id, &ts->tid_palm_state);
+				else if (ts->coord[t_id].grip)
+					__set_bit(t_id, &ts->tid_grip_state);
+#if IS_ENABLED(CONFIG_TOUCHSCREEN_OFFLOAD)
+				ts->offload.coords[t_id].status =
+					COORD_STATUS_FINGER;
+				if (!ts->offload.offload_running) {
+#endif
+#ifdef SW_GLOVE
+				if ((ts->coord[t_id].ttype ==
+					SEC_TS_TOUCHTYPE_GLOVE) &&
+				    !ts->touchkey_glove_mode_status) {
+					input_report_switch(ts->input_dev,
+						SW_GLOVE, 1);
+				} else if ((ts->coord[t_id].ttype !=
+						SEC_TS_TOUCHTYPE_GLOVE) &&
+					   ts->touchkey_glove_mode_status) {
+					input_report_switch(ts->input_dev,
+						SW_GLOVE, 0);
+				}
+#endif
+				input_mt_slot(ts->input_dev, t_id);
+				if (ts->coord[t_id].palm)
+					input_mt_report_slot_state(
+						ts->input_dev, MT_TOOL_PALM, 1);
+				else if (ts->coord[t_id].grip)
+					input_mt_report_slot_state(
+						ts->input_dev, MT_TOOL_PALM, 1);
+				else
+					input_mt_report_slot_state(
+						ts->input_dev,
+						MT_TOOL_FINGER, 1);
+
+				input_report_key(ts->input_dev, BTN_TOUCH, 1);
+				input_report_key(ts->input_dev,
+							BTN_TOOL_FINGER, 1);
+
+				input_report_abs(ts->input_dev,
+					ABS_MT_POSITION_X, ts->coord[t_id].x);
+				input_report_abs(ts->input_dev,
+					ABS_MT_POSITION_Y, ts->coord[t_id].y);
+				input_report_abs(ts->input_dev,
+						ABS_MT_TOUCH_MAJOR,
+						ts->coord[t_id].major);
+				input_report_abs(ts->input_dev,
+						ABS_MT_TOUCH_MINOR,
+						ts->coord[t_id].minor);
+#ifdef ABS_MT_CUSTOM
+				if (ts->brush_mode)
+					input_report_abs(ts->input_dev,
+						ABS_MT_CUSTOM,
+						(ts->coord[t_id].z << 1) |
+							ts->coord[t_id].palm);
+				else
+					input_report_abs(ts->input_dev,
+						ABS_MT_CUSTOM,
+						(BRUSH_Z_DATA << 1) |
+							ts->coord[t_id].palm);
+#endif
+				if (ts->plat_data->support_mt_pressure)
+					input_report_abs(ts->input_dev,
+							ABS_MT_PRESSURE,
+							ts->coord[t_id].z);
+#if IS_ENABLED(CONFIG_TOUCHSCREEN_OFFLOAD)
+				}
+#endif
+			} else
+				input_dbg(true, &ts->client->dev,
+					"%s: do not support coordinate action(%d)\n",
+					__func__, ts->coord[t_id].action);
+		} else
+			input_dbg(true, &ts->client->dev,
+				"%s: do not support coordinate type(%d)\n",
+				__func__, ts->coord[t_id].ttype);
+	} else
+		input_err(true, &ts->client->dev,
+				"%s: tid(%d) is out of range\n",
+				__func__, t_id);
+
+	if (t_id < MAX_SUPPORT_TOUCH_COUNT + MAX_SUPPORT_HOVER_COUNT) {
+
+		if (ts->coord[t_id].action == SEC_TS_COORDINATE_ACTION_PRESS) {
+			input_dbg(false, &ts->client->dev,
+				"%s[P] tID: %d x: %d y: %d z: %d major: %d minor: %d tc: %u type: %X\n",
+				ts->dex_name,
+				t_id, ts->coord[t_id].x,
+				ts->coord[t_id].y, ts->coord[t_id].z,
+				ts->coord[t_id].major,
+				ts->coord[t_id].minor,
+				ts->touch_count,
+				ts->coord[t_id].ttype);
+
+		} else if (ts->coord[t_id].action ==
+			   SEC_TS_COORDINATE_ACTION_RELEASE) {
+			sec_ts_kfifo_push_coord(ts, t_id);
+			input_dbg(false, &ts->client->dev,
+				"%s[R] tID: %d mc: %d tc: %u lx: %d ly: %d v: %02X%02X cal: %02X(%02X) id(%d,%d)\n",
+				ts->dex_name,
+				t_id, ts->coord[t_id].mcount,
+				ts->touch_count,
+				ts->coord[t_id].x, ts->coord[t_id].y,
+				ts->plat_data->img_version_of_ic[2],
+				ts->plat_data->img_version_of_ic[3],
+				ts->cal_status, ts->nv, ts->tspid_val,
+				ts->tspicid_val);
+
+			ts->coord[t_id].mcount = 0;
+		}
+	}
+}
+
+#ifdef SEC_TS_SUPPORT_CUSTOMLIB
+static void sec_ts_handle_gesture_event(struct sec_ts_data *ts,
+				struct sec_ts_gesture_status *p_gesture_status)
+{
+	if ((p_gesture_status->eid == 0x02) &&
+	    (p_gesture_status->stype == 0x00)) {
+		u8 customlib[3] = { 0 };
+
+		ret = sec_ts_read_from_customlib(ts, customlib, 3);
+		if (ret < 0)
+			input_err(true, &ts->client->dev,
+				"%s: fail to read custom library data\n",
+				__func__);
+
+		input_info(true, &ts->client->dev,
+			"%s: Custom Library, %x, %x, %x\n",
+			__func__, customlib[0], customlib[1], customlib[2]);
+
+		if (p_gesture_status->gesture_id == SEC_TS_GESTURE_CODE_SPAY ||
+		    p_gesture_status->gesture_id ==
+			SEC_TS_GESTURE_CODE_DOUBLE_TAP) {
+			/* will be fixed to data structure */
+			if (customlib[1] & SEC_TS_MODE_CUSTOMLIB_AOD) {
+				u8 data[5] = { 0x0A, 0x00, 0x00, 0x00, 0x00 };
+
+				ret = sec_ts_read_from_customlib(ts, data, 5);
+				if (ret < 0)
+					input_err(true, &ts->client->dev,
+						"%s: fail to read custom library data\n",
+						__func__);
+
+				if (data[4] & SEC_TS_AOD_GESTURE_DOUBLETAB)
+					ts->scrub_id =
+					CUSTOMLIB_EVENT_TYPE_AOD_DOUBLETAB;
+
+				ts->scrub_x = (data[1] & 0xFF) << 8 |
+						(data[0] & 0xFF);
+				ts->scrub_y = (data[3] & 0xFF) << 8 |
+						(data[2] & 0xFF);
+				input_info(true, &ts->client->dev,
+					"%s: aod: %d\n",
+					__func__, ts->scrub_id);
+				ts->all_aod_tap_count++;
+			}
+			if (customlib[1] & SEC_TS_MODE_CUSTOMLIB_SPAY) {
+				ts->scrub_id = CUSTOMLIB_EVENT_TYPE_SPAY;
+				input_info(true, &ts->client->dev,
+					"%s: SPAY: %d\n",
+					__func__, ts->scrub_id);
+				ts->all_spay_count++;
+			}
+			input_report_key(ts->input_dev,
+					 KEY_BLACK_UI_GESTURE, 1);
+			input_sync(ts->input_dev);
+			input_report_key(ts->input_dev,
+					 KEY_BLACK_UI_GESTURE, 0);
+		}
+	}
+}
+#endif
+
+#if IS_ENABLED(CONFIG_TOUCHSCREEN_OFFLOAD)
+
+static void sec_ts_populate_coordinate_channel(struct sec_ts_data *ts,
+					struct touch_offload_frame *frame,
+					int channel)
+{
+	int j;
+
+	struct TouchOffloadDataCoord *dc =
+		(struct TouchOffloadDataCoord *)frame->channel_data[channel];
+	memset(dc, 0, frame->channel_data_size[channel]);
+	dc->header.channel_type = TOUCH_DATA_TYPE_COORD;
+	dc->header.channel_size = TOUCH_OFFLOAD_FRAME_SIZE_COORD;
+
+	for (j = 0; j < MAX_COORDS; j++) {
+		dc->coords[j].x = ts->offload.coords[j].x;
+		dc->coords[j].y = ts->offload.coords[j].y;
+		dc->coords[j].major = ts->offload.coords[j].major;
+		dc->coords[j].minor = ts->offload.coords[j].minor;
+		dc->coords[j].pressure = ts->offload.coords[j].pressure;
+		dc->coords[j].rotation = ts->offload.coords[j].rotation;
+		dc->coords[j].status = ts->offload.coords[j].status;
+	}
+}
+
+static void sec_ts_update_v4l2_mutual_strength(struct sec_ts_data *ts,
+					       uint32_t size_x,
+					       uint32_t size_y,
+					       int16_t *heatmap)
+{
+	if (!ts->mutual_strength_heatmap.data) {
+		ts->mutual_strength_heatmap.data = devm_kmalloc(
+			&ts->client->dev, size_x * size_y * 2, GFP_KERNEL);
+		if (!ts->mutual_strength_heatmap.data) {
+			input_err(true, &ts->client->dev,
+				  "%s: kmalloc for mutual_strength_heatmap (%d) failed.\n",
+				  __func__, size_x * size_y * 2);
+		} else {
+			ts->mutual_strength_heatmap.size_x = size_x;
+			ts->mutual_strength_heatmap.size_y = size_y;
+			input_info(true, &ts->client->dev,
+				   "%s: kmalloc for mutual_strength_heatmap (%d).\n",
+				   __func__, size_x * size_y * 2);
+		}
+	}
+
+	if (ts->mutual_strength_heatmap.data) {
+		if (ts->mutual_strength_heatmap.size_x == size_x &&
+		    ts->mutual_strength_heatmap.size_y == size_y) {
+			memcpy(ts->mutual_strength_heatmap.data,
+			       heatmap, size_x * size_y * 2);
+			ts->mutual_strength_heatmap.timestamp =
+				ts->timestamp;
+			ts->v4l2_mutual_strength_updated = true;
+		} else {
+			input_info(true, &ts->client->dev,
+				   "%s: unmatched heatmap size (%d,%d) (%d,%d).\n",
+				   __func__, size_x, size_y,
+				   ts->mutual_strength_heatmap.size_x,
+				   ts->mutual_strength_heatmap.size_y);
+		}
+	}
+}
+
+#define PTFLIB_ENCODED_COUNTER_OFFSET		0x00A8
+#define PTFLIB_ENCODED_COUNTER_READ_SIZE	6
+#define PTFLIB_ENCODED_DATA_READ_SIZE		338
+static int sec_ts_populate_encoded_channel(struct sec_ts_data *ts,
+					   struct touch_offload_frame *frame,
+					   int channel)
+{
+	u32 heatmap_array_len = 0;
+	u32 decoded_size = 0;
+	u32 encoded_counter = 0;
+	u16 read_src_offset = 0;
+	int read_src_size = 0;
+	u8 *r_data;
+	u16 encoded_data_size = 0;
+	u16 first_word = 0;
+	int i;
+	int x;
+	int y;
+	int ret = 0;
+	ktime_t timestamp_read_start;
+	ktime_t timestamp_read_end;
+	struct TouchOffloadData2d *mutual_strength =
+		(struct TouchOffloadData2d *)frame->channel_data[channel];
+
+	mutual_strength->tx_size = ts->tx_count;
+	mutual_strength->rx_size = ts->rx_count;
+	mutual_strength->header.channel_type = frame->channel_type[channel];
+	mutual_strength->header.channel_size =
+		TOUCH_OFFLOAD_FRAME_SIZE_2D(mutual_strength->rx_size,
+					    mutual_strength->tx_size);
+	heatmap_array_len = ts->tx_count * ts->rx_count;
+
+	if (!ts->encoded_buff) {
+		ts->encoded_buff = kmalloc(
+		    heatmap_array_len * 2 + PTFLIB_ENCODED_COUNTER_READ_SIZE,
+		    GFP_KERNEL);
+		if (!ts->encoded_buff) {
+			input_err(true, &ts->client->dev,
+				  "%s: kmalloc for encoded_buff failed.\n",
+				  __func__);
+			return -ENOMEM;
+		}
+	}
+
+	/* Read encoded heatmap from customlib. */
+	read_src_offset = PTFLIB_ENCODED_COUNTER_OFFSET;
+	read_src_size = PTFLIB_ENCODED_COUNTER_READ_SIZE +
+	    PTFLIB_ENCODED_DATA_READ_SIZE;
+	r_data = (u8 *) ts->encoded_buff;
+	r_data[0] = read_src_offset & 0xFF;
+	r_data[1] = (read_src_offset >> 8) & 0xFF;
+	timestamp_read_start = ktime_get();
+	ret = sec_ts_read_from_customlib(ts, r_data, read_src_size);
+	if (ret < 0) {
+		input_err(true, &ts->client->dev,
+			  "%s: Read customlib failed, offset(0x%04X)) size(%d)\n",
+			  __func__, read_src_offset, read_src_size);
+		return -EIO;
+	}
+	timestamp_read_end = ktime_get();
+
+	encoded_counter = le32_to_cpup((uint32_t *) r_data);
+	encoded_data_size = le16_to_cpup((uint16_t *) &r_data[4]);
+	first_word = le16_to_cpup((uint16_t *) &r_data[6]);
+
+	if (encoded_counter == 0 || encoded_data_size == 0 ||
+	    first_word == 0x8FFF ||
+	    encoded_data_size > PTFLIB_ENCODED_DATA_READ_SIZE) {
+		decoded_size = 0;
+	} else {
+		decoded_size = sec_ts_ptflib_decoder(ts, (u16 *) (r_data + 6),
+						     encoded_data_size / 2,
+						     (u16 *) ts->heatmap_buff,
+						     heatmap_array_len);
+	}
+
+	ts->plat_data->encoded_frame_counter++;
+	if (decoded_size != heatmap_array_len) {
+		ts->plat_data->encoded_skip_counter++;
+		input_info(true, &ts->client->dev,
+			  "%s: %d (%d,0x%04X,0x%04X,%d) ts(%lld,%lld)\n",
+			  __func__, encoded_counter,
+			  encoded_data_size & 0x0FFF, encoded_data_size,
+			  first_word, decoded_size,
+			  ktime_us_delta(timestamp_read_start, ts->timestamp),
+			  ktime_us_delta(timestamp_read_end,
+					 timestamp_read_start));
+		return -EIO;
+	}
+
+	i = 0;
+	for (y = mutual_strength->rx_size - 1; y >= 0; y--)
+		for (x = mutual_strength->tx_size - 1; x >= 0; x--)
+			((uint16_t *) mutual_strength->data)[i++] =
+			    ts->heatmap_buff[x * mutual_strength->rx_size + y];
+
+	sec_ts_update_v4l2_mutual_strength(ts, mutual_strength->tx_size,
+					   mutual_strength->rx_size,
+					   (int16_t *) mutual_strength->data);
+
+	return 0;
+}
+
+static void sec_ts_populate_mutual_channel(struct sec_ts_data *ts,
+					struct touch_offload_frame *frame,
+					int channel)
+{
+	uint32_t frame_index = 0;
+	int32_t x, y;
+	uint16_t heatmap_value;
+	int ret = 0;
+	u8 target_data_type, type;
+	struct TouchOffloadData2d *mutual_strength =
+		(struct TouchOffloadData2d *)frame->channel_data[channel];
+
+	switch (frame->channel_type[channel] & ~TOUCH_SCAN_TYPE_MUTUAL) {
+	case TOUCH_DATA_TYPE_RAW:
+		target_data_type = TYPE_DECODED_DATA;
+		break;
+	case TOUCH_DATA_TYPE_FILTERED:
+		target_data_type = TYPE_REMV_AMB_DATA;
+		break;
+	case TOUCH_DATA_TYPE_STRENGTH:
+		target_data_type = TYPE_SIGNAL_DATA;
+		break;
+	case TOUCH_DATA_TYPE_BASELINE:
+		target_data_type = TYPE_AMBIENT_DATA;
+		break;
+	}
+
+	mutual_strength->tx_size = ts->tx_count;
+	mutual_strength->rx_size = ts->rx_count;
+	mutual_strength->header.channel_type = frame->channel_type[channel];
+	mutual_strength->header.channel_size =
+		TOUCH_OFFLOAD_FRAME_SIZE_2D(mutual_strength->rx_size,
+					    mutual_strength->tx_size);
+
+	ret = sec_ts_read(ts,
+		SEC_TS_CMD_MUTU_RAW_TYPE, &ts->ms_frame_type, 1);
+	if (ret < 0) {
+		input_err(true, &ts->client->dev,
+			"%s: read rawdata type failed\n",
+			__func__);
+		return;
+	}
+
+	/* Check raw type is correct */
+	if (ts->ms_frame_type != target_data_type) {
+		input_info(true, &ts->client->dev,
+			"%s: ms_frame_type change from %#x\n",
+			__func__, ts->ms_frame_type);
+
+		/* Check raw type is TYPE_INVALID_DATA */
+		if (ts->ms_frame_type != TYPE_INVALID_DATA) {
+			type = TYPE_INVALID_DATA;
+			ret = sec_ts_write(ts,
+				SEC_TS_CMD_MUTU_RAW_TYPE, &type, 1);
+			if (ret < 0) {
+				input_err(true, &ts->client->dev,
+					"%s: recover rawdata type failed\n",
+					__func__);
+				return;
+			}
+			ts->ms_frame_type = type;
+		}
+
+		/* Set the targeted data type */
+		ret = sec_ts_write(ts, SEC_TS_CMD_MUTU_RAW_TYPE,
+			&target_data_type, 1);
+		if (ret < 0) {
+			input_err(true, &ts->client->dev,
+				"%s: Set rawdata type failed\n",
+				__func__);
+			return;
+		}
+		ts->ms_frame_type = target_data_type;
+
+		/*
+		 * If raw type change, need to wait 50 ms to read data
+		 * back. But, we don't wanto to wait here to cause
+		 * overhead. Just drop this and wait for next reading.
+		 */
+
+		return;
+	}
+
+	ret = sec_ts_read_heap(ts, SEC_TS_READ_TOUCH_RAWDATA,
+		(u8 *)ts->heatmap_buff,
+		mutual_strength->header.channel_size);
+	if (ret < 0) {
+		input_err(true, &ts->client->dev,
+			"%s: Read mutual frame failed\n", __func__);
+		return;
+	}
+
+	for (y = mutual_strength->rx_size - 1; y >= 0; y--) {
+		for (x = mutual_strength->tx_size - 1; x >= 0; x--) {
+			heatmap_value =
+			    ts->heatmap_buff[x * mutual_strength->rx_size + y];
+			((uint16_t *)
+			 mutual_strength->data)[frame_index++] =
+			    be16_to_cpu(heatmap_value);
+		}
+	}
+
+	if (target_data_type == TYPE_SIGNAL_DATA) {
+		sec_ts_update_v4l2_mutual_strength(ts,
+		    mutual_strength->tx_size, mutual_strength->rx_size,
+		    (int16_t *) mutual_strength->data);
+	}
+}
+
+static void sec_ts_populate_self_channel(struct sec_ts_data *ts,
+					struct touch_offload_frame *frame,
+					int channel)
+{
+	uint32_t frame_index = 0;
+	int32_t x, y;
+	uint16_t heatmap_value;
+	int ret = 0;
+	u8 target_data_type, type;
+	struct TouchOffloadData1d *self_strength =
+		(struct TouchOffloadData1d *)frame->channel_data[channel];
+
+	switch (frame->channel_type[channel] & ~TOUCH_SCAN_TYPE_SELF) {
+	case TOUCH_DATA_TYPE_RAW:
+		target_data_type = TYPE_DECODED_DATA;
+		break;
+	case TOUCH_DATA_TYPE_FILTERED:
+		target_data_type = TYPE_REMV_AMB_DATA;
+		break;
+	case TOUCH_DATA_TYPE_STRENGTH:
+		target_data_type = TYPE_SIGNAL_DATA;
+		break;
+	case TOUCH_DATA_TYPE_BASELINE:
+		target_data_type = TYPE_AMBIENT_DATA;
+		break;
+	}
+
+	self_strength->tx_size = ts->tx_count;
+	self_strength->rx_size = ts->rx_count;
+	self_strength->header.channel_type = frame->channel_type[channel];
+	self_strength->header.channel_size =
+		TOUCH_OFFLOAD_FRAME_SIZE_1D(self_strength->rx_size,
+					    self_strength->tx_size);
+
+	ret = sec_ts_read(ts,
+		SEC_TS_CMD_SELF_RAW_TYPE, &ts->ss_frame_type, 1);
+	if (ret < 0) {
+		input_err(true, &ts->client->dev,
+			"%s: read rawdata type failed\n",
+			__func__);
+		return;
+	}
+
+	/* Check raw type is TYPE_SIGNAL_DATA */
+	if (ts->ss_frame_type != target_data_type) {
+		input_info(true, &ts->client->dev,
+			"%s: ss_frame_type change from %#x\n",
+			__func__, ts->ss_frame_type);
+
+		/* Check raw type is TYPE_INVALID_DATA */
+		if (ts->ss_frame_type != TYPE_INVALID_DATA) {
+			type = TYPE_INVALID_DATA;
+			ret = sec_ts_write(ts,
+				SEC_TS_CMD_SELF_RAW_TYPE, &type, 1);
+			if (ret < 0) {
+				input_err(true, &ts->client->dev,
+					"%s: recover rawdata type failed\n",
+					__func__);
+				return;
+			}
+			ts->ss_frame_type = type;
+		}
+
+		/* Set the targeted data type */
+		ret = sec_ts_write(ts, SEC_TS_CMD_SELF_RAW_TYPE,
+			&target_data_type, 1);
+		if (ret < 0) {
+			input_err(true, &ts->client->dev,
+				"%s: Set rawdata type failed\n",
+				__func__);
+			return;
+		}
+		ts->ss_frame_type = target_data_type;
+
+		/*
+		 * If raw type change, need to wait 50 ms to read data
+		 * back. But, we don't wanto to wait here to cause
+		 * overhead. Just drop this and wait for next reading.
+		 */
+
+		return;
+	}
+
+	ret = sec_ts_read_heap(ts, SEC_TS_READ_TOUCH_SELF_RAWDATA,
+		(u8 *)ts->heatmap_buff,
+		self_strength->header.channel_size);
+	if (ret < 0) {
+		input_err(true, &ts->client->dev,
+			"%s: Read self frame failed\n", __func__);
+		return;
+	}
+
+	for (x = self_strength->tx_size - 1; x >= 0; x--) {
+		heatmap_value = ts->heatmap_buff[x];
+		((uint16_t *)
+		 self_strength->data)[frame_index++] =
+		    be16_to_cpu(heatmap_value);
+	}
+	for (y = self_strength->rx_size - 1; y >= 0; y--) {
+		heatmap_value = ts->heatmap_buff[self_strength->tx_size + y];
+		((uint16_t *)
+		 self_strength->data)[frame_index++] =
+		    be16_to_cpu(heatmap_value);
+	}
+}
+
+static void sec_ts_populate_driver_status_channel(struct sec_ts_data *ts,
+					struct touch_offload_frame *frame,
+					int channel)
+{
+	struct TouchOffloadDriverStatus *ds =
+		(struct TouchOffloadDriverStatus *)frame->channel_data[channel];
+	memset(ds, 0, frame->channel_data_size[channel]);
+	ds->header.channel_type = (u32)CONTEXT_CHANNEL_TYPE_DRIVER_STATUS;
+	ds->header.channel_size = sizeof(struct TouchOffloadDriverStatus);
+
+	ds->contents.screen_state = 1;
+	ds->screen_state = (ts->power_status == SEC_TS_STATE_POWER_ON) ? 1 : 0;
+
+	ds->display_refresh_rate = ts->display_refresh_rate;
+	ds->contents.display_refresh_rate = 1;
+}
+
+static void sec_ts_populate_frame(struct sec_ts_data *ts,
+				struct touch_offload_frame *frame)
+{
+	static u64 index;
+	int i;
+	int retval = -1;
+	const struct sec_ts_plat_data *pdata = ts->plat_data;
+
+	frame->header.index = index++;
+	frame->header.timestamp = ts->timestamp;
+
+	if (!ts->heatmap_buff) {
+		ts->heatmap_buff = kmalloc(
+			ts->rx_count * ts->rx_count * 2, GFP_KERNEL);
+	}
+
+	/* Populate all channels */
+	for (i = 0; i < frame->num_channels; i++) {
+		u8 channel_type = frame->channel_type[i];
+
+		if (channel_type == TOUCH_DATA_TYPE_COORD) {
+			sec_ts_populate_coordinate_channel(ts, frame, i);
+		} else if ((channel_type & TOUCH_SCAN_TYPE_MUTUAL) != 0) {
+			if ((pdata->encoded_enable == ENCODED_ENABLE_ON) &&
+			    ((channel_type & ~TOUCH_SCAN_TYPE_MUTUAL) ==
+			    TOUCH_DATA_TYPE_STRENGTH))
+				retval = sec_ts_populate_encoded_channel(
+				    ts, frame, i);
+			if (retval < 0)
+				sec_ts_populate_mutual_channel(ts, frame, i);
+		} else if ((channel_type & TOUCH_SCAN_TYPE_SELF) != 0) {
+			sec_ts_populate_self_channel(ts, frame, i);
+		} else if ((frame->channel_type[i] ==
+			    CONTEXT_CHANNEL_TYPE_DRIVER_STATUS) != 0)
+			sec_ts_populate_driver_status_channel(ts, frame, i);
+		else if ((frame->channel_type[i] ==
+			  CONTEXT_CHANNEL_TYPE_STYLUS_STATUS) != 0) {
+			/* Stylus context is not required by this driver */
+			input_err(true, &ts->client->dev,
+				  "%s: Driver does not support stylus status",
+				  __func__);
+		}
+	}
+}
+
+void sec_ts_enable_ptflib(struct sec_ts_data *ts, bool enable)
+{
+	struct sec_ts_plat_data *pdata = ts->plat_data;
+
+	input_info(true, &ts->client->dev,
+		"%s: enable %d.\n", __func__, enable);
+
+	if (enable) {
+		sec_ts_ptflib_reinit(ts);
+		if (pdata->grip_prescreen_mode == GRIP_PRESCREEN_MODE_2) {
+			sec_ts_ptflib_grip_prescreen_timeout(ts,
+				pdata->grip_prescreen_timeout);
+		}
+		sec_ts_ptflib_grip_prescreen_enable(ts,
+			pdata->grip_prescreen_mode);
+	} else {
+		sec_ts_ptflib_grip_prescreen_enable(ts, GRIP_PRESCREEN_OFF);
+	}
+}
+
+int sec_ts_enable_fw_grip(struct sec_ts_data *ts, bool enable)
+{
+	struct sec_ts_plat_data *pdata = ts->plat_data;
+	u8 value;
+	int ret;
+	int final_result = 0;
+
+	input_info(true, &ts->client->dev,
+		"%s: enable %d.\n", __func__, enable);
+
+	/* Set grip */
+	value = enable ? 0x1F : 0;
+	ret = ts->sec_ts_write(ts, SEC_TS_CMD_SET_GRIP_DETEC, &value, 1);
+	if (ret < 0) {
+		input_err(true, &ts->client->dev,
+			 "%s: SEC_TS_CMD_SET_GRIP_DETEC failed with ret=%d\n",
+			__func__, ret);
+		final_result = ret;
+	} else {
+		/* Configure grip */
+		if (enable) {
+			u8 mm = 10;
+			u8 px_lo = (mm * pdata->mm2px) & 0xFF;
+			u8 px_hi = ((mm * pdata->mm2px) >> 8) & 0xFF;
+			u8 long_press_zone[10] = {0x02, 0x00,	/* long press reject zone type */
+						px_hi, px_lo,	/* left edge */
+						0x00, 0x00,	/* top edge */
+						px_hi, px_lo,	/* right edge */
+						0x00, 0x00};	/* bottom edge */
+			ret = ts->sec_ts_write(ts, SEC_TS_CMD_LONGPRESS_DROP_AREA,
+					long_press_zone, sizeof(long_press_zone));
+			if (ret < 0) {
+				input_err(true, &ts->client->dev,
+					"%s: SEC_TS_CMD_LONGPRESS_DROP_AREA failed with ret=%d\n",
+					__func__, ret);
+			}
+		}
+	}
+
+	return final_result;
+}
+
+static void sec_ts_offload_set_running(struct sec_ts_data *ts, bool running)
+{
+	if (ts->offload.offload_running != running) {
+		ts->offload.offload_running = running;
+		if (running && ts->offload.config.filter_grip) {
+			sec_ts_enable_fw_grip(ts, false);
+			sec_ts_enable_ptflib(ts, true);
+		} else {
+			sec_ts_enable_fw_grip(ts, true);
+			sec_ts_enable_ptflib(ts, false);
+		}
+	}
+}
+
+#endif /* CONFIG_TOUCHSCREEN_OFFLOAD */
+
+#define FOD_CANCEL_EVENT_DELTA_TIME 500
+static void sec_ts_handle_fod_event(struct sec_ts_data *ts,
+					struct sec_ts_event_status *p_event_status)
+{
+	struct sec_ts_fod_event *p_fod =
+				(struct sec_ts_fod_event *)p_event_status;
+	int x = p_fod->x_b11_b8 << 8 | p_fod->x_b7_b0;
+	int y = p_fod->y_b11_b8 << 8 | p_fod->y_b7_b0;
+	s64 delta_ms = ktime_ms_delta(ktime_get(), ts->ktime_resume);
+
+	if (test_bit(0, &ts->tid_touch_state)) {
+		input_info(true, &ts->client->dev,
+			   "%s: slot 0 is in use!", __func__);
+		return;
+	}
+
+	if (!x || !y) {
+		input_info(true, &ts->client->dev,
+			   "%s: one of coords is ZERO(%d, %d)!",
+			   __func__, x, y);
+		x = ts->plat_data->fod_x;
+		y = ts->plat_data->fod_y;
+	}
+
+	input_info(true, &ts->client->dev,
+		   "STATUS: FoD: %s, X,Y: %d, %d\n", p_fod->status ? "ON" : "OFF", x, y);
+	/*
+	 * Send input cancel event to tunr off HBM if the following conditions match:
+	 * 1. FoD status is off.
+	 * 2. FoD event is before the time of (driver reusme + FOD_CANCEL_EVENT_DELTA_TIME).
+	 */
+	if (p_fod->status == false && delta_ms < FOD_CANCEL_EVENT_DELTA_TIME) {
+		input_info(true, &ts->client->dev, "FoD: send input cancel event.\n");
+		mutex_lock(&ts->eventlock);
+		input_mt_slot(ts->input_dev, 0);
+		input_report_key(ts->input_dev, BTN_TOUCH, 1);
+		input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, 1);
+		input_report_abs(ts->input_dev, ABS_MT_POSITION_X, x);
+		input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, y);
+		input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, 140);
+		input_report_abs(ts->input_dev, ABS_MT_TOUCH_MINOR, 140);
+		input_report_abs(ts->input_dev, ABS_MT_PRESSURE, 1);
+		input_sync(ts->input_dev);
+
+		/* Report MT_TOOL_PALM for canceling the touch event. */
+		input_mt_slot(ts->input_dev, 0);
+		input_report_key(ts->input_dev, BTN_TOUCH, 1);
+		input_mt_report_slot_state(ts->input_dev, MT_TOOL_PALM, 1);
+		input_sync(ts->input_dev);
+
+		/* Release slot 0. */
+		input_mt_slot(ts->input_dev, 0);
+		input_report_abs(ts->input_dev, ABS_MT_PRESSURE, 0);
+		input_mt_report_slot_state(ts->input_dev,
+					   MT_TOOL_FINGER, 0);
+		input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID, -1);
+		input_report_key(ts->input_dev, BTN_TOUCH, 0);
+		input_sync(ts->input_dev);
+		mutex_unlock(&ts->eventlock);
+	}
+}
+
+static void sec_ts_read_vendor_event(struct sec_ts_data *ts,
+					struct sec_ts_event_status *p_event_status)
+{
+	if (p_event_status->stype ==
+		TYPE_STATUS_EVENT_VENDOR_INFO) {
+
+		struct sec_ts_event_hopping *p_hopping_event;
+
+		u8 status_id =
+			p_event_status->status_id;
+		u8 status_data_1 =
+			p_event_status->status_data_1;
+		u8 status_data_2 =
+			p_event_status->status_data_2;
+
+		switch (status_id) {
+		case SEC_TS_EVENT_STATUS_ID_HOPPING:
+			p_hopping_event =
+				(struct sec_ts_event_hopping *)p_event_status;
+
+			input_info(true,
+				&ts->client->dev,
+				"STATUS: hopping %d -> %d by %d with lvl %#x %#x\n",
+					p_hopping_event->prev_id,
+					p_hopping_event->id,
+					p_hopping_event->cause,
+					p_hopping_event->noise_lvl[0],
+					p_hopping_event->noise_lvl[1]);
+			break;
+
+		case SEC_TS_EVENT_STATUS_ID_REPORT_RATE:
+			ts->report_rate = status_data_1;
+			if (ts->debug_status)
+				input_info(true,
+					&ts->client->dev,
+					"STATUS: rate %d -> %d\n",
+					status_data_2, status_data_1);
+			break;
+
+		case SEC_TS_EVENT_STATUS_ID_VSYNC:
+			ts->vsync = status_data_1;
+			if (ts->debug_status)
+				input_info(true,
+					&ts->client->dev,
+					"STATUS: vsync %d -> %d\n",
+					status_data_2, status_data_1);
+			break;
+
+		case SEC_TS_EVENT_STATUS_ID_WLC:
+			input_info(true,
+				&ts->client->dev,
+				"STATUS: WLC: %#x\n",
+				status_data_1);
+			break;
+
+		case SEC_TS_EVENT_STATUS_ID_NOISE:
+			input_info(true,
+				&ts->client->dev,
+				"STATUS: noise: %#x\n",
+				status_data_1);
+			break;
+
+		case SEC_TS_EVENT_STATUS_ID_GRIP:
+			if (ts->debug_status)
+				input_info(true,
+					&ts->client->dev,
+					"STATUS: grip: %d.\n",
+					status_data_1);
+			break;
+
+		case SEC_TS_EVENT_STATUS_ID_PALM:
+			input_info(true, &ts->client->dev,
+				"STATUS: palm: %d.\n",
+				status_data_1);
+				if (status_data_1)
+					ts->palm_count++;
+			break;
+
+		case SEC_TS_EVENT_STATUS_ID_FOD:
+			sec_ts_handle_fod_event(ts, p_event_status);
+			break;
+
+		default:
+			break;
+		}
+	} else {
+		input_info(true, &ts->client->dev,
+				"STATUS: %#x %#x %#x %#x %#x %#x %#x %#x\n",
+				p_event_status->data[0],
+				p_event_status->data[1],
+				p_event_status->data[2],
+				p_event_status->data[3],
+				p_event_status->data[4],
+				p_event_status->data[5],
+				p_event_status->data[6],
+				p_event_status->data[7]);
+	}
+}
+
+#define MAX_EVENT_COUNT 32
+static void sec_ts_read_event(struct sec_ts_data *ts)
+{
+	int ret;
+	u8 event_id;
+	u8 left_event_count;
+	u8 read_event_buff[MAX_EVENT_COUNT][SEC_TS_EVENT_BUFF_SIZE] = { { 0 } };
+	u8 *event_buff;
+	struct sec_ts_gesture_status *p_gesture_status;
+	struct sec_ts_event_status *p_event_status;
+	int curr_pos;
+	int remain_event_count = 0;
+	bool processed_pointer_event = false;
+#if IS_ENABLED(CONFIG_TOUCHSCREEN_HEATMAP)
+	unsigned long last_tid_palm_state = ts->tid_palm_state;
+	unsigned long last_tid_grip_state = ts->tid_grip_state;
+#endif
+#if IS_ENABLED(CONFIG_TOUCHSCREEN_OFFLOAD)
+	struct touch_offload_frame *frame = NULL;
+#endif
+	struct sec_ts_health_check hc[1] = {0};
+
+	if (ts->power_status == SEC_TS_STATE_LPM) {
+
+		pm_wakeup_event(&ts->client->dev, 3 * MSEC_PER_SEC);
+		/* waiting for blsp block resuming, if not occurs error */
+		ret = wait_for_completion_interruptible_timeout(
+				&ts->resume_done,
+				msecs_to_jiffies(3 * MSEC_PER_SEC));
+		if (ret == 0) {
+			input_err(true, &ts->client->dev,
+				  "%s: LPM: pm resume is not handled\n",
+				  __func__);
+			return;
+		}
+
+		if (ret < 0) {
+			input_err(true, &ts->client->dev,
+				  "%s: LPM: -ERESTARTSYS if interrupted, %d\n",
+				  __func__, ret);
+			return;
+		}
+
+		input_info(true, &ts->client->dev,
+			"%s: run LPM interrupt handler, %d\n", __func__, ret);
+		/* run lpm interrupt handler */
+	}
+
+	ret = event_id = curr_pos = remain_event_count = 0;
+	/* repeat READ_ONE_EVENT until buffer is empty(No event) */
+	ret = sec_ts_read(ts, SEC_TS_READ_ONE_EVENT,
+			  (u8 *)read_event_buff[0], SEC_TS_EVENT_BUFF_SIZE);
+	if (ret < 0) {
+		input_err(true, &ts->client->dev,
+			  "%s: read one event failed\n", __func__);
+		return;
+	}
+
+	if (ts->debug_events)
+		input_info(true, &ts->client->dev,
+			"ONE: %02X %02X %02X %02X %02X %02X %02X %02X\n",
+			read_event_buff[0][0], read_event_buff[0][1],
+			read_event_buff[0][2], read_event_buff[0][3],
+			read_event_buff[0][4], read_event_buff[0][5],
+			read_event_buff[0][6], read_event_buff[0][7]);
+
+	if (read_event_buff[0][0] == 0) {
+		input_info(true, &ts->client->dev,
+			"%s: event buffer is empty\n", __func__);
+		return;
+	}
+
+	left_event_count = read_event_buff[0][7] & 0x3F;
+	remain_event_count = left_event_count;
+
+	if (left_event_count > MAX_EVENT_COUNT - 1 ||
+		left_event_count == 0xFF) {
+		input_err(true, &ts->client->dev,
+			"%s: event buffer overflow %d\n",
+			__func__, left_event_count);
+
+		/* write clear event stack command
+		 * when read_event_count > MAX_EVENT_COUNT
+		 **/
+		ret = sec_ts_write(ts, SEC_TS_CMD_CLEAR_EVENT_STACK, NULL, 0);
+		if (ret < 0)
+			input_err(true, &ts->client->dev,
+				  "%s: write clear event failed\n", __func__);
+		return;
+	}
+
+	if (left_event_count > 0) {
+		ret = sec_ts_read(ts, SEC_TS_READ_ALL_EVENT,
+			(u8 *)read_event_buff[1],
+			sizeof(u8) * (SEC_TS_EVENT_BUFF_SIZE) *
+				(left_event_count));
+		if (ret < 0) {
+			input_err(true, &ts->client->dev,
+				  "%s: read one event failed\n", __func__);
+			return;
+		}
+	}
+
+	do {
+		event_buff = read_event_buff[curr_pos];
+		event_id = event_buff[0] & 0x3;
+
+		if (ts->debug_events && curr_pos > 0)
+			input_info(true, &ts->client->dev,
+				 "ALL: %02X %02X %02X %02X %02X %02X %02X %02X\n",
+				event_buff[0], event_buff[1], event_buff[2],
+				event_buff[3], event_buff[4], event_buff[5],
+				event_buff[6], event_buff[7]);
+
+		switch (event_id) {
+		case SEC_TS_STATUS_EVENT:
+			hc->status_updated = true;
+			ts->status_event_cnt++;
+			p_event_status =
+				(struct sec_ts_event_status *)event_buff;
+
+			if (p_event_status->stype)
+				sec_ts_read_vendor_event(ts, p_event_status);
+
+			if ((p_event_status->stype ==
+					TYPE_STATUS_EVENT_INFO) &&
+				(p_event_status->status_id ==
+					SEC_TS_ACK_BOOT_COMPLETE)) {
+				u8 status_data_1 =
+					p_event_status->status_data_1;
+
+				switch (status_data_1) {
+				case 0x20:
+					/* watchdog reset !? */
+					input_err(true, &ts->client->dev,
+						"Touch - unexpected reset! Reason : WDT \n");
+
+					sec_ts_locked_release_all_finger(ts);
+					ret = sec_ts_write(ts,
+						SEC_TS_CMD_SENSE_ON, NULL, 0);
+					if (ret < 0)
+						input_err(true,
+							&ts->client->dev,
+							"%s: fail to write Sense_on\n",
+							__func__);
+						sec_ts_reinit(ts);
+					break;
+				case 0x40:
+					input_info(true, &ts->client->dev,
+						"%s: sw_reset ack.\n",
+						__func__);
+					sec_ts_locked_release_all_finger(ts);
+					complete_all(&ts->boot_completed);
+					break;
+				case 0x10:
+					input_info(true, &ts->client->dev,
+						"%s: hw_reset ack.\n",
+						__func__);
+					sec_ts_locked_release_all_finger(ts);
+					complete_all(&ts->boot_completed);
+					break;
+				default:
+					break;
+				}
+
+			}
+
+			/* event queue full-> all finger release */
+			if ((p_event_status->stype == TYPE_STATUS_EVENT_ERR) &&
+				(p_event_status->status_id ==
+					SEC_TS_ERR_EVENT_QUEUE_FULL)) {
+				input_err(true, &ts->client->dev,
+					"%s: IC Event Queue is full\n",
+					__func__);
+				sec_ts_locked_release_all_finger(ts);
+			}
+
+			if ((p_event_status->stype ==
+				TYPE_STATUS_EVENT_ERR) &&
+			    (p_event_status->status_id ==
+				SEC_TS_ERR_EVENT_ESD)) {
+				input_err(true, &ts->client->dev,
+					  "%s: ESD detected. run reset\n",
+					  __func__);
+#ifdef USE_RESET_DURING_POWER_ON
+				schedule_work(&ts->reset_work.work);
+#endif
+			}
+
+			if ((p_event_status->stype ==
+				TYPE_STATUS_EVENT_INFO) &&
+			    (p_event_status->status_id ==
+				SEC_TS_ACK_WET_MODE)) {
+				ts->wet_mode = p_event_status->status_data_1;
+				input_info(true, &ts->client->dev,
+					"%s: water wet mode %d\n",
+					__func__, ts->wet_mode);
+				if (ts->wet_mode)
+					ts->wet_count++;
+
+				}
+
+#ifdef SEC_TS_SUPPORT_CUSTOMLIB
+			mutex_lock(&ts->eventlock);
+			sec_ts_handle_lib_status_event(ts, p_event_status);
+			mutex_unlock(&ts->eventlock);
+#endif
+			break;
+
+		case SEC_TS_COORDINATE_EVENT:
+			hc->coord_updated = true;
+			ts->coord_event_cnt++;
+			processed_pointer_event = true;
+			mutex_lock(&ts->eventlock);
+			sec_ts_handle_coord_event(ts,
+				(struct sec_ts_event_coordinate *)event_buff);
+			mutex_unlock(&ts->eventlock);
+			break;
+
+		case SEC_TS_GESTURE_EVENT:
+			p_gesture_status =
+				(struct sec_ts_gesture_status *)event_buff;
+#ifdef SEC_TS_SUPPORT_CUSTOMLIB
+			mutex_lock(&ts->eventlock);
+			sec_ts_handle_gesture_event(ts, p_gesture_status);
+			mutex_unlock(&ts->eventlock);
+#endif
+			break;
+
+		default:
+			input_err(true, &ts->client->dev,
+				"%s: unknown event %x %x %x %x %x %x\n",
+				__func__,
+				event_buff[0], event_buff[1], event_buff[2],
+				event_buff[3], event_buff[4], event_buff[5]);
+			break;
+		}
+		curr_pos++;
+		remain_event_count--;
+	} while (remain_event_count >= 0);
+
+#if IS_ENABLED(CONFIG_TOUCHSCREEN_OFFLOAD)
+	if (!ts->offload.offload_running) {
+#endif
+	mutex_lock(&ts->eventlock);
+	input_set_timestamp(ts->input_dev, ts->timestamp);
+	input_sync(ts->input_dev);
+	mutex_unlock(&ts->eventlock);
+
+#if IS_ENABLED(CONFIG_TOUCHSCREEN_OFFLOAD)
+	}
+
+	if (processed_pointer_event) {
+		ret = touch_offload_reserve_frame(&ts->offload, &frame);
+		if (ret != 0) {
+			input_dbg(true, &ts->client->dev,
+				  "Could not reserve a frame: ret=%d.\n", ret);
+
+			/* Stop offload when there are no buffers available */
+			sec_ts_offload_set_running(ts, false);
+		} else {
+			sec_ts_offload_set_running(ts, true);
+
+			sec_ts_populate_frame(ts, frame);
+
+			ret = touch_offload_queue_frame(&ts->offload, frame);
+			if (ret != 0) {
+				pr_err("%s: Failed to queue reserved frame: ret=%d.\n",
+				       __func__, ret);
+			}
+		}
+	}
+#endif
+
+	/* TODO: If the mutual strength heatmap was already read into the touch
+	 * offload interface, use it here instead of reading again.
+	 */
+#if IS_ENABLED(CONFIG_TOUCHSCREEN_HEATMAP)
+	if (processed_pointer_event) {
+		if (ts->heatmap_init_done && !ts->offload.offload_running) {
+			heatmap_read(&ts->v4l2, ktime_to_ns(ts->timestamp));
+		}
+
+		/* palm */
+		if (last_tid_palm_state == 0 &&
+			ts->tid_palm_state >= 1) {
+			input_info(true, &ts->client->dev,
+				"COORD: detect palm enter(tid 0x0 -> %#x)\n",
+				ts->tid_palm_state);
+		}
+		if (last_tid_palm_state >= 1 &&
+			ts->tid_palm_state == 0) {
+			input_info(true, &ts->client->dev,
+				"COORD: detect palm leave(tid %#x -> 0x0), tid_touch %#x\n",
+				last_tid_palm_state, ts->tid_touch_state);
+			if (ts->touch_count || ts->tid_touch_state) {
+				ts->palms_leaved_once = true;
+				input_dbg(true, &ts->client->dev,
+					"COORD: wait all finger(s) release after palm entered\n");
+			}
+		}
+		/* grip */
+		if (last_tid_grip_state == 0 &&
+			ts->tid_grip_state >= 1) {
+			input_info(true, &ts->client->dev,
+				"COORD: detect grip enter(tid 0x0 -> %#x)\n",
+				ts->tid_grip_state);
+		}
+		if (last_tid_grip_state >= 1 &&
+			ts->tid_grip_state == 0) {
+			input_info(true, &ts->client->dev,
+				"COORD: detect grip leave(tid %#x -> 0x0), tid_touch %#x\n",
+				last_tid_grip_state, ts->tid_touch_state);
+			if (ts->touch_count || ts->tid_touch_state) {
+				ts->grips_leaved_once = true;
+				input_dbg(true, &ts->client->dev,
+					"COORD: wait all finger(s) release after grip entered\n");
+			}
+		}
+		if ((ts->touch_count == 0 || ts->tid_touch_state == 0) &&
+			(ts->palms_leaved_once || ts->grips_leaved_once)) {
+			ts->palms_leaved_once = false;
+			ts->grips_leaved_once = false;
+			input_info(true, &ts->client->dev,
+				"COORD: all fingers released with palm(s)/grip(s) leaved once\n");
+		}
+	}
+
+	/* Disable the firmware motion filter during single touch */
+	if (!ts->offload.offload_running)
+		update_motion_filter(ts, ts->tid_touch_state);
+#endif
+
+	/* Update the health check info. */
+	sec_ts_hc_update_and_push(ts, hc);
+}
+
+static irqreturn_t sec_ts_isr(int irq, void *handle)
+{
+	struct sec_ts_data *ts = (struct sec_ts_data *)handle;
+
+	ts->timestamp = ktime_get();
+	ts->int_cnt++;
+
+	return IRQ_WAKE_THREAD;
+}
+
+static irqreturn_t sec_ts_irq_thread(int irq, void *ptr)
+{
+	struct sec_ts_data *ts = (struct sec_ts_data *)ptr;
+
+	if (sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_IRQ, true) < 0) {
+		/* Interrupt during bus suspend */
+		input_info(true, &ts->client->dev,
+			"%s: Skipping stray interrupt since bus is suspended(power_status: %d)\n",
+			__func__, ts->power_status);
+		return IRQ_HANDLED;
+	}
+
+	/* prevent CPU from entering deep sleep */
+	cpu_latency_qos_update_request(&ts->pm_qos_req, 100);
+	pm_wakeup_event(&ts->client->dev, MSEC_PER_SEC);
+
+	sec_ts_read_event(ts);
+
+	cpu_latency_qos_update_request(&ts->pm_qos_req, PM_QOS_DEFAULT_VALUE);
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_IRQ, false);
+
+	return IRQ_HANDLED;
+}
+
+#if IS_ENABLED(CONFIG_TOUCHSCREEN_OFFLOAD)
+static void sec_ts_offload_report(void *handle,
+				  struct TouchOffloadIocReport *report)
+{
+	struct sec_ts_data *ts = (struct sec_ts_data *)handle;
+	bool touch_down = 0;
+	unsigned long touch_id = 0;
+	int i;
+
+	mutex_lock(&ts->eventlock);
+
+	input_set_timestamp(ts->input_dev, report->timestamp);
+
+	for (i = 0; i < MAX_COORDS; i++) {
+		if (report->coords[i].status == COORD_STATUS_FINGER) {
+			input_mt_slot(ts->input_dev, i);
+			touch_down = 1;
+			__set_bit(i, &touch_id);
+			input_report_key(ts->input_dev, BTN_TOUCH,
+					 touch_down);
+			input_mt_report_slot_state(ts->input_dev,
+						   MT_TOOL_FINGER, 1);
+			input_report_abs(ts->input_dev, ABS_MT_POSITION_X,
+					 report->coords[i].x);
+			input_report_abs(ts->input_dev, ABS_MT_POSITION_Y,
+					 report->coords[i].y);
+			input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR,
+					 report->coords[i].major);
+			input_report_abs(ts->input_dev, ABS_MT_TOUCH_MINOR,
+					 report->coords[i].minor);
+			if (ts->plat_data->support_mt_pressure)
+				input_report_abs(ts->input_dev,
+					ABS_MT_PRESSURE,
+					report->coords[i].pressure);
+			input_report_abs(ts->input_dev, ABS_MT_ORIENTATION,
+					 report->coords[i].rotation);
+		} else {
+			input_mt_slot(ts->input_dev, i);
+			input_report_abs(ts->input_dev, ABS_MT_PRESSURE, 0);
+			input_mt_report_slot_state(ts->input_dev,
+						   MT_TOOL_FINGER, 0);
+			input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID,
+					 -1);
+			input_report_abs(ts->input_dev, ABS_MT_ORIENTATION, 0);
+		}
+	}
+
+	input_report_key(ts->input_dev, BTN_TOUCH, touch_down);
+
+	input_sync(ts->input_dev);
+
+	mutex_unlock(&ts->eventlock);
+
+	if (touch_down)
+		heatmap_read(&ts->v4l2, ktime_to_ns(report->timestamp));
+
+	/* Disable the firmware motion filter during single touch */
+	update_motion_filter(ts, touch_id);
+}
+#endif /* CONFIG_TOUCHSCREEN_OFFLOAD */
+
+int get_tsp_status(void)
+{
+	return 0;
+}
+EXPORT_SYMBOL(get_tsp_status);
+
+int sec_ts_glove_mode_enables(struct sec_ts_data *ts, int mode)
+{
+	int ret;
+
+	if (mode)
+		ts->touch_functions = (ts->touch_functions |
+				       SEC_TS_BIT_SETFUNC_GLOVE |
+				       SEC_TS_DEFAULT_ENABLE_BIT_SETFUNC);
+	else
+		ts->touch_functions = ((ts->touch_functions &
+					(~SEC_TS_BIT_SETFUNC_GLOVE)) |
+				       SEC_TS_DEFAULT_ENABLE_BIT_SETFUNC);
+
+	if (ts->power_status == SEC_TS_STATE_POWER_OFF) {
+		input_err(true, &ts->client->dev,
+			"%s: pwr off, glove: %d, status: %x\n", __func__,
+			mode, ts->touch_functions);
+		goto glove_enable_err;
+	}
+
+	ret = sec_ts_write(ts, SEC_TS_CMD_SET_TOUCHFUNCTION,
+			   (u8 *)&ts->touch_functions, 2);
+	if (ret < 0) {
+		input_err(true, &ts->client->dev,
+			  "%s: Failed to send command", __func__);
+		goto glove_enable_err;
+	}
+
+	input_info(true, &ts->client->dev,
+		"%s: glove: %d, status: %x\n", __func__,
+		mode, ts->touch_functions);
+
+	return 0;
+
+glove_enable_err:
+	return -EIO;
+}
+EXPORT_SYMBOL(sec_ts_glove_mode_enables);
+
+int sec_ts_set_cover_type(struct sec_ts_data *ts, bool enable)
+{
+	int ret;
+
+	input_info(true, &ts->client->dev, "%s: %d\n",
+		   __func__, ts->cover_type);
+
+
+	switch (ts->cover_type) {
+	case SEC_TS_VIEW_WIRELESS:
+	case SEC_TS_VIEW_COVER:
+	case SEC_TS_VIEW_WALLET:
+	case SEC_TS_FLIP_WALLET:
+	case SEC_TS_LED_COVER:
+	case SEC_TS_MONTBLANC_COVER:
+	case SEC_TS_CLEAR_FLIP_COVER:
+	case SEC_TS_QWERTY_KEYBOARD_EUR:
+	case SEC_TS_QWERTY_KEYBOARD_KOR:
+		ts->cover_cmd = (u8)ts->cover_type;
+		break;
+	case SEC_TS_CHARGER_COVER:
+	case SEC_TS_COVER_NOTHING1:
+	case SEC_TS_COVER_NOTHING2:
+	default:
+		ts->cover_cmd = 0;
+		input_err(true, &ts->client->dev,
+			 "%s: not chage touch state, %d\n",
+			__func__, ts->cover_type);
+		break;
+	}
+
+	if (enable)
+		ts->touch_functions = (ts->touch_functions |
+				       SEC_TS_BIT_SETFUNC_COVER |
+				       SEC_TS_DEFAULT_ENABLE_BIT_SETFUNC);
+	else
+		ts->touch_functions = ((ts->touch_functions &
+					(~SEC_TS_BIT_SETFUNC_COVER)) |
+				       SEC_TS_DEFAULT_ENABLE_BIT_SETFUNC);
+
+	if (ts->power_status == SEC_TS_STATE_POWER_OFF) {
+		input_err(true, &ts->client->dev,
+			  "%s: pwr off, close: %d, status: %x\n", __func__,
+			enable, ts->touch_functions);
+		goto cover_enable_err;
+	}
+
+	if (enable) {
+		ret = sec_ts_write(ts, SEC_TS_CMD_SET_COVERTYPE,
+				   &ts->cover_cmd, 1);
+		if (ret < 0) {
+			input_err(true, &ts->client->dev,
+				  "%s: Failed to send covertype command: %d",
+				  __func__, ts->cover_cmd);
+			goto cover_enable_err;
+		}
+	}
+
+	ret = sec_ts_write(ts, SEC_TS_CMD_SET_TOUCHFUNCTION,
+			   (u8 *)&(ts->touch_functions), 2);
+	if (ret < 0) {
+		input_err(true, &ts->client->dev,
+			  "%s: Failed to send command", __func__);
+		goto cover_enable_err;
+	}
+
+	input_info(true, &ts->client->dev,
+		"%s: close: %d, status: %x\n", __func__,
+		enable, ts->touch_functions);
+
+	return 0;
+
+cover_enable_err:
+	return -EIO;
+
+
+}
+EXPORT_SYMBOL(sec_ts_set_cover_type);
+
+void sec_ts_set_grip_type(struct sec_ts_data *ts, u8 set_type)
+{
+	u8 mode = G_NONE;
+
+	input_info(true, &ts->client->dev,
+		"%s: re-init grip(%d), edh: %d, edg: %d, lan: %d\n", __func__,
+		set_type, ts->grip_edgehandler_direction, ts->grip_edge_range,
+		ts->grip_landscape_mode);
+
+	/* edge handler */
+	if (ts->grip_edgehandler_direction != 0)
+		mode |= G_SET_EDGE_HANDLER;
+
+	if (set_type == GRIP_ALL_DATA) {
+		/* edge */
+		if (ts->grip_edge_range != 60)
+			mode |= G_SET_EDGE_ZONE;
+
+		/* dead zone */
+		if (ts->grip_landscape_mode == 1)	/* default 0 mode, 32 */
+			mode |= G_SET_LANDSCAPE_MODE;
+		else
+			mode |= G_SET_NORMAL_MODE;
+	}
+
+	if (mode)
+		set_grip_data_to_ic(ts, mode);
+
+}
+
+/* for debugging--------------------------------------------------------------*/
+
+static int sec_ts_pinctrl_configure(struct sec_ts_data *ts, bool enable)
+{
+	struct pinctrl_state *state;
+
+	input_info(true, &ts->client->dev, "%s: %s\n",
+		   __func__, enable ? "ACTIVE" : "SUSPEND");
+
+	if (enable) {
+		state = pinctrl_lookup_state(ts->plat_data->pinctrl,
+					     "on_state");
+		if (IS_ERR(ts->plat_data->pinctrl))
+			input_err(true, &ts->client->dev,
+				"%s: could not get active pinstate\n",
+				__func__);
+	} else {
+		state = pinctrl_lookup_state(ts->plat_data->pinctrl,
+					     "off_state");
+		if (IS_ERR(ts->plat_data->pinctrl))
+			input_err(true, &ts->client->dev,
+				"%s: could not get suspend pinstate\n",
+				__func__);
+	}
+
+	if (!IS_ERR_OR_NULL(state))
+		return pinctrl_select_state(ts->plat_data->pinctrl, state);
+
+	return 0;
+
+}
+
+/* Return true if you should defer sec_ts probe waiting for
+ * avdd or vdd regulators.
+ */
+static int sec_ts_check_for_deferred_regulators(struct device *dev)
+{
+	struct regulator *reg = regulator_get(dev, "vdd");
+
+	if (reg == ERR_PTR(-EPROBE_DEFER))
+		return true;
+	if (!IS_ERR_OR_NULL(reg))
+		regulator_put(reg);
+
+	reg = regulator_get(dev, "avdd");
+	if (reg == ERR_PTR(-EPROBE_DEFER))
+		return true;
+	if (!IS_ERR_OR_NULL(reg))
+		regulator_put(reg);
+	return false;
+}
+
+static int sec_ts_power(void *data, bool on)
+{
+	struct sec_ts_data *ts = (struct sec_ts_data *)data;
+	struct sec_ts_plat_data *pdata = ts->plat_data;
+	static bool vdd_enabled, avdd_enabled;
+	int ret = 0;
+
+	if (!pdata->regulator_vdd) {
+		pdata->regulator_vdd = regulator_get(&ts->client->dev, "vdd");
+		if (IS_ERR_OR_NULL(pdata->regulator_vdd)) {
+			pdata->regulator_vdd = NULL;
+			input_err(true, &ts->client->dev,
+				"%s: Failed to get vdd regulator.\n",
+				__func__);
+		}
+	}
+
+	if (!pdata->regulator_avdd) {
+		pdata->regulator_avdd = regulator_get(&ts->client->dev, "avdd");
+		if (IS_ERR_OR_NULL(pdata->regulator_avdd)) {
+			pdata->regulator_avdd = NULL;
+			input_err(true, &ts->client->dev,
+				"%s: Failed to get avdd regulator.\n",
+				__func__);
+		}
+	}
+
+	if (pdata->regulator_vdd) {
+		if (vdd_enabled != on){
+			ret = (on) ? regulator_enable(pdata->regulator_vdd) :
+				regulator_disable(pdata->regulator_vdd);
+			if (ret)
+				input_err(true, &ts->client->dev,
+					"%s: Failed to control vdd: %d\n",
+					__func__, ret);
+			else {
+				input_info(true, &ts->client->dev, "%s: %s vdd\n",
+					__func__, on ? "enable" : "disable");
+				sec_ts_delay(on ? 1 : 4);
+				vdd_enabled = on;
+			}
+		}
+
+		if (!vdd_enabled) {
+			regulator_put(pdata->regulator_vdd);
+			pdata->regulator_vdd = NULL;
+		}
+	}
+
+	if (pdata->regulator_avdd) {
+		if (avdd_enabled != on) {
+			ret = (on) ? regulator_enable(pdata->regulator_avdd) :
+				regulator_disable(pdata->regulator_avdd);
+			if (ret)
+				input_err(true, &ts->client->dev,
+					"%s: Failed to control avdd: %d\n",
+					__func__, ret);
+			else {
+				input_info(true, &ts->client->dev, "%s: %s avdd\n",
+					__func__, on ? "enable" : "disable");
+				avdd_enabled = on;
+			}
+		}
+
+		if (!avdd_enabled) {
+			regulator_put(pdata->regulator_avdd);
+			pdata->regulator_avdd = NULL;
+		}
+	}
+
+	return ret;
+}
+
+#ifdef I2C_INTERFACE
+static int sec_ts_parse_dt(struct i2c_client *client)
+#else
+static int sec_ts_parse_dt(struct spi_device *client)
+#endif
+{
+	struct device *dev = &client->dev;
+	struct sec_ts_plat_data *pdata = dev->platform_data;
+	struct device_node *np = dev->of_node;
+	u32 coords[2];
+	u8 offload_id[4];
+	int ret = 0;
+	int count = 0;
+	u32 ic_match_value;
+	int lcdtype = 0;
+#if defined(CONFIG_EXYNOS_DECON_FB)
+	int connected;
+#endif
+	int index;
+	struct of_phandle_args panelmap;
+	struct drm_panel *panel = NULL;
+
+	if (of_property_read_bool(np, "sec,panel_map")) {
+		for (index = 0 ;; index++) {
+			ret = of_parse_phandle_with_fixed_args(np,
+					"sec,panel_map",
+					1,
+					index,
+					&panelmap);
+			if (ret)
+				return -EPROBE_DEFER;
+			panel = of_drm_find_panel(panelmap.np);
+			of_node_put(panelmap.np);
+			if (!IS_ERR_OR_NULL(panel)) {
+				pdata->panel = panel;
+				pdata->initial_panel_index = panelmap.args[0];
+				break;
+			}
+		}
+	}
+
+	pdata->tsp_icid = of_get_named_gpio(np, "sec,tsp-icid_gpio", 0);
+	if (gpio_is_valid(pdata->tsp_icid)) {
+		input_info(true, dev, "%s: TSP_ICID : %d\n",
+			   __func__, gpio_get_value(pdata->tsp_icid));
+		if (of_property_read_u32(np, "sec,icid_match_value",
+					 &ic_match_value)) {
+			input_err(true, dev,
+				"%s: Failed to get icid match value\n",
+				__func__);
+			return -EINVAL;
+		}
+
+		if (gpio_get_value(pdata->tsp_icid) != ic_match_value) {
+			input_err(true, dev,
+				  "%s: Do not match TSP_ICID\n", __func__);
+			return -EINVAL;
+		}
+	} else {
+		input_dbg(true, dev,
+			  "%s: Failed to get tsp-icid gpio\n", __func__);
+	}
+
+	pdata->vsync_gpio = of_get_named_gpio(np, "sec,tsp_vsync_gpio", 0);
+	if (gpio_is_valid(pdata->vsync_gpio))
+		input_info(true, &client->dev, "%s: vsync %s\n", __func__,
+			gpio_get_value(pdata->vsync_gpio) ?
+				"disable" : "enable");
+
+	pdata->irq_gpio = of_get_named_gpio(np, "sec,irq_gpio", 0);
+	if (gpio_is_valid(pdata->irq_gpio)) {
+		ret = gpio_request_one(pdata->irq_gpio, GPIOF_DIR_IN,
+				       "sec,tsp_int");
+		if (ret) {
+			input_err(true, &client->dev,
+				  "%s: Unable to request tsp_int [%d]\n",
+				  __func__, pdata->irq_gpio);
+			return -EINVAL;
+		}
+	} else {
+		input_err(true, &client->dev,
+			  "%s: Failed to get irq gpio\n", __func__);
+		return -EINVAL;
+	}
+
+	client->irq = gpio_to_irq(pdata->irq_gpio);
+
+	if (of_property_read_u32(np, "sec,irq_type", &pdata->irq_type)) {
+		input_dbg(true, dev,
+			"%s: no irq_type property, set to default!\n",
+			__func__);
+		pdata->irq_type = IRQF_TRIGGER_LOW | IRQF_ONESHOT;
+	}
+
+	if (of_property_read_u32(np, "sec,i2c-burstmax", &pdata->io_burstmax)) {
+		input_dbg(false, &client->dev,
+			  "%s: Failed to get io_burstmax property\n", __func__);
+		pdata->io_burstmax = 1024; //TODO: check this
+	}
+	if (pdata->io_burstmax > IO_PREALLOC_READ_BUF_SZ ||
+	    pdata->io_burstmax > IO_PREALLOC_WRITE_BUF_SZ) {
+		input_err(true, &client->dev,
+			  "%s: io_burstmax is larger than io_read_buf and/or io_write_buf.\n",
+			  __func__);
+//TODO: check this
+//		return -EINVAL;
+	}
+
+	if (of_property_read_u32_array(np, "sec,max_coords", coords, 2)) {
+		input_err(true, &client->dev,
+			  "%s: Failed to get max_coords property\n", __func__);
+		return -EINVAL;
+	}
+	pdata->max_x = coords[0] - 1;
+	pdata->max_y = coords[1] - 1;
+
+	if (of_property_read_u32_array(np, "sec,fod_coords", coords, 2)) {
+		input_info(true, &client->dev,
+			  "%s: sec,fod_coords not found!\n", __func__);
+		coords[0] = 0;
+		coords[1] = 0;
+	}
+	pdata->fod_x = coords[0];
+	pdata->fod_y = coords[1];
+
+#ifdef PAT_CONTROL
+	if (of_property_read_u32(np, "sec,pat_function",
+				 &pdata->pat_function) < 0) {
+		pdata->pat_function = 0;
+		input_err(true, dev,
+			"%s: Failed to get pat_function property\n", __func__);
+	} else {
+		input_info(true, dev,
+			"%s: pat_function: %#x\n", __func__, pdata->pat_function);
+	}
+
+	if (of_property_read_u32(np, "sec,afe_base", &pdata->afe_base) < 0) {
+		pdata->afe_base = 0;
+		input_err(true, dev,
+			  "%s: Failed to get afe_base property\n", __func__);
+	}
+#endif
+
+	pdata->tsp_id = of_get_named_gpio(np, "sec,tsp-id_gpio", 0);
+	if (gpio_is_valid(pdata->tsp_id))
+		input_info(true, dev, "%s: TSP_ID : %d\n", __func__,
+			   gpio_get_value(pdata->tsp_id));
+	else
+		input_dbg(true, dev,
+			  "%s: Failed to get tsp-id gpio\n", __func__);
+
+	pdata->switch_gpio = of_get_named_gpio(np,
+					       "sec,switch_gpio", 0);
+	if (gpio_is_valid(pdata->switch_gpio)) {
+		ret = gpio_request_one(pdata->switch_gpio,
+				       GPIOF_OUT_INIT_LOW,
+				       "sec,touch_i2c_switch");
+		if (ret) {
+			input_err(true, dev,
+				  "%s: Failed to request gpio %d\n",
+				  __func__, pdata->switch_gpio);
+			return -EINVAL;
+		}
+
+		ret = gpio_direction_output(pdata->switch_gpio,
+					    SEC_SWITCH_GPIO_VALUE_AP_MASTER);
+		if (ret) {
+			input_err(true, dev,
+				  "%s: Failed to set gpio %d direction\n",
+				  __func__, pdata->switch_gpio);
+			return -EINVAL;
+		}
+	} else {
+		input_info(true, dev, "%s: unavailable switch_gpio!\n",
+			  __func__);
+	}
+
+	pdata->reset_gpio = of_get_named_gpio(np, "sec,reset_gpio", 0);
+	if (gpio_is_valid(pdata->reset_gpio)) {
+		ret = gpio_request_one(pdata->reset_gpio,
+					GPIOF_OUT_INIT_HIGH,
+					"sec,touch_reset_gpio");
+		if (ret) {
+			input_err(true, dev,
+				  "%s: Failed to request gpio %d, ret %d\n",
+				  __func__, pdata->reset_gpio, ret);
+			pdata->reset_gpio = -1;
+		}
+		ret = gpio_direction_output(pdata->reset_gpio, 0);
+
+	} else
+		input_err(true, dev, "%s: Failed to get reset_gpio\n",
+			__func__);
+
+	count = of_property_count_strings(np, "sec,firmware_name");
+	if (count <= 0) {
+		pdata->firmware_name = NULL;
+	} else {
+		if (gpio_is_valid(pdata->tsp_id))
+			of_property_read_string_index(np, "sec,firmware_name",
+						gpio_get_value(pdata->tsp_id),
+						&pdata->firmware_name);
+		else
+			of_property_read_string_index(np, "sec,firmware_name",
+						      0, &pdata->firmware_name);
+	}
+
+	if (of_property_read_string_index(np, "sec,project_name", 0,
+					  &pdata->project_name))
+		input_dbg(true, &client->dev,
+			"%s: skipped to get project_name property\n", __func__);
+	if (of_property_read_string_index(np, "sec,model_name",
+					  1, &pdata->model_name))
+		input_dbg(true, &client->dev,
+			  "%s: skipped to get model_name property\n", __func__);
+
+#if defined(CONFIG_FB_MSM_MDSS_SAMSUNG)
+	lcdtype = get_lcd_attached("GET");
+	if (lcdtype < 0) {
+		input_err(true, &client->dev,
+			  "%s: lcd is not attached\n", __func__);
+		return -ENODEV;
+	}
+#endif
+
+#if defined(CONFIG_EXYNOS_DECON_FB)
+	connected = get_lcd_info("connected");
+	if (connected < 0) {
+		input_err(true, dev, "%s: Failed to get lcd info\n", __func__);
+		return -EINVAL;
+	}
+
+	if (!connected) {
+		input_err(true, &client->dev,
+			  "%s: lcd is disconnected\n", __func__);
+		return -ENODEV;
+	}
+
+	input_info(true, &client->dev, "%s: lcd is connected\n", __func__);
+
+	lcdtype = get_lcd_info("id");
+	if (lcdtype < 0) {
+		input_err(true, dev, "%s: Failed to get lcd info\n", __func__);
+		return -EINVAL;
+	}
+#endif
+
+	input_info(true, &client->dev,
+		   "%s: lcdtype 0x%08X\n", __func__, lcdtype);
+
+	if (pdata->model_name && strncmp(pdata->model_name, "G950", 4) == 0)
+		pdata->panel_revision = 0;
+	else
+		pdata->panel_revision = ((lcdtype >> 8) & 0xFF) >> 4;
+
+	pdata->power = sec_ts_power;
+
+	if (of_property_read_u32(np, "sec,always_lpmode",
+				 &pdata->always_lpmode) < 0)
+		pdata->always_lpmode = 0;
+
+	if (of_property_read_u32(np, "sec,bringup", &pdata->bringup) < 0)
+		pdata->bringup = 0;
+
+	if (of_property_read_u32(np, "sec,mis_cal_check",
+				 &pdata->mis_cal_check) < 0)
+		pdata->mis_cal_check = 0;
+
+	if (of_property_read_u32(np, "sec,encoded_enable",
+		&pdata->encoded_enable) < 0)
+		pdata->encoded_enable = 0;
+
+	pdata->grip_prescreen_mode = GRIP_PRESCREEN_MODE_2;
+	pdata->grip_prescreen_timeout = 120;
+	pdata->is_heatmap_enabled = false;
+	pdata->encoded_frame_counter = 0;
+	pdata->encoded_skip_counter = 0;
+
+	if (of_property_read_u32(np, "sec,heatmap_mode",
+		&pdata->heatmap_mode) < 0)
+		pdata->heatmap_mode = 0;
+
+	pdata->regulator_boot_on = of_property_read_bool(np,
+						"sec,regulator_boot_on");
+	pdata->support_sidegesture = of_property_read_bool(np,
+						"sec,support_sidegesture");
+	pdata->support_dex = of_property_read_bool(np, "support_dex_mode");
+
+	pdata->support_mt_pressure = true;
+
+	pdata->offload_id = 0;
+	if (of_property_read_u8_array(np, "sec,touch_offload_id",
+				      offload_id, 4) == -EINVAL)
+		input_err(true, &client->dev,
+			  "%s: Failed to read sec,touch_offload_id\n");
+	else {
+		pdata->offload_id = *(u32 *)offload_id;
+		input_info(true, &client->dev,
+			   "%s: Offload device ID = \"%c%c%c%c\" / 0x%08X\n",
+			   __func__, offload_id[0], offload_id[1], offload_id[2],
+			   offload_id[3], pdata->offload_id);
+	}
+
+	if (of_property_read_u8(np, "sec,mm2px", &pdata->mm2px) < 0)
+		pdata->mm2px = 1;
+	input_info(true, &client->dev,
+		   "%s: mm2px %d\n", __func__, pdata->mm2px);
+
+	input_info(true, &client->dev,
+		"%s: io_burstmax: %d, bringup: %d, FW: %s, mis_cal_check: %d\n",
+		__func__, pdata->io_burstmax, pdata->bringup,
+		pdata->firmware_name, pdata->mis_cal_check);
+	return ret;
+}
+
+int sec_ts_read_information(struct sec_ts_data *ts)
+{
+	unsigned char data[13] = { 0 };
+	int ret;
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_READ_INFO, true);
+
+	memset(data, 0x0, 3);
+	ret = sec_ts_read(ts, SEC_TS_READ_ID, data, 3);
+	if (ret < 0) {
+		input_err(true, &ts->client->dev,
+					"%s: failed to read device id(%d)\n",
+					__func__, ret);
+		goto out;
+	}
+
+	input_info(true, &ts->client->dev,
+				"%s: %X, %X, %X\n",
+				__func__, data[0], data[1], data[2]);
+	memset(data, 0x0, 11);
+	ret = sec_ts_read(ts,  SEC_TS_READ_PANEL_INFO, data, 11);
+	if (ret < 0) {
+		input_err(true, &ts->client->dev,
+					"%s: failed to read sub id(%d)\n",
+					__func__, ret);
+		goto out;
+	}
+
+	input_info(true, &ts->client->dev,
+		   "%s: nTX: %d, nRX: %d, rY: %d, rX: %d\n",
+		   __func__, data[8], data[9],
+		   (data[2] << 8) | data[3], (data[0] << 8) | data[1]);
+
+	/* Set X,Y Resolution from IC information. */
+	if (((data[0] << 8) | data[1]) > 0)
+		ts->plat_data->max_x = ((data[0] << 8) | data[1]) - 1;
+
+	if (((data[2] << 8) | data[3]) > 0)
+		ts->plat_data->max_y = ((data[2] << 8) | data[3]) - 1;
+
+	ts->tx_count = data[8];
+	ts->rx_count = data[9];
+
+	data[0] = 0;
+	ret = sec_ts_read(ts, SEC_TS_READ_BOOT_STATUS, data, 1);
+	if (ret < 0) {
+		input_err(true, &ts->client->dev,
+					"%s: failed to read sub id(%d)\n",
+					__func__, ret);
+		goto out;
+	}
+
+	input_info(true, &ts->client->dev,
+				"%s: BOOT_STATUS: %X\n",
+				__func__, data[0]);
+
+	memset(data, 0x0, 4);
+	ret = sec_ts_read(ts, SEC_TS_READ_TS_STATUS, data, 4);
+	if (ret < 0) {
+		input_err(true, &ts->client->dev,
+					"%s: failed to read sub id(%d)\n",
+					__func__, ret);
+		goto out;
+	}
+
+	input_info(true, &ts->client->dev,
+		   "%s: TS_STATUS: %02X, %02X, %02X, %02X\n",
+		   __func__, data[0], data[1], data[2], data[3]);
+	ret = sec_ts_read(ts, SEC_TS_CMD_SET_TOUCHFUNCTION,
+			  (u8 *)&(ts->touch_functions), 2);
+	if (ret < 0) {
+		input_err(true, &ts->client->dev,
+			"%s: failed to read touch functions(%d)\n",
+			__func__, ret);
+		goto out;
+	}
+
+	input_info(true, &ts->client->dev,
+				"%s: Functions: %02X\n",
+				__func__, ts->touch_functions);
+
+out:
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_READ_INFO, false);
+	return ret;
+}
+
+#ifdef SEC_TS_SUPPORT_CUSTOMLIB
+int sec_ts_set_custom_library(struct sec_ts_data *ts)
+{
+	u8 data[3] = { 0 };
+	int ret;
+
+	input_err(true, &ts->client->dev, "%s: Custom Library (0x%02x)\n",
+				__func__, ts->lowpower_mode);
+
+	data[2] = ts->lowpower_mode;
+
+	ret = sec_ts_write(ts, SEC_TS_CMD_CUSTOMLIB_WRITE_PARAM, &data[0], 3);
+	if (ret < 0)
+		input_err(true, &ts->client->dev,
+			  "%s: Failed to Custom Library\n", __func__);
+
+	ret = sec_ts_write(ts, SEC_TS_CMD_CUSTOMLIB_NOTIFY_PACKET, NULL, 0);
+	if (ret < 0)
+		input_err(true, &ts->client->dev,
+			"%s: Failed to send NOTIFY Custom Library\n", __func__);
+
+	return ret;
+}
+
+int sec_ts_check_custom_library(struct sec_ts_data *ts)
+{
+	u8 data[10] = { 0 };
+	int ret = -1;
+
+	ret = ts->sec_ts_read(ts, SEC_TS_CMD_CUSTOMLIB_GET_INFO, &data[0], 10);
+
+	input_info(true, &ts->client->dev,
+		"%s: (%d) %c%c%c%c, || %02X, %02X, %02X, %02X, || %02X, %02X\n",
+		__func__, ret, data[0], data[1], data[2], data[3], data[4],
+		data[5], data[6], data[7], data[8], data[9]);
+
+	/* compare model name with device tree */
+	if (ts->plat_data->model_name)
+		ret = strncmp(data, ts->plat_data->model_name, 4);
+
+	if (ret == 0)
+		ts->use_customlib = true;
+	else
+		ts->use_customlib = false;
+
+	input_err(true, &ts->client->dev, "%s: use %s\n",
+		  __func__, ts->use_customlib ? "CUSTOMLIB" : "VENDOR");
+
+	return ret;
+}
+#endif
+
+static void sec_ts_set_input_prop(struct sec_ts_data *ts,
+				  struct input_dev *dev, u8 propbit)
+{
+	static char sec_ts_phys[64] = { 0 };
+
+	snprintf(sec_ts_phys, sizeof(sec_ts_phys), "%s/input1",
+			dev->name);
+	dev->phys = sec_ts_phys;
+#ifdef I2C_INTERFACE
+	dev->id.bustype = BUS_I2C;
+#else
+	dev->id.bustype = BUS_SPI;
+#endif
+	dev->dev.parent = &ts->client->dev;
+
+	set_bit(EV_SYN, dev->evbit);
+	set_bit(EV_KEY, dev->evbit);
+	set_bit(EV_ABS, dev->evbit);
+	set_bit(EV_SW, dev->evbit);
+	set_bit(BTN_TOUCH, dev->keybit);
+	set_bit(BTN_TOOL_FINGER, dev->keybit);
+#ifdef SEC_TS_SUPPORT_CUSTOMLIB
+	set_bit(KEY_BLACK_UI_GESTURE, dev->keybit);
+#endif
+#ifdef SEC_TS_SUPPORT_TOUCH_KEY
+	if (ts->plat_data->support_mskey) {
+		int i;
+
+		for (i = 0 ; i < ts->plat_data->num_touchkey ; i++)
+			set_bit(ts->plat_data->touchkey[i].keycode,
+				dev->keybit);
+
+		set_bit(EV_LED, dev->evbit);
+		set_bit(LED_MISC, dev->ledbit);
+	}
+#endif
+#ifdef KEY_SIDE_GESTURE
+	if (ts->plat_data->support_sidegesture) {
+		set_bit(KEY_SIDE_GESTURE, dev->keybit);
+		set_bit(KEY_SIDE_GESTURE_RIGHT, dev->keybit);
+		set_bit(KEY_SIDE_GESTURE_LEFT, dev->keybit);
+	}
+#endif
+	set_bit(propbit, dev->propbit);
+	set_bit(KEY_HOMEPAGE, dev->keybit);
+
+#ifdef SW_GLOVE
+	input_set_capability(dev, EV_SW, SW_GLOVE);
+#endif
+	input_set_abs_params(dev, ABS_MT_POSITION_X, 0, ts->plat_data->max_x,
+			     0, 0);
+	input_set_abs_params(dev, ABS_MT_POSITION_Y, 0, ts->plat_data->max_y,
+			     0, 0);
+	input_set_abs_params(dev, ABS_MT_TOUCH_MAJOR, 0,
+			255 * ts->plat_data->mm2px,
+			0, 0);
+	input_set_abs_params(dev, ABS_MT_TOUCH_MINOR, 0,
+			255 * ts->plat_data->mm2px,
+			0, 0);
+	input_set_abs_params(dev, ABS_MT_TOOL_TYPE, MT_TOOL_FINGER,
+			     MT_TOOL_FINGER, 0, 0);
+#ifdef ABS_MT_CUSTOM
+	input_set_abs_params(dev, ABS_MT_CUSTOM, 0, 0xFFFF, 0, 0);
+#endif
+	if (ts->plat_data->support_mt_pressure)
+		input_set_abs_params(dev, ABS_MT_PRESSURE, 0,
+				     SEC_TS_PRESSURE_MAX, 0, 0);
+
+	/* Units are (-4096, 4096), representing the range between rotation
+	 * 90 degrees to left and 90 degrees to the right.
+	 */
+	input_set_abs_params(dev, ABS_MT_ORIENTATION, -4096, 4096, 0, 0);
+
+	if (propbit == INPUT_PROP_POINTER)
+		input_mt_init_slots(dev, MAX_SUPPORT_TOUCH_COUNT,
+				    INPUT_MT_POINTER);
+	else
+		input_mt_init_slots(dev, MAX_SUPPORT_TOUCH_COUNT,
+				    INPUT_MT_DIRECT);
+
+	input_set_drvdata(dev, ts);
+}
+
+static int sec_ts_fw_init(struct sec_ts_data *ts)
+{
+	int ret = SEC_TS_ERR_NA;
+	bool force_update = false;
+	bool valid_firmware_integrity = false;
+	unsigned char data[5] = { 0 };
+	unsigned char deviceID[5] = { 0 };
+	unsigned char result = 0;
+
+	ret = sec_ts_read(ts, SEC_TS_READ_DEVICE_ID, deviceID, 5);
+	if (ret < 0)
+		input_err(true, &ts->client->dev,
+			  "%s: failed to read device ID(%d)\n",
+			  __func__, ret);
+	else
+		input_info(true, &ts->client->dev,
+			"%s: DEVICE ID: %02X, %02X, %02X, %02X, %02X\n",
+			__func__, deviceID[0], deviceID[1], deviceID[2],
+			deviceID[3], deviceID[4]);
+
+	ret = sec_ts_read(ts, SEC_TS_READ_FIRMWARE_INTEGRITY, &result, 1);
+	if (ret < 0) {
+		input_err(true, &ts->client->dev,
+			  "%s: failed to integrity check (%d)\n",
+			  __func__, ret);
+	} else {
+		if (result & 0x80)
+			valid_firmware_integrity = true;
+		else
+			input_err(true, &ts->client->dev,
+				  "%s: invalid integrity result (0x%x)\n",
+				  __func__, result);
+	}
+
+	ret = sec_ts_read(ts, SEC_TS_READ_BOOT_STATUS, &data[0], 1);
+	if (ret < 0) {
+		input_err(true, &ts->client->dev,
+			  "%s: failed to read sub id(%d)\n", __func__, ret);
+	} else {
+		ret = sec_ts_read(ts, SEC_TS_READ_TS_STATUS, &data[1], 4);
+		if (ret < 0)
+			input_err(true, &ts->client->dev,
+				  "%s: failed to touch status(%d)\n",
+				  __func__, ret);
+	}
+	input_info(true, &ts->client->dev,
+		"%s: TOUCH STATUS: %02X || %02X, %02X, %02X, %02X\n",
+		__func__, data[0], data[1], data[2], data[3], data[4]);
+
+	if (data[0] == SEC_TS_STATUS_BOOT_MODE)
+		ts->checksum_result = 1;
+
+	if (((data[0] == SEC_TS_STATUS_APP_MODE &&
+	      data[2] == TOUCH_SYSTEM_MODE_FLASH) || ret < 0) &&
+	    (valid_firmware_integrity == false))
+		force_update = true;
+
+	ret = sec_ts_read_information(ts);
+	if (ret < 0) {
+		input_err(true, &ts->client->dev,
+			  "%s: fail to read information 0x%x\n",
+			  __func__, ret);
+		return SEC_TS_ERR_INIT;
+	}
+
+	ts->touch_functions |= SEC_TS_DEFAULT_ENABLE_BIT_SETFUNC;
+	ret = sec_ts_write(ts, SEC_TS_CMD_SET_TOUCHFUNCTION,
+			       (u8 *)&ts->touch_functions, 2);
+	if (ret < 0)
+		input_err(true, &ts->client->dev,
+			  "%s: Failed to send touch func_mode command",
+			  __func__);
+
+	/* Sense_on */
+	ret = sec_ts_write(ts, SEC_TS_CMD_SENSE_ON, NULL, 0);
+	if (ret < 0) {
+		input_err(true, &ts->client->dev,
+			  "%s: fail to write Sense_on 0x%x\n",
+			  __func__, ret);
+		return SEC_TS_ERR_INIT;
+	}
+
+	ts->pFrame = kzalloc(ts->tx_count * ts->rx_count * 2, GFP_KERNEL);
+	if (!ts->pFrame)
+		return SEC_TS_ERR_ALLOC_FRAME;
+
+
+	ts->pFrameSS = kzalloc((ts->tx_count + ts->rx_count) * 2, GFP_KERNEL);
+	if (!ts->pFrameSS) {
+		kfree(ts->pFrame);
+		ts->pFrame = NULL;
+		return SEC_TS_ERR_ALLOC_FRAME_SS;
+	}
+
+#ifdef USE_STIM_PAD
+	ts->gainTable = kzalloc(ts->tx_count * ts->rx_count, GFP_KERNEL);
+	if (!ts->gainTable) {
+		kfree(ts->pFrame);
+		kfree(ts->pFrameSS);
+		ts->pFrame = NULL;
+		ts->pFrameSS = NULL;
+		return SEC_TS_ERR_ALLOC_GAINTABLE;
+	}
+#endif
+
+	if (ts->plat_data->support_dex) {
+		ts->input_dev_pad->name = "sec_touchpad";
+		sec_ts_set_input_prop(ts, ts->input_dev_pad,
+				      INPUT_PROP_POINTER);
+	}
+	ts->dex_name = "";
+
+	ts->input_dev->name = "sec_touchscreen";
+	sec_ts_set_input_prop(ts, ts->input_dev, INPUT_PROP_DIRECT);
+#ifdef USE_OPEN_CLOSE
+	ts->input_dev->open = sec_ts_input_open;
+	ts->input_dev->close = sec_ts_input_close;
+#endif
+	ts->input_dev_touch = ts->input_dev;
+
+	ret = input_register_device(ts->input_dev);
+	if (ret) {
+		input_err(true, &ts->client->dev,
+			  "%s: Unable to register %s input device 0x%x\n",
+			  __func__, ts->input_dev->name, ret);
+		return SEC_TS_ERR_REG_INPUT_DEV;
+	}
+
+	if (ts->plat_data->support_dex) {
+		ret = input_register_device(ts->input_dev_pad);
+		if (ret) {
+			input_err(true, &ts->client->dev,
+				  "%s: Unable to register %s input device 0x%x\n",
+				  __func__, ts->input_dev_pad->name, ret);
+			return SEC_TS_ERR_REG_INPUT_PAD_DEV;
+		}
+	}
+
+	return SEC_TS_ERR_NA;
+}
+
+static void sec_ts_device_init(struct sec_ts_data *ts)
+{
+#if (1) //!defined(CONFIG_SAMSUNG_PRODUCT_SHIP)
+	sec_ts_raw_device_init(ts);
+#endif
+	sec_ts_fn_init(ts);
+
+#ifdef SEC_TS_SUPPORT_CUSTOMLIB
+	sec_ts_check_custom_library(ts);
+	if (ts->use_customlib)
+		sec_ts_set_custom_library(ts);
+#endif
+}
+
+static int sec_ts_heatmap_init(struct sec_ts_data *ts)
+{
+	int ret = 0;
+
+	if (ts->heatmap_init_done) {
+		input_info(true, &ts->client->dev, "%s: already init done!\n",
+			__func__);
+		return ret;
+	}
+
+	input_info(true, &ts->client->dev, "%s\n", __func__);
+#if IS_ENABLED(CONFIG_TOUCHSCREEN_HEATMAP)
+	/*
+	 * Heatmap_probe must be called before irq routine is registered,
+	 * because heatmap_read is called from the irq context.
+	 * If the ISR runs before heatmap_probe is finished, it will invoke
+	 * heatmap_read and cause NPE, since read_frame would not yet be set.
+	 */
+	ts->v4l2.parent_dev = &ts->client->dev;
+	ts->v4l2.input_dev = ts->input_dev;
+	ts->v4l2.read_frame = read_heatmap_raw;
+	ts->v4l2.width = ts->tx_count;
+	ts->v4l2.height = ts->rx_count;
+	/* 120 Hz operation */
+	ts->v4l2.timeperframe.numerator = 1;
+	ts->v4l2.timeperframe.denominator = 120;
+	ret = heatmap_probe(&ts->v4l2);
+	if (ret == 0) {
+		ts->heatmap_init_done = true;
+	} else {
+		input_err(true, &ts->client->dev,
+			"%s: fail! ret %d\n", __func__, ret);
+	}
+#endif
+	return ret;
+}
+
+#ifdef USE_CHARGER_WORK
+static struct notifier_block sec_ts_psy_nb;
+#endif
+
+#ifdef I2C_INTERFACE
+static int sec_ts_probe(struct i2c_client *client,
+			const struct i2c_device_id *id)
+#else
+static int sec_ts_probe(struct spi_device *client)
+#endif
+{
+	struct sec_ts_data *ts;
+	struct sec_ts_plat_data *pdata;
+	int ret = 0;
+
+	input_info(true, &client->dev, "%s\n", __func__);
+
+#ifdef I2C_INTERFACE
+	input_info(true, &client->dev, "%s: I2C interface\n", __func__);
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+		input_err(true, &client->dev, "%s: EIO err!\n", __func__);
+		return -EIO;
+	}
+#else
+	if (client->controller->rt == false) {
+		client->rt = true;
+		ret = spi_setup(client);
+		if (ret < 0) {
+			input_err(true, &client->dev, "%s: setup SPI rt failed(%d)\n",
+				  __func__, ret);
+		}
+	}
+	input_info(true, &client->dev, "%s: SPI interface(%d Hz)\n",
+		   __func__, client->max_speed_hz);
+#endif
+	/* parse dt */
+	if (client->dev.of_node) {
+		pdata = devm_kzalloc(&client->dev,
+				sizeof(struct sec_ts_plat_data), GFP_KERNEL);
+
+		if (!pdata) {
+			input_err(true, &client->dev,
+				"%s: Failed to allocate platform data\n",
+				__func__);
+			goto error_allocate_pdata;
+		}
+
+		client->dev.platform_data = pdata;
+
+		ret = sec_ts_parse_dt(client);
+		if (ret) {
+			input_err(true, &client->dev,
+				  "%s: Failed to parse dt\n", __func__);
+			goto error_allocate_mem;
+		}
+	} else {
+		pdata = client->dev.platform_data;
+		if (!pdata) {
+			input_err(true, &client->dev,
+				  "%s: No platform data found\n", __func__);
+			goto error_allocate_pdata;
+		}
+	}
+
+	if (sec_ts_check_for_deferred_regulators(&client->dev)) {
+		input_err(true, &client->dev,
+				"sec_ts deferring for power regulators\n");
+		ret = -EPROBE_DEFER;
+		goto error_allocate_mem;
+	}
+
+	if (!pdata->power) {
+		input_err(true, &client->dev, "%s: No power contorl found\n",
+			  __func__);
+		goto error_allocate_mem;
+	}
+
+	pdata->pinctrl = devm_pinctrl_get(&client->dev);
+	if (IS_ERR(pdata->pinctrl))
+		input_err(true, &client->dev, "%s: could not get pinctrl\n",
+			  __func__);
+
+	ts = kzalloc(sizeof(struct sec_ts_data), GFP_KERNEL);
+	if (!ts)
+		goto error_allocate_mem;
+
+	ts->client = client;
+	ts->plat_data = pdata;
+	ts->crc_addr = 0x0001FE00;
+	ts->fw_addr = 0x00002000;
+	ts->para_addr = 0x18000;
+	ts->flash_page_size = SEC_TS_FW_BLK_SIZE_DEFAULT;
+	ts->sec_ts_read = sec_ts_read;
+	ts->sec_ts_read_heap = sec_ts_read_heap;
+	ts->sec_ts_write = sec_ts_write;
+	ts->sec_ts_write_burst = sec_ts_write_burst;
+	ts->sec_ts_write_burst_heap = sec_ts_write_burst_heap;
+	ts->sec_ts_read_bulk = sec_ts_read_bulk;
+	ts->sec_ts_read_bulk_heap = sec_ts_read_bulk_heap;
+	ts->io_burstmax = pdata->io_burstmax;
+#ifdef USE_POWER_RESET_WORK
+	INIT_DELAYED_WORK(&ts->reset_work, sec_ts_reset_work);
+#endif
+	INIT_WORK(&ts->suspend_work, sec_ts_suspend_work);
+	INIT_WORK(&ts->resume_work, sec_ts_resume_work);
+#ifdef USE_CHARGER_WORK
+	INIT_WORK(&ts->charger_work, sec_ts_charger_work);
+#endif
+	ts->event_wq = alloc_workqueue("sec_ts-event-queue", WQ_UNBOUND |
+					 WQ_HIGHPRI | WQ_CPU_INTENSIVE, 1);
+	if (!ts->event_wq) {
+		input_err(true, &ts->client->dev,
+			"%s: Cannot create work thread\n", __func__);
+		ret = -ENOMEM;
+		goto error_alloc_workqueue;
+	}
+
+	init_completion(&ts->bus_resumed);
+	complete_all(&ts->bus_resumed);
+
+#ifdef SEC_TS_FW_UPDATE_ON_PROBE
+	INIT_WORK(&ts->fw_update_work, sec_ts_fw_update_work);
+#else
+	input_info(true, &ts->client->dev, "%s: fw update on probe disabled!\n",
+		   __func__);
+	ts->fw_update_wq = alloc_workqueue("sec_ts-fw-update-queue",
+					    WQ_UNBOUND | WQ_HIGHPRI |
+					    WQ_CPU_INTENSIVE, 1);
+	if (!ts->fw_update_wq) {
+		input_err(true, &ts->client->dev,
+			  "%s: Can't alloc fw update work thread\n",
+			  __func__);
+		ret = -ENOMEM;
+		goto error_alloc_fw_update_wq;
+	}
+	INIT_DELAYED_WORK(&ts->fw_update_work, sec_ts_fw_update_work);
+#endif
+
+	ts->is_fw_corrupted = false;
+
+	/* Assume screen is on throughout probe */
+	ts->bus_refmask = SEC_TS_BUS_REF_SCREEN_ON;
+#ifdef I2C_INTERFACE
+	i2c_set_clientdata(client, ts);
+#else
+	spi_set_drvdata(client, ts);
+#endif
+
+#if IS_ENABLED(CONFIG_TOUCHSCREEN_TBN)
+	if (register_tbn(&ts->tbn_register_mask)) {
+		ret = -ENODEV;
+		input_err(true, &ts->client->dev,
+			   "%s: Failed to register tbn context.\n", __func__);
+		goto err_init_tbn;
+	}
+	input_info(true, &ts->client->dev, "%s: tbn_register_mask = %#x.\n",
+		   __func__, ts->tbn_register_mask);
+#endif
+
+	if (gpio_is_valid(ts->plat_data->tsp_id))
+		ts->tspid_val = gpio_get_value(ts->plat_data->tsp_id);
+
+	if (gpio_is_valid(ts->plat_data->tsp_icid))
+		ts->tspicid_val = gpio_get_value(ts->plat_data->tsp_icid);
+
+	ts->input_dev = input_allocate_device();
+	if (!ts->input_dev) {
+		input_err(true, &ts->client->dev,
+			  "%s: allocate device err!\n", __func__);
+		ret = -ENOMEM;
+		goto err_allocate_input_dev;
+	}
+
+	if (ts->plat_data->support_dex) {
+		ts->input_dev_pad = input_allocate_device();
+		if (!ts->input_dev_pad) {
+			input_err(true, &ts->client->dev,
+				  "%s: allocate device err!\n", __func__);
+			ret = -ENOMEM;
+			goto err_allocate_input_dev_pad;
+		}
+	}
+
+	ts->touch_count = 0;
+	ts->tid_palm_state = 0;
+	ts->tid_grip_state = 0;
+	ts->tid_touch_state = 0;
+	ts->palms_leaved_once = false;
+	ts->grips_leaved_once = false;
+
+	ts->sec_ts_write = sec_ts_write;
+	ts->sec_ts_read = sec_ts_read;
+	ts->sec_ts_read_heap = sec_ts_read_heap;
+	ts->sec_ts_read_customlib = sec_ts_read_from_customlib;
+
+	ts->max_z_value = 0;
+	ts->min_z_value = 0xFFFFFFFF;
+	ts->sum_z_value = 0;
+
+	mutex_init(&ts->bus_mutex);
+	mutex_init(&ts->lock);
+	mutex_init(&ts->device_mutex);
+	mutex_init(&ts->io_mutex);
+	mutex_init(&ts->eventlock);
+
+	init_completion(&ts->resume_done);
+	complete_all(&ts->resume_done);
+
+	init_completion(&ts->boot_completed);
+	complete_all(&ts->boot_completed);
+
+	if (pdata->always_lpmode)
+		ts->lowpower_mode |= SEC_TS_MODE_CUSTOMLIB_FORCE_KEY;
+	else
+		ts->lowpower_mode &= ~SEC_TS_MODE_CUSTOMLIB_FORCE_KEY;
+
+	sec_ts_pinctrl_configure(ts, true);
+
+	/* power enable */
+	sec_ts_power(ts, true);
+	mdelay(10);
+	ret = gpio_direction_output(pdata->reset_gpio, 1);
+	mdelay(10);
+	ret = gpio_direction_output(pdata->reset_gpio, 0);
+	mdelay(10);
+	ret = gpio_direction_output(pdata->reset_gpio, 1);
+	mdelay(10);
+	if (!pdata->regulator_boot_on)
+		sec_ts_delay(70);
+	ts->power_status = SEC_TS_STATE_POWER_ON;
+	ts->external_factory = false;
+	ts->heatmap_init_done = false;
+	ts->mutual_strength_heatmap.timestamp = 0;
+	ts->mutual_strength_heatmap.size_x = 0;
+	ts->mutual_strength_heatmap.size_y = 0;
+	ts->mutual_strength_heatmap.data = NULL;
+	ts->v4l2_mutual_strength_updated = false;
+
+	ret = sec_ts_wait_for_ready(ts, SEC_TS_ACK_BOOT_COMPLETE);
+	if (ret < 0) {
+		u8 boot_status;
+		/* Read the boot status in case device is in bootloader mode */
+		ret = ts->sec_ts_read(ts, SEC_TS_READ_BOOT_STATUS,
+					  &boot_status, 1);
+		if (ret < 0) {
+			input_err(true, &ts->client->dev,
+				  "%s: could not read boot status. Assuming no device connected.\n",
+				  __func__);
+			ret = -EPROBE_DEFER;
+			goto err_init;
+		}
+
+		switch (boot_status) {
+		case SEC_TS_STATUS_BOOT_MODE:
+			input_err(true, &ts->client->dev,
+				"%s: boot timeout(status %#x)! Reflash FW to recover.\n",
+				__func__, boot_status);
+			sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_FW_UPDATE, true);
+			ret = sec_ts_firmware_update_on_probe(ts, true);
+			sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_FW_UPDATE, false);
+			if (ret) {
+				ts->is_fw_corrupted = true;
+				ret = -EPROBE_DEFER;
+				goto err_init;
+			}
+			break;
+		case SEC_TS_STATUS_APP_MODE:
+		default:
+			input_err(true, &ts->client->dev,
+				"%s: boot timeout(status %#x)! Reset system to recover.\n",
+				__func__, boot_status);
+			sec_ts_system_reset(ts, RESET_MODE_HW, true, false);
+			break;
+		}
+	}
+
+	input_info(true, &client->dev, "%s: power enable\n", __func__);
+
+	if (ts->is_fw_corrupted == false) {
+		switch (sec_ts_fw_init(ts)) {
+		case SEC_TS_ERR_INIT:
+			ret = -EPROBE_DEFER;
+			goto err_init;
+		case SEC_TS_ERR_ALLOC_FRAME:
+			goto err_allocate_frame;
+		case SEC_TS_ERR_ALLOC_FRAME_SS:
+			goto err_allocate_frame_ss;
+		case SEC_TS_ERR_ALLOC_GAINTABLE:
+			goto err_allocate_gaintable;
+		case SEC_TS_ERR_REG_INPUT_DEV:
+			goto err_input_register_device;
+		case SEC_TS_ERR_REG_INPUT_PAD_DEV:
+			goto err_input_pad_register_device;
+		}
+	}
+
+	cpu_latency_qos_add_request(&ts->pm_qos_req, PM_QOS_DEFAULT_VALUE);
+
+	ts->ignore_charger_nb = 0;
+	/* init motion filter mode */
+	ts->use_default_mf = 0;
+	ts->mf_state = SEC_TS_MF_FILTERED;
+
+	/* init heatmap */
+	if (ts->is_fw_corrupted == false) {
+		ret = sec_ts_heatmap_init(ts);
+		if (ret)
+			goto err_irq;
+	}
+
+	input_info(true, &ts->client->dev, "%s: request_irq = %d\n", __func__,
+			client->irq);
+
+	ret = request_threaded_irq(client->irq, sec_ts_isr, sec_ts_irq_thread,
+			ts->plat_data->irq_type, SEC_TS_NAME, ts);
+	if (ret < 0) {
+		input_err(true, &ts->client->dev,
+			"%s: Unable to request threaded irq\n", __func__);
+		goto err_heatmap;
+	}
+
+#if IS_ENABLED(CONFIG_TOUCHSCREEN_OFFLOAD)
+	ts->offload.caps.touch_offload_major_version =
+			TOUCH_OFFLOAD_INTERFACE_MAJOR_VERSION;
+	ts->offload.caps.touch_offload_minor_version =
+			TOUCH_OFFLOAD_INTERFACE_MINOR_VERSION;
+	ts->offload.caps.device_id = ts->plat_data->offload_id;
+	ts->offload.caps.display_width = ts->plat_data->max_x + 1;
+	ts->offload.caps.display_height = ts->plat_data->max_y + 1;
+	ts->offload.caps.tx_size = ts->tx_count;
+	ts->offload.caps.rx_size = ts->rx_count;
+	ts->offload.caps.heatmap_size = HEATMAP_SIZE_FULL;
+#ifdef I2C_INTERFACE
+	ts->offload.caps.bus_type = BUS_TYPE_I2C;
+	ts->offload.caps.bus_speed_hz = 1000000;
+#else
+	ts->offload.caps.bus_type = BUS_TYPE_SPI;
+	ts->offload.caps.bus_speed_hz = client->max_speed_hz;
+#endif
+
+	/* Currently can only reliably read mutual and self strength heatmaps
+	 * each frame. Cannot support other formats due to penalties associated
+	 * with switching data types.
+	 */
+	ts->offload.caps.touch_data_types =
+	    TOUCH_DATA_TYPE_COORD | TOUCH_DATA_TYPE_STRENGTH;
+	ts->offload.caps.touch_scan_types =
+	    TOUCH_SCAN_TYPE_MUTUAL | TOUCH_SCAN_TYPE_SELF;
+	ts->offload.caps.context_channel_types =
+			CONTEXT_CHANNEL_TYPE_DRIVER_STATUS;
+
+	ts->offload.caps.continuous_reporting = true;
+	ts->offload.caps.noise_reporting = false;
+	ts->offload.caps.cancel_reporting = false;
+	ts->offload.caps.rotation_reporting = true;
+	ts->offload.caps.size_reporting = true;
+	ts->offload.caps.auto_reporting = false;
+	ts->offload.caps.filter_grip = true;
+	ts->offload.caps.filter_palm = true;
+	ts->offload.caps.num_sensitivity_settings = 1;
+
+	ts->offload.hcallback = (void *)ts;
+	ts->offload.report_cb = sec_ts_offload_report;
+	touch_offload_init(&ts->offload);
+#endif
+
+#ifndef CONFIG_SEC_SYSFS
+	sec_class = class_create(THIS_MODULE, "sec");
+#endif
+
+	device_init_wakeup(&client->dev, true);
+
+	if (ts->is_fw_corrupted == false)
+		sec_ts_device_init(ts);
+
+#ifdef SEC_TS_FW_UPDATE_ON_PROBE
+	schedule_work(&ts->fw_update_work);
+
+	/* Do not finish probe without checking and flashing the firmware */
+	flush_work(&ts->fw_update_work);
+#else
+	queue_delayed_work(ts->fw_update_wq, &ts->fw_update_work,
+		    msecs_to_jiffies(SEC_TS_FW_UPDATE_DELAY_MS_AFTER_PROBE));
+#endif
+
+#if defined(CONFIG_TOUCHSCREEN_DUMP_MODE)
+	dump_callbacks.inform_dump = dump_tsp_log;
+	INIT_DELAYED_WORK(&ts->ghost_check, sec_ts_check_rawdata);
+	p_ghost_check = &ts->ghost_check;
+#endif
+
+	ts_dup = ts;
+	ts->probe_done = true;
+
+	ts->wlc_online = false;
+	ts->usb_present = false;
+	ts->charger_mode = SEC_TS_BIT_CHARGER_MODE_NO;
+	ts->wireless_psy = power_supply_get_by_name("wireless");
+	ts->usb_psy = power_supply_get_by_name("usb");
+#ifdef USE_CHARGER_WORK
+	ts->psy_nb = sec_ts_psy_nb;
+	ret = power_supply_reg_notifier(&ts->psy_nb);
+	if (ret < 0)
+		input_err(true, &ts->client->dev, "psy notifier register failed\n");
+#endif
+	input_info(true, &ts->client->dev, "%s: done\n", __func__);
+	input_log_fix();
+
+	return 0;
+
+	/* need to be enabled when new goto statement is added */
+/*
+ *	sec_ts_fn_remove(ts);
+ *	free_irq(client->irq, ts);
+ **/
+#if IS_ENABLED(CONFIG_TOUCHSCREEN_OFFLOAD)
+	touch_offload_cleanup(&ts->offload);
+#endif
+
+err_heatmap:
+#if IS_ENABLED(CONFIG_TOUCHSCREEN_HEATMAP)
+	heatmap_remove(&ts->v4l2);
+err_irq:
+#endif
+	cpu_latency_qos_remove_request(&ts->pm_qos_req);
+	if (ts->plat_data->support_dex) {
+		input_unregister_device(ts->input_dev_pad);
+		ts->input_dev_pad = NULL;
+	}
+err_input_pad_register_device:
+	input_unregister_device(ts->input_dev);
+	ts->input_dev = NULL;
+	ts->input_dev_touch = NULL;
+err_input_register_device:
+#ifdef USE_STIM_PAD
+	kfree(ts->gainTable);
+#endif
+err_allocate_gaintable:
+	kfree(ts->pFrameSS);
+err_allocate_frame_ss:
+	kfree(ts->pFrame);
+err_allocate_frame:
+err_init:
+	sec_ts_power(ts, false);
+	if (ts->plat_data->support_dex) {
+		if (ts->input_dev_pad)
+			input_free_device(ts->input_dev_pad);
+	}
+err_allocate_input_dev_pad:
+	if (ts->input_dev)
+		input_free_device(ts->input_dev);
+err_allocate_input_dev:
+#if IS_ENABLED(CONFIG_TOUCHSCREEN_TBN)
+	if (ts->tbn_register_mask)
+		unregister_tbn(&ts->tbn_register_mask);
+err_init_tbn:
+#endif
+
+#ifndef SEC_TS_FW_UPDATE_ON_PROBE
+	if (ts->fw_update_wq)
+		destroy_workqueue(ts->fw_update_wq);
+error_alloc_fw_update_wq:
+#endif
+
+	if (ts->event_wq)
+		destroy_workqueue(ts->event_wq);
+error_alloc_workqueue:
+	kfree(ts);
+
+error_allocate_mem:
+	if (gpio_is_valid(pdata->irq_gpio))
+		gpio_free(pdata->irq_gpio);
+	if (gpio_is_valid(pdata->tsp_id))
+		gpio_free(pdata->tsp_id);
+	if (gpio_is_valid(pdata->tsp_icid))
+		gpio_free(pdata->tsp_icid);
+	if (gpio_is_valid(pdata->switch_gpio))
+		gpio_free(pdata->switch_gpio);
+	if (gpio_is_valid(pdata->reset_gpio))
+		gpio_free(pdata->reset_gpio);
+
+error_allocate_pdata:
+	if (ret == -ECONNREFUSED)
+		sec_ts_delay(100);
+	if (ret != -EPROBE_DEFER)
+		ret = -ENODEV;
+#ifdef CONFIG_TOUCHSCREEN_DUMP_MODE
+	p_ghost_check = NULL;
+#endif
+	ts_dup = NULL;
+	input_err(true, &client->dev, "%s: failed(%d)\n", __func__, ret);
+	input_log_fix();
+	return ret;
+}
+
+void sec_ts_unlocked_release_all_finger(struct sec_ts_data *ts)
+{
+	int i;
+	s64 ms_delta;
+
+	for (i = 0; i < MAX_SUPPORT_TOUCH_COUNT; i++) {
+		input_mt_slot(ts->input_dev, i);
+		if (ts->plat_data->support_mt_pressure)
+			input_report_abs(ts->input_dev, ABS_MT_PRESSURE, 0);
+		input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER,
+					   false);
+
+		if ((ts->coord[i].action == SEC_TS_COORDINATE_ACTION_PRESS) ||
+			(ts->coord[i].action ==
+			 SEC_TS_COORDINATE_ACTION_MOVE)) {
+
+			input_info(true, &ts->client->dev,
+				"%s: [RA] tID: %d mc: %d tc: %u v: %02X%02X cal: %02X(%02X) id(%d,%d)\n",
+				__func__, i,
+				ts->coord[i].mcount, ts->touch_count,
+				ts->plat_data->img_version_of_ic[2],
+				ts->plat_data->img_version_of_ic[3],
+				ts->cal_status, ts->nv, ts->tspid_val,
+				ts->tspicid_val);
+
+			ts->coord[i].ktime_released = ktime_get();
+			ms_delta = ktime_ms_delta(ts->coord[i].ktime_released,
+						ts->coord[i].ktime_pressed);
+			if (ts->longest_duration < ms_delta)
+				ts->longest_duration = ms_delta;
+
+			/* special case to push into kfifo during release all fingers. */
+			sec_ts_kfifo_push_coord(ts, i);
+		}
+
+#if IS_ENABLED(CONFIG_TOUCHSCREEN_OFFLOAD)
+		ts->offload.coords[i].status = COORD_STATUS_INACTIVE;
+		ts->offload.coords[i].major = 0;
+		ts->offload.coords[i].minor = 0;
+		ts->offload.coords[i].pressure = 0;
+		ts->offload.coords[i].rotation = 0;
+#endif
+		ts->coord[i].action = SEC_TS_COORDINATE_ACTION_RELEASE;
+		ts->coord[i].mcount = 0;
+	}
+
+	input_mt_slot(ts->input_dev, 0);
+
+	input_report_key(ts->input_dev, BTN_TOUCH, false);
+	input_report_key(ts->input_dev, BTN_TOOL_FINGER, false);
+#ifdef SW_GLOVE
+	input_report_switch(ts->input_dev, SW_GLOVE, false);
+#endif
+	ts->touchkey_glove_mode_status = false;
+	ts->touch_count = 0;
+	ts->check_multi = 0;
+	ts->tid_palm_state = 0;
+	ts->tid_grip_state = 0;
+	ts->tid_touch_state = 0;
+	ts->palms_leaved_once = false;
+	ts->grips_leaved_once = false;
+
+#ifdef KEY_SIDE_GESTURE
+	if (ts->plat_data->support_sidegesture) {
+		input_report_key(ts->input_dev, KEY_SIDE_GESTURE, 0);
+		input_report_key(ts->input_dev, KEY_SIDE_GESTURE_LEFT, 0);
+		input_report_key(ts->input_dev, KEY_SIDE_GESTURE_RIGHT, 0);
+	}
+#endif
+	input_report_key(ts->input_dev, KEY_HOMEPAGE, 0);
+	input_sync(ts->input_dev);
+}
+
+void sec_ts_locked_release_all_finger(struct sec_ts_data *ts)
+{
+	mutex_lock(&ts->eventlock);
+	sec_ts_unlocked_release_all_finger(ts);
+	mutex_unlock(&ts->eventlock);
+}
+
+#ifdef USE_POWER_RESET_WORK
+static void sec_ts_reset_work(struct work_struct *work)
+{
+	struct sec_ts_data *ts = container_of(work, struct sec_ts_data,
+							reset_work.work);
+
+	ts->reset_is_on_going = true;
+	input_info(true, &ts->client->dev, "%s\n", __func__);
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_RESET, true);
+
+	sec_ts_stop_device(ts);
+
+	sec_ts_delay(30);
+
+	sec_ts_start_device(ts);
+
+	ts->reset_is_on_going = false;
+	ts->plat_data->is_heatmap_enabled = false;
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_RESET, false);
+}
+#endif
+
+void sec_ts_read_init_info(struct sec_ts_data *ts)
+{
+#ifndef CONFIG_SEC_FACTORY
+	struct sec_ts_test_mode mode;
+	char para = TO_TOUCH_MODE;
+#endif
+#ifdef USE_PRESSURE_SENSOR
+	unsigned char data[18] = { 0 };
+#endif
+	int ret;
+
+	ts->nv = get_tsp_nvm_data(ts, SEC_TS_NVM_OFFSET_FAC_RESULT);
+	ts->cal_count = get_tsp_nvm_data(ts, SEC_TS_NVM_OFFSET_CAL_COUNT);
+	ts->pressure_cal_base = get_tsp_nvm_data(ts,
+				SEC_TS_NVM_OFFSET_PRESSURE_BASE_CAL_COUNT);
+	ts->pressure_cal_delta = get_tsp_nvm_data(ts,
+				SEC_TS_NVM_OFFSET_PRESSURE_DELTA_CAL_COUNT);
+
+	input_info(true, &ts->client->dev,
+		    "%s: fac_nv: %02X, cal_count: %02X\n",
+		    __func__, ts->nv, ts->cal_count);
+
+#ifdef PAT_CONTROL
+	ts->tune_fix_ver = (get_tsp_nvm_data(ts,
+				SEC_TS_NVM_OFFSET_TUNE_VERSION) << 8) |
+			    get_tsp_nvm_data(ts,
+				SEC_TS_NVM_OFFSET_TUNE_VERSION + 1);
+	input_info(true, &ts->client->dev,
+	    "%s: tune_fix_ver [%04X]\n", __func__, ts->tune_fix_ver);
+#endif
+
+#ifdef USE_PRESSURE_SENSOR
+	ret = ts->sec_ts_read(ts, SEC_TS_CMD_SET_GET_PRESSURE, data, 18);
+	if (ret < 0)
+		return;
+
+	ts->pressure_left = ((data[16] << 8) | data[17]);
+	ts->pressure_center = ((data[8] << 8) | data[9]);
+	ts->pressure_right = ((data[0] << 8) | data[1]);
+	input_info(true, &ts->client->dev,
+		"%s: left: %d, center: %d, right: %d\n", __func__,
+		ts->pressure_left, ts->pressure_center, ts->pressure_right);
+#endif
+
+#ifndef CONFIG_SEC_FACTORY
+	/* run self-test */
+	disable_irq(ts->client->irq);
+	execute_selftest(ts,
+		TEST_OPEN | TEST_NODE_VARIANCE |
+		TEST_SHORT | TEST_SELF_NODE | TEST_NOT_SAVE);
+	enable_irq(ts->client->irq);
+
+	input_info(true, &ts->client->dev, "%s: %02X %02X %02X %02X\n",
+		__func__, ts->ito_test[0], ts->ito_test[1]
+		, ts->ito_test[2], ts->ito_test[3]);
+
+	ret = ts->sec_ts_write(ts, SEC_TS_CMD_SET_POWER_MODE, &para, 1);
+	if (ret < 0)
+		input_err(true, &ts->client->dev, "%s: Failed to set\n",
+				__func__);
+
+	sec_ts_delay(350);
+
+	/* run ambient read */
+	memset(&mode, 0x00, sizeof(struct sec_ts_test_mode));
+	mode.type = TYPE_AMBIENT_DATA;
+	mode.allnode = TEST_MODE_ALL_NODE;
+
+	sec_ts_read_raw_data(ts, NULL, &mode);
+#endif
+
+	input_log_fix();
+}
+
+static void sec_ts_fw_update_work(struct work_struct *work)
+{
+#ifdef SEC_TS_FW_UPDATE_ON_PROBE
+	struct sec_ts_data *ts = container_of(work, struct sec_ts_data,
+					      fw_update_work);
+#else
+	struct delayed_work *fw_update_work = container_of(work,
+					struct delayed_work, work);
+	struct sec_ts_data *ts = container_of(fw_update_work,
+					struct sec_ts_data, fw_update_work);
+#endif
+
+	int ret;
+
+	input_info(true, &ts->client->dev,
+		   "%s: Beginning firmware update after probe.\n", __func__);
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_FW_UPDATE, true);
+
+	ret = sec_ts_firmware_update_on_probe(ts, false);
+	if (ret < 0)
+		input_info(true, &ts->client->dev,
+			   "%s: firmware update was unsuccessful.\n",
+			   __func__);
+
+	if (ts->is_fw_corrupted == true && ret == 0) {
+		ret = sec_ts_fw_init(ts);
+		if (ret == SEC_TS_ERR_NA) {
+			ts->is_fw_corrupted = false;
+			sec_ts_device_init(ts);
+		} else {
+			input_info(true, &ts->client->dev,
+				"%s: fail to sec_ts_fw_init 0x%x\n",
+				__func__, ret);
+		}
+	}
+
+	if (ts->is_fw_corrupted == false)
+		sec_ts_read_init_info(ts);
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_FW_UPDATE, false);
+
+	ret = register_panel_bridge(ts);
+	if (ret < 0)
+		input_err(true, &ts->client->dev,
+			  "%s: register_panel_bridge failed. ret = 0x%08X\n",
+			  __func__, ret);
+}
+
+int sec_ts_set_lowpowermode(struct sec_ts_data *ts, u8 mode)
+{
+	int ret;
+	int retrycnt = 0;
+	u8 data;
+	char para = 0;
+
+	input_err(true, &ts->client->dev, "%s: %s(%X)\n", __func__,
+			mode == TO_LOWPOWER_MODE ? "ENTER" : "EXIT",
+			ts->lowpower_mode);
+
+	if (mode) {
+		#ifdef SEC_TS_SUPPORT_CUSTOMLIB
+		if (ts->use_customlib)
+			sec_ts_set_custom_library(ts);
+		#endif
+
+		data = (ts->lowpower_mode & SEC_TS_MODE_LOWPOWER_FLAG) >> 1;
+		ret = sec_ts_write(ts, SEC_TS_CMD_WAKEUP_GESTURE_MODE,
+				   &data, 1);
+		if (ret < 0)
+			input_err(true, &ts->client->dev,
+				  "%s: Failed to set\n", __func__);
+	}
+
+retry_pmode:
+	ret = sec_ts_write(ts, SEC_TS_CMD_SET_POWER_MODE, &mode, 1);
+	if (ret < 0)
+		input_err(true, &ts->client->dev,
+				"%s: failed\n", __func__);
+	sec_ts_delay(50);
+
+	/* read data */
+
+	ret = sec_ts_read(ts, SEC_TS_CMD_SET_POWER_MODE, &para, 1);
+	if (ret < 0)
+		input_err(true, &ts->client->dev,
+			  "%s: read power mode failed!\n", __func__);
+	else
+		input_info(true, &ts->client->dev,
+			   "%s: power mode - write(%d) read(%d)\n",
+			   __func__, mode, para);
+
+	if (mode != para) {
+		retrycnt++;
+		if (retrycnt < 5)
+			goto retry_pmode;
+	}
+
+	ret = sec_ts_write(ts, SEC_TS_CMD_CLEAR_EVENT_STACK, NULL, 0);
+	if (ret < 0)
+		input_err(true, &ts->client->dev,
+			  "%s: write clear event failed\n", __func__);
+
+
+	sec_ts_locked_release_all_finger(ts);
+
+	if (device_may_wakeup(&ts->client->dev)) {
+		if (mode)
+			enable_irq_wake(ts->client->irq);
+		else
+			disable_irq_wake(ts->client->irq);
+	}
+
+	ts->lowpower_status = mode;
+	input_info(true, &ts->client->dev, "%s: end\n", __func__);
+
+	return ret;
+}
+
+#ifdef USE_OPEN_CLOSE
+static int sec_ts_input_open(struct input_dev *dev)
+{
+	struct sec_ts_data *ts = input_get_drvdata(dev);
+	int ret;
+
+	ts->input_closed = false;
+
+	input_info(true, &ts->client->dev, "%s\n", __func__);
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_INPUT_DEV, true);
+
+	if (ts->lowpower_status) {
+#ifdef USE_RESET_EXIT_LPM
+		schedule_delayed_work(&ts->reset_work,
+				      msecs_to_jiffies(TOUCH_RESET_DWORK_TIME));
+#else
+		sec_ts_set_lowpowermode(ts, TO_TOUCH_MODE);
+#endif
+		ts->power_status = SEC_TS_STATE_POWER_ON;
+	} else {
+		ret = sec_ts_start_device(ts);
+		if (ret < 0)
+			input_err(true, &ts->client->dev,
+				  "%s: Failed to start device\n", __func__);
+	}
+
+	/* because edge and dead zone will recover soon */
+	sec_ts_set_grip_type(ts, ONLY_EDGE_HANDLER);
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_INPUT_DEV, false);
+
+	return 0;
+}
+
+static void sec_ts_input_close(struct input_dev *dev)
+{
+	struct sec_ts_data *ts = input_get_drvdata(dev);
+
+	ts->input_closed = true;
+
+	input_info(true, &ts->client->dev, "%s\n", __func__);
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_INPUT_DEV, true);
+
+	cancel_work_sync(&ts->suspend_work);
+	cancel_work_sync(&ts->resume_work);
+
+#ifdef USE_POWER_RESET_WORK
+	cancel_delayed_work(&ts->reset_work);
+#endif
+
+#ifndef CONFIG_SEC_FACTORY
+	ts->lowpower_mode |= SEC_TS_MODE_CUSTOMLIB_FORCE_KEY;
+#endif
+	if (ts->lowpower_mode) {
+		sec_ts_set_lowpowermode(ts, TO_LOWPOWER_MODE);
+		ts->power_status = SEC_TS_STATE_LPM;
+	} else {
+		sec_ts_stop_device(ts);
+	}
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_INPUT_DEV, false);
+}
+#endif
+
+#ifdef I2C_INTERFACE
+static void sec_ts_remove(struct i2c_client *client)
+#else
+static void sec_ts_remove(struct spi_device *client)
+#endif
+{
+#ifdef I2C_INTERFACE
+	struct sec_ts_data *ts = i2c_get_clientdata(client);
+#else
+	struct sec_ts_data *ts = spi_get_drvdata(client);
+#endif
+	/* const struct sec_ts_plat_data *pdata = ts->plat_data; */
+	bool fw_update_cancelled = false;
+
+	input_info(true, &ts->client->dev, "%s\n", __func__);
+
+	if (ts_dup == NULL || ts->probe_done == false)
+		return;
+
+	/* Force the bus active throughout removal of the client */
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_FORCE_ACTIVE, true);
+
+	power_supply_unreg_notifier(&ts->psy_nb);
+
+	cancel_work_sync(&ts->suspend_work);
+	cancel_work_sync(&ts->resume_work);
+#ifdef USE_CHARGER_WORK
+	cancel_work_sync(&ts->charger_work);
+#endif
+	destroy_workqueue(ts->event_wq);
+
+#ifdef SEC_TS_FW_UPDATE_ON_PROBE
+	fw_update_cancelled = cancel_work_sync(&ts->fw_update_work);
+#else
+	fw_update_cancelled = cancel_delayed_work_sync(&ts->fw_update_work);
+	destroy_workqueue(ts->fw_update_wq);
+#endif
+	if (!fw_update_cancelled)
+		unregister_panel_bridge(&ts->panel_bridge);
+
+	disable_irq_nosync(ts->client->irq);
+	free_irq(ts->client->irq, ts);
+	input_info(true, &ts->client->dev, "%s: irq disabled\n", __func__);
+
+#if IS_ENABLED(CONFIG_TOUCHSCREEN_OFFLOAD)
+	touch_offload_cleanup(&ts->offload);
+#endif
+
+#if IS_ENABLED(CONFIG_TOUCHSCREEN_HEATMAP)
+	heatmap_remove(&ts->v4l2);
+#endif
+
+	cpu_latency_qos_remove_request(&ts->pm_qos_req);
+
+#ifdef USE_POWER_RESET_WORK
+	cancel_delayed_work_sync(&ts->reset_work);
+	flush_delayed_work(&ts->reset_work);
+
+	input_info(true, &ts->client->dev, "%s: flush queue\n", __func__);
+
+#endif
+
+	sec_ts_fn_remove(ts);
+
+#ifdef CONFIG_TOUCHSCREEN_DUMP_MODE
+	p_ghost_check = NULL;
+#endif
+	device_init_wakeup(&client->dev, false);
+
+	ts->lowpower_mode = false;
+	ts->probe_done = false;
+
+	if (ts->plat_data->support_dex) {
+		input_mt_destroy_slots(ts->input_dev_pad);
+		input_unregister_device(ts->input_dev_pad);
+	}
+
+	ts->input_dev = ts->input_dev_touch;
+	input_mt_destroy_slots(ts->input_dev);
+	input_unregister_device(ts->input_dev);
+
+	ts->input_dev_pad = NULL;
+	ts->input_dev = NULL;
+	ts->input_dev_touch = NULL;
+	ts_dup = NULL;
+
+	/* need to do software reset for next sec_ts_probe() without error */
+	ts->sec_ts_write(ts, SEC_TS_CMD_SW_RESET, NULL, 0);
+
+	ts->plat_data->power(ts, false);
+
+#if IS_ENABLED(CONFIG_TOUCHSCREEN_TBN)
+	if (ts->tbn_register_mask)
+		unregister_tbn(&ts->tbn_register_mask);
+#endif
+
+	if (gpio_is_valid(ts->plat_data->irq_gpio))
+		gpio_free(ts->plat_data->irq_gpio);
+	if (gpio_is_valid(ts->plat_data->switch_gpio))
+		gpio_free(ts->plat_data->switch_gpio);
+	if (gpio_is_valid(ts->plat_data->reset_gpio))
+		gpio_free(ts->plat_data->reset_gpio);
+
+	sec_ts_raw_device_exit(ts);
+#ifndef CONFIG_SEC_SYSFS
+	class_destroy(sec_class);
+#endif
+
+#if IS_ENABLED(CONFIG_TOUCHSCREEN_HEATMAP)
+	kfree(ts->heatmap_buff);
+	kfree(ts->encoded_buff);
+#endif
+#ifdef USE_STIM_PAD
+	kfree(ts->gainTable);
+#endif
+	kfree(ts->pFrameSS);
+	kfree(ts->pFrame);
+	kfree(ts);
+}
+
+#ifdef I2C_INTERFACE
+static void sec_ts_shutdown(struct i2c_client *client)
+#else
+static void sec_ts_shutdown(struct spi_device *client)
+#endif
+{
+	pr_info("%s\n", __func__);
+	if (ts_dup)
+		sec_ts_remove(client);
+}
+
+int sec_ts_stop_device(struct sec_ts_data *ts)
+{
+	input_info(true, &ts->client->dev, "%s\n", __func__);
+
+	mutex_lock(&ts->device_mutex);
+
+	if (ts->power_status == SEC_TS_STATE_POWER_OFF) {
+		input_err(true, &ts->client->dev,
+			  "%s: already power off\n", __func__);
+		goto out;
+	}
+
+	ts->power_status = SEC_TS_STATE_POWER_OFF;
+
+	disable_irq(ts->client->irq);
+	sec_ts_locked_release_all_finger(ts);
+
+	ts->plat_data->power(ts, false);
+
+	if (ts->plat_data->enable_sync)
+		ts->plat_data->enable_sync(false);
+
+	sec_ts_pinctrl_configure(ts, false);
+
+out:
+	mutex_unlock(&ts->device_mutex);
+	return 0;
+}
+
+int sec_ts_start_device(struct sec_ts_data *ts)
+{
+	int ret;
+
+	input_info(true, &ts->client->dev, "%s\n", __func__);
+
+	sec_ts_pinctrl_configure(ts, true);
+
+	mutex_lock(&ts->device_mutex);
+
+	if (ts->power_status == SEC_TS_STATE_POWER_ON) {
+		input_info(true, &ts->client->dev,
+			  "%s: already power on\n", __func__);
+		goto out;
+	}
+
+	sec_ts_locked_release_all_finger(ts);
+
+	ts->plat_data->power(ts, true);
+	sec_ts_delay(70);
+	ts->power_status = SEC_TS_STATE_POWER_ON;
+	sec_ts_wait_for_ready(ts, SEC_TS_ACK_BOOT_COMPLETE);
+
+	if (ts->plat_data->enable_sync)
+		ts->plat_data->enable_sync(true);
+
+	if (ts->flip_enable) {
+		ret = sec_ts_write(ts, SEC_TS_CMD_SET_COVERTYPE,
+				   &ts->cover_cmd, 1);
+
+		ts->touch_functions = ts->touch_functions |
+				SEC_TS_BIT_SETFUNC_COVER;
+		input_info(true, &ts->client->dev,
+				"%s: cover cmd write type: %d, mode: %x, ret: %d",
+				__func__, ts->touch_functions,
+				ts->cover_cmd, ret);
+	} else {
+		ts->touch_functions = (ts->touch_functions &
+				       (~SEC_TS_BIT_SETFUNC_COVER));
+		input_info(true, &ts->client->dev,
+			"%s: cover open, not send cmd", __func__);
+	}
+
+	ts->touch_functions = ts->touch_functions |
+				SEC_TS_DEFAULT_ENABLE_BIT_SETFUNC;
+	ret = sec_ts_write(ts, SEC_TS_CMD_SET_TOUCHFUNCTION,
+			   (u8 *)&ts->touch_functions, 2);
+	if (ret < 0)
+		input_err(true, &ts->client->dev,
+			"%s: Failed to send touch function command", __func__);
+
+	#ifdef SEC_TS_SUPPORT_CUSTOMLIB
+	if (ts->use_customlib)
+		sec_ts_set_custom_library(ts);
+	#endif
+
+	sec_ts_set_grip_type(ts, ONLY_EDGE_HANDLER);
+
+	if (ts->dex_mode) {
+		input_info(true, &ts->client->dev,
+			   "%s: set dex mode\n", __func__);
+		ret = ts->sec_ts_write(ts, SEC_TS_CMD_SET_DEX_MODE,
+				       &ts->dex_mode, 1);
+		if (ret < 0)
+			input_err(true, &ts->client->dev,
+				"%s: failed to set dex mode %x\n",
+				__func__, ts->dex_mode);
+	}
+
+	if (ts->brush_mode) {
+		input_info(true, &ts->client->dev,
+			   "%s: set brush mode\n", __func__);
+		ret = ts->sec_ts_write(ts, SEC_TS_CMD_SET_BRUSH_MODE,
+				       &ts->brush_mode, 1);
+		if (ret < 0)
+			input_err(true, &ts->client->dev,
+				"%s: failed to set brush mode\n", __func__);
+	}
+
+	if (ts->touchable_area) {
+		input_info(true, &ts->client->dev,
+			   "%s: set 16:9 mode\n", __func__);
+		ret = ts->sec_ts_write(ts, SEC_TS_CMD_SET_TOUCHABLE_AREA,
+				       &ts->touchable_area, 1);
+		if (ret < 0)
+			input_err(true, &ts->client->dev,
+				"%s: failed to set 16:9 mode\n", __func__);
+	}
+
+	/* Sense_on */
+	ret = sec_ts_write(ts, SEC_TS_CMD_SENSE_ON, NULL, 0);
+	if (ret < 0)
+		input_err(true, &ts->client->dev,
+			  "%s: fail to write Sense_on\n", __func__);
+
+	enable_irq(ts->client->irq);
+
+out:
+	mutex_unlock(&ts->device_mutex);
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int sec_ts_pm_suspend(struct device *dev)
+{
+	struct sec_ts_data *ts = dev_get_drvdata(dev);
+
+	if (ts->bus_refmask) {
+		input_info(true, &ts->client->dev,
+			"%s: bus_refmask 0x%X\n", __func__, ts->bus_refmask);
+	}
+
+	/* Flush work in case a suspend is in progress */
+	flush_workqueue(ts->event_wq);
+
+	if (ts->power_status != SEC_TS_STATE_SUSPEND) {
+		input_err(true, &ts->client->dev,
+			"%s: can't suspend because touch bus is in use!\n",
+			__func__);
+		if (ts->bus_refmask == SEC_TS_BUS_REF_BUGREPORT) {
+			s64 delta_ms = ktime_ms_delta(ktime_get(),
+						      ts->bugreport_ktime_start);
+
+			if (delta_ms > 30 * MSEC_PER_SEC) {
+				sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_BUGREPORT, false);
+				pm_relax(&ts->client->dev);
+				ts->bugreport_ktime_start = 0;
+				input_err(true, &ts->client->dev,
+					  "%s: force release SEC_TS_BUS_REF_BUGREPORT(delta: %lld)!\n",
+					   __func__, delta_ms);
+			}
+		}
+		return -EBUSY;
+	}
+
+	if (ts->lowpower_mode)
+		reinit_completion(&ts->resume_done);
+
+	return 0;
+}
+
+static int sec_ts_pm_resume(struct device *dev)
+{
+	struct sec_ts_data *ts = dev_get_drvdata(dev);
+
+	if (ts->lowpower_mode)
+		complete_all(&ts->resume_done);
+
+	return 0;
+}
+#endif
+
+static const struct i2c_device_id sec_ts_id[] = {
+	{ SEC_TS_NAME, 0 },
+	{ },
+};
+
+#ifdef CONFIG_PM
+static const struct dev_pm_ops sec_ts_dev_pm_ops = {
+	.suspend = sec_ts_pm_suspend,
+	.resume = sec_ts_pm_resume,
+};
+#endif
+
+/*
+ * Configure the switch GPIO to toggle bus master between AP and SLPI.
+ * gpio_value takes one of
+ * { SEC_SWITCH_GPIO_VALUE_SLPI_MASTER, SEC_SWITCH_GPIO_VALUE_AP_MASTER }
+ */
+static void sec_set_switch_gpio(struct sec_ts_data *ts, int gpio_value)
+{
+	int retval;
+	unsigned int gpio = ts->plat_data->switch_gpio;
+
+	if (!gpio_is_valid(gpio))
+		return;
+
+	input_info(true, &ts->client->dev, "%s: toggling switch to %s\n",
+		   __func__, gpio_value == SEC_SWITCH_GPIO_VALUE_AP_MASTER ?
+		   "AP" : "SLPI");
+
+	retval = gpio_direction_output(gpio, gpio_value);
+	if (retval < 0)
+		input_err(true, &ts->client->dev,
+			  "%s: Failed to toggle switch_gpio, err = %d\n",
+			  __func__, retval);
+}
+
+static void sec_ts_suspend_work(struct work_struct *work)
+{
+	struct sec_ts_data *ts = container_of(work, struct sec_ts_data,
+					      suspend_work);
+	int ret = 0;
+
+	input_info(true, &ts->client->dev, "%s: int_cnt %llu.\n", __func__, ts->int_cnt);
+	input_info(true, &ts->client->dev, "%s: encoded skipped %d/%d\n",
+		   __func__, ts->plat_data->encoded_skip_counter,
+		   ts->plat_data->encoded_frame_counter);
+	if (ts->plat_data->grip_prescreen_mode != GRIP_PRESCREEN_OFF) {
+		input_info(true, &ts->client->dev, "%s: grip prescreened frames %d.\n",
+			__func__, sec_ts_ptflib_get_grip_prescreen_frames(ts));
+	}
+
+	if (ts->power_status == SEC_TS_STATE_SUSPEND) {
+		input_err(true, &ts->client->dev, "%s: already suspended.\n",
+			  __func__);
+		return;
+	}
+
+	mutex_lock(&ts->device_mutex);
+	/*
+	 * Do the system reset to initialize the FW to the default state
+	 * before handing over to AOC. And, recover the charger mode to
+	 * have the AFE setting as the original one.
+	 */
+	sec_ts_system_reset(ts, RESET_MODE_AUTO, true, false);
+	ret = ts->sec_ts_write(ts, SET_TS_CMD_SET_CHARGER_MODE,
+			       &ts->charger_mode, 1);
+	if (ret < 0) {
+		input_err(true, &ts->client->dev,
+			  "%s: write reg %#x %#x failed, returned %i\n",
+			__func__, SET_TS_CMD_SET_CHARGER_MODE, ts->charger_mode,
+			ret);
+	} else {
+		input_info(true, &ts->client->dev, "%s: set charger mode %#x\n",
+			__func__, ts->charger_mode);
+	}
+
+	reinit_completion(&ts->bus_resumed);
+	sec_ts_enable_fw_grip(ts, true);
+
+	/* Stop T-IC */
+	sec_ts_fix_tmode(ts, TOUCH_SYSTEM_MODE_SLEEP, TOUCH_MODE_STATE_STOP);
+	ret = sec_ts_write(ts, SEC_TS_CMD_CLEAR_EVENT_STACK, NULL, 0);
+	if (ret < 0)
+		input_err(true, &ts->client->dev,
+			"%s: write clear event failed\n", __func__);
+
+	disable_irq_nosync(ts->client->irq);
+	sec_ts_locked_release_all_finger(ts);
+
+	if (ts->plat_data->enable_sync)
+		ts->plat_data->enable_sync(false);
+
+	ts->power_status = SEC_TS_STATE_SUSPEND;
+
+	sec_ts_pinctrl_configure(ts, false);
+
+	sec_set_switch_gpio(ts, SEC_SWITCH_GPIO_VALUE_SLPI_MASTER);
+
+#if IS_ENABLED(CONFIG_TOUCHSCREEN_TBN)
+	if (ts->tbn_register_mask)
+		tbn_release_bus(ts->tbn_register_mask);
+#endif
+	mutex_unlock(&ts->device_mutex);
+
+	sec_ts_hc_dump(ts);
+	sec_ts_debug_dump(ts);
+}
+
+static void sec_ts_resume_work(struct work_struct *work)
+{
+	struct sec_ts_data *ts = container_of(work, struct sec_ts_data,
+					      resume_work);
+	u8 touch_mode[2] = {0};
+	int ret = 0;
+
+	input_info(true, &ts->client->dev, "%s: int_cnt %llu.\n", __func__, ts->int_cnt);
+	ts->ktime_resume = ktime_get();
+	ts->comm_err_count = 0;
+	ts->hw_reset_count = 0;
+	ts->longest_duration = 0;
+	ts->pressed_count = 0;
+	ts->palm_count = 0;
+	ts->wet_count = 0;
+
+	mutex_lock(&ts->device_mutex);
+
+#if IS_ENABLED(CONFIG_TOUCHSCREEN_TBN)
+	if (ts->tbn_register_mask)
+		tbn_request_bus(ts->tbn_register_mask);
+#endif
+
+	sec_set_switch_gpio(ts, SEC_SWITCH_GPIO_VALUE_AP_MASTER);
+
+	sec_ts_pinctrl_configure(ts, true);
+
+	if (ts->power_status == SEC_TS_STATE_POWER_ON) {
+		input_err(true, &ts->client->dev, "%s: already resumed.\n",
+			  __func__);
+		mutex_unlock(&ts->device_mutex);
+		return;
+	}
+
+	sec_ts_locked_release_all_finger(ts);
+
+	ts->power_status = SEC_TS_STATE_POWER_ON;
+
+	ret = ts->sec_ts_read(ts, SEC_TS_CMD_CHG_SYSMODE, touch_mode,
+			       sizeof(touch_mode));
+	if (ret < 0) {
+		input_err(true, &ts->client->dev,
+			"%s: read touch mode failed(%d)\n",
+			__func__, ret);
+		ret = sec_ts_system_reset(ts, RESET_MODE_HW, false, false);
+		if (ret < 0) {
+			input_err(true, &ts->client->dev,
+				  "%s: reset failed! ret %d\n", __func__, ret);
+		}
+	} else {
+		u8 power_mode = TO_TOUCH_MODE;
+		u8 state_manage_on = { STATE_MANAGE_ON };
+
+		input_info(true, &ts->client->dev,
+			"%s: before resume: mode %#x, state %#x.\n",
+			__func__, touch_mode[0], touch_mode[1]);
+
+		/* Enable Normal scan. */
+		ret = sec_ts_write(ts, SEC_TS_CMD_SET_POWER_MODE,
+				   &power_mode, sizeof(power_mode));
+		if (ret < 0) {
+			input_err(true, &ts->client->dev,
+				  "%s: set power mode failed(%d)\n",
+				  __func__, ret);
+			ret = sec_ts_system_reset(ts, RESET_MODE_HW, false, false);
+			if (ret < 0) {
+				input_err(true, &ts->client->dev,
+					  "%s: reset failed! ret %d\n", __func__, ret);
+			}
+		} else {
+			/* Wait at least 50 ms for mode change. */
+			sec_ts_delay(50);
+		}
+
+		ret = ts->sec_ts_read(ts, SEC_TS_CMD_CHG_SYSMODE, touch_mode,
+				      sizeof(touch_mode));
+		if (ret < 0) {
+			input_err(true, &ts->client->dev,
+				  "%s: read touch mode failed(%d)\n",
+				  __func__, ret);
+		} else {
+			input_info(true, &ts->client->dev,
+				   "%s: after resume: mode %#x, state %#x.\n",
+				   __func__, touch_mode[0], touch_mode[1]);
+		}
+
+		ret = sec_ts_write(ts, SEC_TS_CMD_STATEMANAGE_ON, &state_manage_on,
+				sizeof(state_manage_on));
+		if (ret < 0) {
+			input_err(true, &ts->client->dev,
+				"%s: SEC_TS_CMD_STATEMANAGE_ON failed! ret %d\n",
+				__func__, ret);
+		}
+	}
+
+	if (ts->plat_data->enable_sync)
+		ts->plat_data->enable_sync(true);
+
+	ts->touch_functions =
+	    ts->touch_functions | SEC_TS_DEFAULT_ENABLE_BIT_SETFUNC;
+	ret = sec_ts_write(ts, SEC_TS_CMD_SET_TOUCHFUNCTION,
+			       (u8 *)&ts->touch_functions, 2);
+	if (ret < 0)
+		input_err(true, &ts->client->dev,
+			  "%s: Failed to send touch function command.",
+			  __func__);
+
+#ifdef SEC_TS_SUPPORT_CUSTOMLIB
+	if (ts->use_customlib)
+		sec_ts_set_custom_library(ts);
+#endif
+
+	ts->plat_data->is_heatmap_enabled = false;
+	ts->plat_data->encoded_frame_counter = 0;
+	ts->plat_data->encoded_skip_counter = 0;
+
+	if (ts->dex_mode) {
+		input_info(true, &ts->client->dev, "%s: set dex mode.\n",
+			   __func__);
+		ret = ts->sec_ts_write(ts, SEC_TS_CMD_SET_DEX_MODE,
+					   &ts->dex_mode, 1);
+		if (ret < 0)
+			input_err(true, &ts->client->dev,
+				  "%s: failed to set dex mode %x.\n", __func__,
+				  ts->dex_mode);
+	}
+
+	if (ts->brush_mode) {
+		input_info(true, &ts->client->dev, "%s: set brush mode.\n",
+			   __func__);
+		ret = ts->sec_ts_write(ts, SEC_TS_CMD_SET_BRUSH_MODE,
+					   &ts->brush_mode, 1);
+		if (ret < 0)
+			input_err(true, &ts->client->dev,
+				  "%s: failed to set brush mode.\n", __func__);
+	}
+
+	if (ts->touchable_area) {
+		input_info(true, &ts->client->dev, "%s: set 16:9 mode.\n",
+			   __func__);
+		ret = ts->sec_ts_write(ts, SEC_TS_CMD_SET_TOUCHABLE_AREA,
+					   &ts->touchable_area, 1);
+		if (ret < 0)
+			input_err(true, &ts->client->dev,
+				  "%s: failed to set 16:9 mode.\n", __func__);
+	}
+
+	/* set charger mode */
+	ret = ts->sec_ts_write(ts, SET_TS_CMD_SET_CHARGER_MODE,
+			       &ts->charger_mode, 1);
+	if (ret < 0)
+		input_err(true, &ts->client->dev,
+			  "%s: write reg %#x %#x failed, returned %i\n",
+			__func__, SET_TS_CMD_SET_CHARGER_MODE, ts->charger_mode,
+			ret);
+	else
+		input_info(true, &ts->client->dev, "%s: set charger mode %#x\n",
+			__func__, ts->charger_mode);
+#ifdef USE_CHARGER_WORK
+	queue_work(ts->event_wq, &ts->charger_work);
+#endif
+
+	/* Sense_on */
+	ret = sec_ts_write(ts, SEC_TS_CMD_SENSE_ON, NULL, 0);
+	if (ret < 0)
+		input_err(true, &ts->client->dev,
+			  "%s: failed to write Sense_on.\n", __func__);
+
+#if IS_ENABLED(CONFIG_TOUCHSCREEN_OFFLOAD)
+	/* Set touch_offload configuration */
+	if (ts->offload.offload_running) {
+		input_info(true, &ts->client->dev,
+			   "applying touch_offload settings.\n");
+
+		if (ts->offload.config.filter_grip) {
+			sec_ts_enable_fw_grip(ts, false);
+			sec_ts_enable_ptflib(ts, true);
+		}
+	}
+#endif
+
+	enable_irq(ts->client->irq);
+
+	complete_all(&ts->bus_resumed);
+
+	mutex_unlock(&ts->device_mutex);
+}
+
+#ifdef USE_CHARGER_WORK
+static void sec_ts_charger_work(struct work_struct *work)
+{
+	int ret;
+	union power_supply_propval prop = {0,};
+	struct sec_ts_data *ts = container_of(work, struct sec_ts_data,
+					      charger_work);
+	u8 charger_mode = SEC_TS_BIT_CHARGER_MODE_NO;
+	bool usb_present = ts->usb_present;
+	bool wlc_online = ts->wlc_online;
+	bool force_wlc = ts->force_wlc;
+	const u64 debounce_ms = 500;
+
+	/* usb case */
+	if (ts->usb_psy != NULL) {
+		ret = power_supply_get_property(ts->usb_psy,
+						POWER_SUPPLY_PROP_PRESENT, &prop);
+		if (ret == 0) {
+			usb_present = !!prop.intval;
+			if (usb_present)
+				charger_mode = SEC_TS_BIT_CHARGER_MODE_WIRE_CHARGER;
+		}
+	}
+
+	/* wlc case */
+	wlc_online = false;
+	if (ts->wireless_psy != NULL) {
+		ret = power_supply_get_property(ts->wireless_psy,
+					POWER_SUPPLY_PROP_ONLINE, &prop);
+		if (ret == 0) {
+			wlc_online = !!prop.intval;
+			if (wlc_online)
+				charger_mode =
+				    SEC_TS_BIT_CHARGER_MODE_WIRELESS_CHARGER;
+		}
+	}
+
+	/*
+	* RTX case
+	*    ret = power_supply_get_property(ts->wireless_psy,
+	*                                    POWER_SUPPLY_PROP_RTX, &prop);
+	* if (ret == 0)
+	*  pr_debug("%s: RTX %s", __func__,
+	*          (!!prop.intval) ? "ON" : "OFF");
+	*/
+
+	/* Check if any change for usb and wlc */
+	if (usb_present == ts->usb_present &&
+	    wlc_online == ts->wlc_online) {
+		input_dbg(true, &ts->client->dev,
+			"%s: usb_present(%d) and wlc_online(%d) no changed!",
+			__func__, usb_present, wlc_online);
+		return;
+	}
+
+	/* Force wlc case */
+	if (usb_present &&
+	    !wlc_online && ts->wlc_online &&
+	    ktime_before(ts->wlc_changed_ktime,
+		ktime_add_ms(ts->usb_changed_ktime, debounce_ms))) {
+		force_wlc = true;
+		charger_mode = SEC_TS_BIT_CHARGER_MODE_WIRELESS_CHARGER;
+		input_info(true, &ts->client->dev,
+			"%s: force wlc mode if usb present during wlc online.",
+			__func__);
+	} else {
+		force_wlc = false;
+	}
+
+	input_info(true, &ts->client->dev,
+		"%s: force_wlc(%d->%d), usb_present(%d->%d), wlc_online(%d->%d), charger_mode(%#x->%#x)",
+		__func__,
+		ts->force_wlc, force_wlc,
+		ts->usb_present, usb_present,
+		ts->wlc_online, wlc_online,
+		ts->charger_mode, charger_mode);
+
+	if (ts->charger_mode != charger_mode) {
+		if (ts->power_status == SEC_TS_STATE_POWER_ON) {
+			ret = ts->sec_ts_write(ts, SET_TS_CMD_SET_CHARGER_MODE,
+				       &charger_mode, 1);
+			if (ret < 0) {
+				input_err(true, &ts->client->dev,
+				"%s: write reg %#x %#x failed, returned %i\n",
+				__func__, SET_TS_CMD_SET_CHARGER_MODE,
+				charger_mode, ret);
+				return;
+			}
+
+			input_info(true, &ts->client->dev,
+				"%s: charger_mode change from %#x to %#x\n",
+				__func__, ts->charger_mode, charger_mode);
+		} else {
+			input_info(true, &ts->client->dev,
+				"%s: ONLY update charger_mode status from %#x to %#x, then will apply during resume\n",
+				__func__, ts->charger_mode, charger_mode);
+		}
+		ts->charger_mode = charger_mode;
+	}
+
+	/* update final charger state */
+	ts->wlc_online = wlc_online;
+	ts->usb_present = usb_present;
+	ts->force_wlc = force_wlc;
+}
+#endif
+
+static void sec_ts_aggregate_bus_state(struct sec_ts_data *ts)
+{
+	input_dbg(true, &ts->client->dev, "%s: bus_refmask = 0x%02X.\n",
+		  __func__, ts->bus_refmask);
+
+	/* Complete or cancel any outstanding transitions */
+	cancel_work_sync(&ts->suspend_work);
+	cancel_work_sync(&ts->resume_work);
+
+	if ((ts->bus_refmask == 0 &&
+		ts->power_status == SEC_TS_STATE_SUSPEND) ||
+	    (ts->bus_refmask != 0 &&
+		ts->power_status != SEC_TS_STATE_SUSPEND))
+		return;
+
+	if (ts->bus_refmask == 0)
+		queue_work(ts->event_wq, &ts->suspend_work);
+	else
+		queue_work(ts->event_wq, &ts->resume_work);
+}
+
+int sec_ts_set_bus_ref(struct sec_ts_data *ts, u16 ref, bool enable)
+{
+	int result = 0;
+
+	mutex_lock(&ts->bus_mutex);
+
+	input_dbg(true, &ts->client->dev, "%s: bus_refmask = 0x%02X.\n",
+		  __func__, ref);
+
+	if ((enable && (ts->bus_refmask & ref)) ||
+	    (!enable && !(ts->bus_refmask & ref))) {
+		input_dbg(true, &ts->client->dev,
+			"%s: reference is unexpectedly set: mask=0x%04X, ref=0x%04X, enable=%d\n",
+			__func__, ts->bus_refmask, ref, enable);
+		mutex_unlock(&ts->bus_mutex);
+		return -EINVAL;
+	}
+
+	if (enable) {
+		/* IRQs can only keep the bus active. IRQs received while the
+		 * bus is transferred to SLPI should be ignored.
+		 */
+		if (ref == SEC_TS_BUS_REF_IRQ && ts->bus_refmask == 0)
+			result = -EAGAIN;
+		else
+			ts->bus_refmask |= ref;
+	} else
+		ts->bus_refmask &= ~ref;
+	sec_ts_aggregate_bus_state(ts);
+
+	mutex_unlock(&ts->bus_mutex);
+
+	/* When triggering a wake, wait up to one second to resume. SCREEN_ON
+	 * and IRQ references do not need to wait.
+	 */
+	if (enable &&
+	    ref != SEC_TS_BUS_REF_SCREEN_ON && ref != SEC_TS_BUS_REF_IRQ) {
+		wait_for_completion_timeout(&ts->bus_resumed, HZ);
+		if (ts->power_status != SEC_TS_STATE_POWER_ON) {
+			input_info(true, &ts->client->dev,
+				   "%s: Failed to wake the touch bus.\n",
+				   __func__);
+			result = -ETIMEDOUT;
+		}
+	}
+
+	return result;
+}
+
+struct drm_connector *get_bridge_connector(struct drm_bridge *bridge)
+{
+	struct drm_connector *connector;
+	struct drm_connector_list_iter conn_iter;
+
+	drm_connector_list_iter_begin(bridge->dev, &conn_iter);
+	drm_for_each_connector_iter(connector, &conn_iter) {
+		if (connector->encoder == bridge->encoder)
+			break;
+	}
+	drm_connector_list_iter_end(&conn_iter);
+	return connector;
+}
+
+static bool bridge_is_lp_mode(struct drm_connector *connector)
+{
+	if (connector && connector->state) {
+		if (is_exynos_drm_connector(connector)) {
+			struct exynos_drm_connector_state *s =
+				to_exynos_connector_state(connector->state);
+
+			return s->exynos_mode.is_lp_mode;
+		}
+#if IS_ENABLED(CONFIG_GS_DRM_PANEL_UNIFIED)
+		else if (is_gs_drm_connector(connector)) {
+			struct gs_drm_connector_state *s =
+				to_gs_connector_state(connector->state);
+
+			return s->gs_mode.is_lp_mode;
+		}
+#endif
+	}
+	return false;
+}
+
+static void panel_bridge_enable(struct drm_bridge *bridge)
+{
+	struct sec_ts_data *ts =
+		container_of(bridge, struct sec_ts_data, panel_bridge);
+
+	pr_debug("%s\n", __func__);
+	if (!ts->is_panel_lp_mode)
+		sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SCREEN_ON, true);
+}
+
+static void panel_bridge_disable(struct drm_bridge *bridge)
+{
+	struct sec_ts_data *ts =
+		container_of(bridge, struct sec_ts_data, panel_bridge);
+
+	if (bridge->encoder && bridge->encoder->crtc) {
+		const struct drm_crtc_state *crtc_state = bridge->encoder->crtc->state;
+
+		if (drm_atomic_crtc_effectively_active(crtc_state))
+			return;
+	}
+
+	pr_debug("%s\n", __func__);
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SCREEN_ON, false);
+}
+
+static void panel_bridge_mode_set(struct drm_bridge *bridge,
+				  const struct drm_display_mode *mode,
+				  const struct drm_display_mode *adjusted_mode)
+{
+	struct sec_ts_data *ts =
+		container_of(bridge, struct sec_ts_data, panel_bridge);
+
+	if (!ts->connector || !ts->connector->state)
+		ts->connector = get_bridge_connector(bridge);
+
+	ts->is_panel_lp_mode = bridge_is_lp_mode(ts->connector);
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SCREEN_ON, !ts->is_panel_lp_mode);
+
+	if (adjusted_mode) {
+		int vrefresh = drm_mode_vrefresh(adjusted_mode);
+
+		if (ts->display_refresh_rate != vrefresh) {
+			input_dbg(true, &ts->client->dev,
+				"%s: refresh rate(Hz) changed to %d from %d\n",
+				__func__,  vrefresh, ts->display_refresh_rate);
+			ts->display_refresh_rate = vrefresh;
+		}
+	}
+}
+
+static const struct drm_bridge_funcs panel_bridge_funcs = {
+	.enable = panel_bridge_enable,
+	.disable = panel_bridge_disable,
+	.mode_set = panel_bridge_mode_set,
+};
+
+static int register_panel_bridge(struct sec_ts_data *ts)
+{
+	pr_debug("%s\n", __func__);
+#ifdef CONFIG_OF
+	ts->panel_bridge.of_node = ts->client->dev.of_node;
+#endif
+	ts->panel_bridge.funcs = &panel_bridge_funcs;
+	drm_bridge_add(&ts->panel_bridge);
+
+	return 0;
+}
+
+static void unregister_panel_bridge(struct drm_bridge *bridge)
+{
+	struct drm_bridge *node;
+
+	pr_debug("%s\n", __func__);
+	drm_bridge_remove(bridge);
+
+	if (!bridge->dev) /* not attached */
+		return;
+
+	drm_modeset_lock(&bridge->dev->mode_config.connection_mutex, NULL);
+	list_for_each_entry(node, &bridge->encoder->bridge_chain, chain_node)
+		if (node == bridge) {
+			if (bridge->funcs->detach)
+				bridge->funcs->detach(bridge);
+			list_del(&bridge->chain_node);
+			break;
+		}
+	drm_modeset_unlock(&bridge->dev->mode_config.connection_mutex);
+	bridge->dev = NULL;
+}
+
+/*
+ * power supply callback
+ */
+#ifdef USE_CHARGER_WORK
+static int sec_ts_psy_cb(struct notifier_block *nb,
+			       unsigned long val, void *data)
+{
+	struct sec_ts_data *ts = container_of(nb, struct sec_ts_data, psy_nb);
+
+	pr_debug("%s: val %lu", __func__, val);
+
+	if (val != PSY_EVENT_PROP_CHANGED ||
+	    ts->usb_psy == NULL ||
+	    (ts->wireless_psy != data && ts->usb_psy != data) ||
+	    ts->ignore_charger_nb == 1)
+		return NOTIFY_OK;
+
+	if (ts->usb_psy == data) {
+		ts->usb_changed_ktime = ktime_get();
+	}
+
+	if (ts->wireless_psy != NULL && ts->wireless_psy == data) {
+		ts->wlc_changed_ktime = ktime_get();
+	}
+
+	if (ts->power_status == SEC_TS_STATE_POWER_ON)
+		queue_work(ts->event_wq, &ts->charger_work);
+
+	return NOTIFY_OK;
+}
+
+static struct notifier_block sec_ts_psy_nb = {
+	.notifier_call = sec_ts_psy_cb,
+};
+#endif
+
+#ifdef CONFIG_OF
+static const struct of_device_id sec_ts_match_table[] = {
+	{ .compatible = "sec,sec_ts",},
+	{ },
+};
+MODULE_DEVICE_TABLE(of, sec_ts_match_table);
+#else
+#define sec_ts_match_table NULL
+#endif
+
+#ifdef I2C_INTERFACE
+static struct i2c_driver sec_ts_driver = {
+	.probe		= sec_ts_probe,
+	.remove		= sec_ts_remove,
+	.shutdown	= sec_ts_shutdown,
+	.id_table	= sec_ts_id,
+	.driver = {
+		.owner	= THIS_MODULE,
+		.name	= SEC_TS_NAME,
+#ifdef CONFIG_OF
+		.of_match_table = sec_ts_match_table,
+#endif
+#ifdef CONFIG_PM
+		.pm = &sec_ts_dev_pm_ops,
+#endif
+	},
+};
+#else
+static struct spi_driver sec_ts_driver = {
+	.probe    = sec_ts_probe,
+	.remove   = sec_ts_remove,
+	.shutdown   = sec_ts_shutdown,
+	.driver   = {
+		.owner  = THIS_MODULE,
+		.name = SEC_TS_NAME,
+#ifdef CONFIG_OF
+		.of_match_table = sec_ts_match_table,
+#endif
+#ifdef CONFIG_PM
+		.pm = &sec_ts_dev_pm_ops,
+#endif
+	},
+};
+#endif
+
+
+static int __init sec_ts_init(void)
+{
+#ifdef CONFIG_BATTERY_SAMSUNG
+	if (lpcharge == 1) {
+		pr_err("%s %s: Do not load driver due to lpm %d\n",
+				SECLOG, __func__, lpcharge);
+		return -ENODEV;
+	}
+#endif
+
+#ifdef I2C_INTERFACE
+	return i2c_add_driver(&sec_ts_driver);
+#else
+	return spi_register_driver(&sec_ts_driver);
+#endif
+}
+
+static void __exit sec_ts_exit(void)
+{
+
+#ifdef I2C_INTERFACE
+	i2c_del_driver(&sec_ts_driver);
+#else
+	spi_unregister_driver(&sec_ts_driver);
+#endif
+}
+
+MODULE_AUTHOR("Hyobae, Ahn<hyobae.ahn@samsung.com>");
+MODULE_DESCRIPTION("Samsung Electronics TouchScreen driver");
+MODULE_LICENSE("GPL");
+
+module_init(sec_ts_init);
+module_exit(sec_ts_exit);
diff --git a/sec_ts.h b/sec_ts.h
new file mode 100644
index 0000000..f5e044c
--- /dev/null
+++ b/sec_ts.h
@@ -0,0 +1,1328 @@
+/* drivers/input/touchscreen/sec_ts.h
+ *
+ * Copyright (C) 2015 Samsung Electronics Co., Ltd.
+ * http://www.samsungsemi.com/
+ *
+ * Core file for Samsung TSC driver
+ *
+ * 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 __SEC_TS_H__
+#define __SEC_TS_H__
+
+#include <asm/unaligned.h>
+#include <linux/completion.h>
+#include <linux/ctype.h>
+#include <linux/delay.h>
+#include <linux/firmware.h>
+#include <linux/gpio.h>
+#include <linux/hrtimer.h>
+#include <linux/i2c.h>
+#include <linux/spi/spi.h>
+#include <linux/input.h>
+#if IS_ENABLED(CONFIG_TOUCHSCREEN_HEATMAP)
+#include <heatmap.h>
+#endif
+#include <linux/input/mt.h>
+#if IS_ENABLED(CONFIG_TOUCHSCREEN_OFFLOAD)
+#include <touch_offload.h>
+#endif
+#include "sec_cmd.h"
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/kfifo.h>
+#include <linux/module.h>
+#include <drm/drm_bridge.h>
+#include <drm/drm_device.h>
+#include <drm/drm_encoder.h>
+#include <drm/drm_modes.h>
+#include <drm/drm_panel.h>
+#include <linux/of_gpio.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/platform_device.h>
+#include <linux/pm_qos.h>
+#include <linux/power_supply.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+#include <linux/time.h>
+#include <linux/uaccess.h>
+#include <linux/vmalloc.h>
+#include <linux/workqueue.h>
+#ifdef CONFIG_SEC_SYSFS
+#include <linux/sec_sysfs.h>
+#endif
+
+#ifdef CONFIG_INPUT_BOOSTER
+#include <linux/input/input_booster.h>
+#endif
+
+#if IS_ENABLED(CONFIG_TOUCHSCREEN_TBN)
+#include <touch_bus_negotiator.h>
+#endif
+
+#define SEC_TS_NAME		"sec_ts"
+#define SEC_TS_DEVICE_NAME	"SEC_TS"
+
+#undef SEC_TS_DEBUG_IO
+#undef USE_OPEN_CLOSE
+#undef USE_RESET_DURING_POWER_ON
+#undef USE_RESET_EXIT_LPM
+#undef USE_POR_AFTER_I2C_RETRY
+#undef USE_POR_AFTER_SPI_RETRY
+#undef USER_OPEN_DWORK
+#undef USE_PRESSURE_SENSOR
+#undef PAT_CONTROL
+#define USE_CHARGER_WORK
+#undef USE_STIM_PAD
+#undef USE_SPEC_CHECK
+
+#if defined(USE_RESET_DURING_POWER_ON) || defined(USE_POR_AFTER_I2C_RETRY) || \
+    defined(USE_RESET_EXIT_LPM) || defined(USE_POR_AFTER_SPI_RETRY)
+#define USE_POWER_RESET_WORK
+#endif
+
+#ifndef I2C_INTERFACE
+#define SPI_CLOCK_FREQ			10000000
+#define SPI_DELAY_CS			10
+#define SEC_TS_SPI_SYNC_CODE		0xAA
+#define SEC_TS_SPI_HEADER_SIZE		5
+#define SEC_TS_SPI_READ_HEADER_SIZE	7
+#define SEC_TS_SPI_CHECKSUM_SIZE	1
+
+#define SEC_TS_SPI_CMD_OK		0x0
+#define SEC_TS_SPI_CMD_NG		(1u<<7)
+#define SEC_TS_SPI_CMD_UNKNOWN		(SEC_TS_SPI_CMD_NG | (1))
+#define SEC_TS_SPI_CMD_FAIL		(SEC_TS_SPI_CMD_NG | (2))
+#define SEC_TS_SPI_CMD_BAD_PARAM	(SEC_TS_SPI_CMD_NG | (3))
+#define SEC_TS_SPI_CMD_CHKSUM_FAIL	(SEC_TS_SPI_CMD_NG | (4))
+#endif
+
+#define TOUCH_RESET_DWORK_TIME		10
+#define BRUSH_Z_DATA			63	/* for ArtCanvas */
+
+#define MASK_1_BITS			0x0001
+#define MASK_2_BITS			0x0003
+#define MASK_3_BITS			0x0007
+#define MASK_4_BITS			0x000F
+#define MASK_5_BITS			0x001F
+#define MASK_6_BITS			0x003F
+#define MASK_7_BITS			0x007F
+#define MASK_8_BITS			0x00FF
+
+/* support feature */
+//#define SEC_TS_SUPPORT_CUSTOMLIB	/* support user defined library */
+
+#define TYPE_STATUS_EVENT_CMD_DRIVEN	0
+#define TYPE_STATUS_EVENT_ERR		1
+#define TYPE_STATUS_EVENT_INFO		2
+#define TYPE_STATUS_EVENT_USER_INPUT	3
+#define TYPE_STATUS_EVENT_CUSTOMLIB_INFO	6
+#define TYPE_STATUS_EVENT_VENDOR_INFO	7
+#define TYPE_STATUS_CODE_SAR	0x28
+
+#define BIT_STATUS_EVENT_CMD_DRIVEN(a)	(a << TYPE_STATUS_EVENT_CMD_DRIVEN)
+#define BIT_STATUS_EVENT_ERR(a)		(a << TYPE_STATUS_EVENT_ERR)
+#define BIT_STATUS_EVENT_INFO(a)	(a << TYPE_STATUS_EVENT_INFO)
+#define BIT_STATUS_EVENT_USER_INPUT(a)	(a << TYPE_STATUS_EVENT_USER_INPUT)
+#define BIT_STATUS_EVENT_VENDOR_INFO(a)	(a << TYPE_STATUS_EVENT_VENDOR_INFO)
+
+#define DO_FW_CHECKSUM			(1 << 0)
+#define DO_PARA_CHECKSUM		(1 << 1)
+#define MAX_SUPPORT_TOUCH_COUNT		10
+#define MAX_SUPPORT_HOVER_COUNT		1
+
+#define SEC_TS_EVENTID_HOVER		10
+
+#define SEC_TS_DEFAULT_FW_NAME		"tsp_sec/sec_hero.fw"
+#define SEC_TS_DEFAULT_BL_NAME		"tsp_sec/s6smc41_blupdate_img_REL.bin"
+#define SEC_TS_DEFAULT_PARA_NAME	"tsp_sec/s6smc41_para_REL_DGA0_V0106_150114_193317.bin"
+#define SEC_TS_DEFAULT_FFU_FW		"ffu_tsp.bin"
+#define SEC_TS_MAX_FW_PATH		64
+#define SEC_TS_FW_BLK_SIZE_MAX		(512)
+#define SEC_TS_FW_BLK_SIZE_DEFAULT	(512)
+#define SEC_TS_SELFTEST_REPORT_SIZE	80
+#define SEC_TS_PRESSURE_MAX		0x3f
+
+#define IO_WRITE_BUFFER_SIZE		(256 - 1)//10
+
+#ifdef I2C_INTERFACE
+/* max read size: from sec_ts_read_event() at sec_ts.c */
+#define IO_PREALLOC_READ_BUF_SZ	(32 * SEC_TS_EVENT_BUFF_SIZE)
+/* max write size: from sec_ts_flashpagewrite() at sec_ts_fw.c */
+#define IO_PREALLOC_WRITE_BUF_SZ	(SEC_TS_SPI_HEADER_SIZE + 1 + 2 +\
+					    SEC_TS_FW_BLK_SIZE_MAX + 1)
+#else
+#define IO_PREALLOC_READ_BUF_SZ	2048
+#define IO_PREALLOC_WRITE_BUF_SZ	1024
+#endif
+
+#define SEC_TS_FW_HEADER_SIGN		0x53494654
+#define SEC_TS_FW_CHUNK_SIGN		0x53434654
+
+#undef SEC_TS_FW_UPDATE_ON_PROBE
+#define SEC_TS_FW_UPDATE_DELAY_MS_AFTER_PROBE	1000
+
+#define AMBIENT_CAL			0
+#define OFFSET_CAL_SDC			1
+#define OFFSET_CAL_SEC			2
+#define PRESSURE_CAL			3
+
+#define SEC_TS_SKIPTSP_DUTY		100
+
+#define SEC_TS_NVM_OFFSET_FAC_RESULT		0
+#define SEC_TS_NVM_OFFSET_CAL_COUNT		1
+#define SEC_TS_NVM_OFFSET_DISASSEMBLE_COUNT	2
+#define SEC_TS_NVM_OFFSET_TUNE_VERSION		3
+#define SEC_TS_NVM_OFFSET_TUNE_VERSION_LENGTH	2
+
+#define SEC_TS_NVM_OFFSET_PRESSURE_INDEX	5
+
+#define SEC_TS_NVM_OFFSET_PRESSURE_STRENGTH	6
+#define SEC_TS_NVM_OFFSET_PRESSURE_STRENGTH_1	6
+#define SEC_TS_NVM_OFFSET_PRESSURE_STRENGTH_2	12
+#define SEC_TS_NVM_OFFSET_PRESSURE_STRENGTH_3	18
+#define SEC_TS_NVM_OFFSET_PRESSURE_STRENGTH_4	24
+
+#define SEC_TS_NVM_OFFSET_PRESSURE_RAWDATA	30
+#define SEC_TS_NVM_OFFSET_PRESSURE_RAWDATA_1	30
+#define SEC_TS_NVM_OFFSET_PRESSURE_RAWDATA_2	36
+#define SEC_TS_NVM_OFFSET_PRESSURE_RAWDATA_3	42
+#define SEC_TS_NVM_OFFSET_PRESSURE_RAWDATA_4	48
+#define SEC_TS_NVM_SIZE_PRESSURE_BLOCK		6
+
+#define SEC_TS_NVM_OFFSET_PRESSURE_BASE_CAL_COUNT	54
+#define SEC_TS_NVM_OFFSET_PRESSURE_DELTA_CAL_COUNT	55
+#define SEC_TS_NVM_SIZE_PRESSURE_CAL_BLOCK		1
+
+#define SEC_TS_NVM_LAST_BLOCK_OFFSET	\
+	    SEC_TS_NVM_OFFSET_PRESSURE_DELTA_CAL_COUNT
+#define SEC_TS_NVM_LAST_BLOCK_SIZE	SEC_TS_NVM_SIZE_PRESSURE_CAL_BLOCK
+
+#define SEC_TS_NVM_OFFSET_LENGTH	(SEC_TS_NVM_LAST_BLOCK_OFFSET +\
+					    SEC_TS_NVM_LAST_BLOCK_SIZE + 1)
+
+/* SEC_TS READ REGISTER ADDRESS */
+#define SEC_TS_CMD_SENSE_ON			0x10
+#define SEC_TS_CMD_SENSE_OFF			0x11
+#define SEC_TS_CMD_SW_RESET			0x12
+#define SEC_TS_CMD_CALIBRATION_SEC		0x13	/* send it to touch ic,
+							 * but touch ic works
+							 * nothing.
+							 **/
+#define SEC_TS_CMD_FACTORY_PANELCALIBRATION	0x14
+
+#define SEC_TS_READ_GPIO_STATUS			0x20	// not support
+#define SEC_TS_READ_FIRMWARE_INTEGRITY		0x21
+#define SEC_TS_READ_DEVICE_ID			0x22
+#define SEC_TS_READ_PANEL_INFO			0x23
+#define SEC_TS_READ_CORE_CONFIG_VERSION		0x24
+#define SEC_TS_CMD_DISABLE_GAIN_LIMIT		0x2A
+
+#define SEC_TS_CMD_SET_TOUCHFUNCTION		0x30
+#define SEC_TS_CMD_SET_TSC_MODE			0x31
+#define SET_TS_CMD_SET_CHARGER_MODE		0x32
+#define SET_TS_CMD_SET_NOISE_MODE		0x33
+#define SET_TS_CMD_SET_REPORT_RATE		0x34
+#define SEC_TS_CMD_TOUCH_MODE_FOR_THRESHOLD	0x35
+#define SEC_TS_CMD_TOUCH_THRESHOLD		0x36
+#define SET_TS_CMD_KEY_THRESHOLD		0x37
+#define SEC_TS_CMD_SET_COVERTYPE		0x38
+#define SEC_TS_CMD_WAKEUP_GESTURE_MODE		0x39
+#define SEC_TS_WRITE_POSITION_FILTER		0x3A
+#define SEC_TS_CMD_WET_MODE			0x3B
+#define SEC_TS_CMD_DISABLE_NORM_TABLE		0x40
+#define SEC_TS_CMD_READ_NORM_TABLE		0x41
+#define SEC_TS_CMD_DISABLE_BASELINE_ADAPT	0x43
+#define SEC_TS_CMD_DISABLE_DF			0x44
+#define SEC_TS_CMD_ERASE_FLASH			0x45
+#define SEC_TS_CMD_RESET_BASELINE		0x47
+#define SEC_TS_CMD_SET_CONT_REPORT		0x49
+#define SEC_TS_CMD_WRITE_NORM_TABLE		0x49
+#if IS_ENABLED(CONFIG_TOUCHSCREEN_HEATMAP)
+#define SEC_TS_CMD_HEATMAP_READ			0x4A
+#define SEC_TS_CMD_HEATMAP_ENABLE		0x4B
+#endif
+#define SEC_TS_READ_ID				0x52
+#define SEC_TS_READ_BOOT_STATUS			0x55
+#define SEC_TS_CMD_ENTER_FW_MODE		0x57
+#define SEC_TS_READ_ONE_EVENT			0x60
+#define SEC_TS_READ_ALL_EVENT			0x61
+#define SEC_TS_CMD_CLEAR_EVENT_STACK		0x62
+#define SEC_TS_CMD_MUTU_RAW_TYPE		0x70
+#define SEC_TS_CMD_SELF_RAW_TYPE		0x71
+#define SEC_TS_READ_TOUCH_RAWDATA		0x72
+#define SEC_TS_READ_TOUCH_SELF_RAWDATA		0x73
+#define SEC_TS_READ_SELFTEST_RESULT		0x80
+#define SEC_TS_CMD_CALIBRATION_AMBIENT		0x81
+#define SEC_TS_CMD_P2PTEST			0x82
+#define SEC_TS_CMD_SET_P2PTEST_MODE		0x83
+#define SEC_TS_CMD_NVM				0x85
+#define SEC_TS_CMD_SET_WET_MODE			0x8B
+#define SEC_TS_CMD_STATEMANAGE_ON		0x8E
+#define SEC_TS_CMD_CALIBRATION_OFFSET_SDC	0x8F
+
+/* SEC_TS CUSTOMLIB OPCODE COMMAND */
+#define SEC_TS_CMD_CUSTOMLIB_GET_INFO			0x90
+#define SEC_TS_CMD_CUSTOMLIB_WRITE_PARAM			0x91
+#define SEC_TS_CMD_CUSTOMLIB_READ_PARAM			0x92
+#define SEC_TS_CMD_CUSTOMLIB_NOTIFY_PACKET			0x93
+#define SEC_TS_CMD_CUSTOMLIB_OFFSET_PRESSURE_LEVEL		0x5E
+#define SEC_TS_CMD_CUSTOMLIB_OFFSET_PRESSURE_THD_HIGH	0x84
+#define SEC_TS_CMD_CUSTOMLIB_OFFSET_PRESSURE_THD_LOW	0x86
+#define SEC_TS_CMD_CUSTOMLIB_LP_DUMP			0x01F0
+
+#define SEC_TS_CMD_STATUS_EVENT_TYPE	0xA0
+#define SEC_TS_READ_FW_INFO		0xA2
+#define SEC_TS_READ_FW_VERSION		0xA3
+#define SEC_TS_READ_PARA_VERSION	0xA4
+#define SEC_TS_READ_IMG_VERSION		0xA5
+#define SEC_TS_CMD_GET_CHECKSUM		0xA6
+#define SEC_TS_CMD_MIS_CAL_CHECK	0xA7
+#define SEC_TS_CMD_MIS_CAL_READ		0xA8
+#define SEC_TS_CMD_MIS_CAL_SPEC		0xA9
+#define SEC_TS_CMD_DEADZONE_RANGE	0xAA
+#define SEC_TS_CMD_LONGPRESSZONE_RANGE	0xAB
+#define SEC_TS_CMD_LONGPRESS_DROP_AREA	0xAC
+#define SEC_TS_CMD_LONGPRESS_DROP_DIFF	0xAD
+#define SEC_TS_READ_TS_STATUS		0xAF
+#define SEC_TS_CMD_SELFTEST		0xAE
+#define SEC_TS_READ_FORCE_RECAL_COUNT	0xB0
+#define SEC_TS_READ_FORCE_SIG_MAX_VAL	0xB1
+#define SEC_TS_CAAT_READ_STORED_DATA	0xB7
+#define SEC_TS_CMD_SET_NOISE_MODE	0xBB
+#define SEC_TS_CMD_SET_GRIP_DETEC	0xBC
+#define SEC_TS_CMD_SET_PALM_DETEC	0xBE
+#define SEC_TS_READ_CSRAM_RTDP_DATA	0xC3
+
+/* SEC_TS FLASH COMMAND */
+#define SEC_TS_CMD_FLASH_READ_ADDR	0xD0
+#define SEC_TS_CMD_FLASH_READ_SIZE	0xD1
+#define SEC_TS_CMD_FLASH_READ_DATA	0xD2
+#define SEC_TS_CMD_CHG_SYSMODE		0xD7
+#define SEC_TS_CMD_FLASH_ERASE		0xD8
+#define SEC_TS_CMD_FLASH_WRITE		0xD9
+#define SEC_TS_CMD_FLASH_PADDING	0xDA
+
+#define SEC_TS_READ_BL_UPDATE_STATUS	0xDB
+#define SEC_TS_CMD_SET_TOUCH_ENGINE_MODE	0xE1
+#define SEC_TS_CMD_SET_POWER_MODE	0xE4
+#define SEC_TS_CMD_EDGE_DEADZONE	0xE5
+#define SEC_TS_CMD_SET_DEX_MODE		0xE7
+#define SEC_TS_CMD_CALIBRATION_PRESSURE		0xE9
+/* Have to need delay 30msec after writing 0xEA command */
+/* Do not write Zero with 0xEA command */
+#define SEC_TS_CMD_SET_GET_PRESSURE		0xEA
+#define SEC_TS_CMD_SET_USER_PRESSURE		0xEB
+#define SEC_TS_CMD_SET_TEMPERATURE_COMP_MODE	0xEC
+#define SEC_TS_CMD_SET_TOUCHABLE_AREA		0xED
+#define SEC_TS_CMD_SET_BRUSH_MODE		0xEF
+
+#define SEC_TS_READ_CALIBRATION_REPORT		0xF1
+#define SEC_TS_CMD_SET_VENDOR_EVENT_LEVEL	0xF2
+#define SEC_TS_CMD_SET_SPENMODE			0xF3
+#define SEC_TS_CMD_SELECT_PRESSURE_TYPE		0xF5
+#define SEC_TS_CMD_READ_PRESSURE_DATA		0xF6
+
+#define SEC_TS_FLASH_SIZE_64		64
+#define SEC_TS_FLASH_SIZE_128		128
+#define SEC_TS_FLASH_SIZE_256		256
+
+#define SEC_TS_FLASH_SIZE_CMD		1
+#define SEC_TS_FLASH_SIZE_ADDR		2
+#define SEC_TS_FLASH_SIZE_CHECKSUM	1
+
+#define SEC_TS_STATUS_BOOT_MODE		0x10
+#define SEC_TS_STATUS_APP_MODE		0x20
+
+#define SEC_TS_FIRMWARE_PAGE_SIZE_256	256
+#define SEC_TS_FIRMWARE_PAGE_SIZE_128	128
+
+/* SEC status event id */
+#define SEC_TS_COORDINATE_EVENT		0
+#define SEC_TS_STATUS_EVENT		1
+#define SEC_TS_GESTURE_EVENT		2
+#define SEC_TS_EMPTY_EVENT		3
+
+#define SEC_TS_EVENT_BUFF_SIZE		8
+#define SEC_TS_SID_GESTURE		0x14
+#define SEC_TS_GESTURE_CODE_SPAY		0x00
+#define SEC_TS_GESTURE_CODE_DOUBLE_TAP		0x01
+
+#define SEC_TS_COORDINATE_ACTION_NONE		0
+#define SEC_TS_COORDINATE_ACTION_PRESS		1
+#define SEC_TS_COORDINATE_ACTION_MOVE		2
+#define SEC_TS_COORDINATE_ACTION_RELEASE	3
+
+#define SEC_TS_TOUCHTYPE_NORMAL		0
+#define SEC_TS_TOUCHTYPE_HOVER		1
+#define SEC_TS_TOUCHTYPE_FLIPCOVER	2
+#define SEC_TS_TOUCHTYPE_GLOVE		3
+#define SEC_TS_TOUCHTYPE_STYLUS		4
+#define SEC_TS_TOUCHTYPE_PALM		5
+#define SEC_TS_TOUCHTYPE_WET		6
+#define SEC_TS_TOUCHTYPE_PROXIMITY	7
+#define SEC_TS_TOUCHTYPE_JIG		8
+#define SEC_TS_TOUCHTYPE_GRIP		10
+
+/* SEC_TS_INFO : Info acknowledge event */
+#define SEC_TS_ACK_BOOT_COMPLETE	0x00
+#define SEC_TS_ACK_WET_MODE	0x1
+
+/* SEC_TS_VENDOR_INFO : Vendor acknowledge event */
+#define SEC_TS_VENDOR_ACK_OFFSET_CAL_DONE	0x40
+#define SEC_TS_VENDOR_ACK_SELF_TEST_DONE	0x41
+#define SEC_TS_VENDOR_ACK_P2P_TEST_DONE		0x42
+
+/* SEC_TS_STATUS_EVENT_USER_INPUT */
+#define SEC_TS_EVENT_FORCE_KEY	0x1
+
+/* SEC_TS_STATUS_EVENT_CUSTOMLIB_INFO */
+#define SEC_TS_EVENT_CUSTOMLIB_FORCE_KEY	0x00
+
+/* SEC_TS_ERROR : Error event */
+#define SEC_TS_ERR_EVNET_CORE_ERR	0x0
+#define SEC_TS_ERR_EVENT_QUEUE_FULL	0x01
+#define SEC_TS_ERR_EVENT_ESD		0x2
+
+#define SEC_TS_BIT_SETFUNC_TOUCH		(1 << 0)
+#define SEC_TS_BIT_SETFUNC_MUTUAL		(1 << 0)
+#define SEC_TS_BIT_SETFUNC_HOVER		(1 << 1)
+#define SEC_TS_BIT_SETFUNC_COVER		(1 << 2)
+#define SEC_TS_BIT_SETFUNC_GLOVE		(1 << 3)
+#define SEC_TS_BIT_SETFUNC_STYLUS		(1 << 4)
+#define SEC_TS_BIT_SETFUNC_PALM			(1 << 5)
+#define SEC_TS_BIT_SETFUNC_WET			(1 << 6)
+#define SEC_TS_BIT_SETFUNC_PROXIMITY		(1 << 7)
+
+#define SEC_TS_DEFAULT_ENABLE_BIT_SETFUNC	(SEC_TS_BIT_SETFUNC_TOUCH |\
+						SEC_TS_BIT_SETFUNC_PALM |\
+						SEC_TS_BIT_SETFUNC_WET)
+
+#define SEC_TS_BIT_CHARGER_MODE_NO			(0x1 << 0)
+#define SEC_TS_BIT_CHARGER_MODE_WIRE_CHARGER		(0x1 << 1)
+#define SEC_TS_BIT_CHARGER_MODE_WIRELESS_CHARGER	(0x1 << 2)
+#define SEC_TS_BIT_CHARGER_MODE_WIRELESS_BATTERY_PACK	(0x1 << 3)
+
+#ifdef PAT_CONTROL
+/*
+ *  <<< apply to server >>>
+ *  0x00 : no action
+ *  0x01 : clear nv
+ *  0x02 : pat magic
+ *  0x03 : rfu
+ *
+ *  <<< use for temp bin >>>
+ *  0x05 : forced clear nv & f/w update  before pat magic, eventhough same f/w
+ *  0x06 : rfu
+ **/
+#define PAT_CONTROL_NONE			0x00
+#define PAT_CONTROL_CLEAR_NV		0x01
+#define PAT_CONTROL_PAT_MAGIC		0x02
+#define PAT_CONTROL_FORCE_UPDATE	0x05
+
+#define PAT_COUNT_ZERO			0x00
+#define PAT_MAX_LCIA			0x80
+#define PAT_MAGIC_NUMBER		0x83
+#define PAT_MAX_MAGIC			0xC5
+#define PAT_EXT_FACT			0xE0
+#define PAT_MAX_EXT			0xF5
+#endif
+
+#define STATE_MANAGE_ON			1
+#define STATE_MANAGE_OFF		0
+
+#define SEC_TS_STATUS_NOT_CALIBRATION	0x50
+#define SEC_TS_STATUS_CALIBRATION_SDC	0xA1
+#define SEC_TS_STATUS_CALIBRATION_SEC	0xA2
+
+#define SEC_TS_CMD_EDGE_HANDLER		0xAA
+#define SEC_TS_CMD_EDGE_AREA		0xAB
+#define SEC_TS_CMD_DEAD_ZONE		0xAC
+#define SEC_TS_CMD_LANDSCAPE_MODE	0xAD
+
+enum spec_check_type {
+	SPEC_NO_CHECK			= 0,
+	SPEC_CHECK			= 1,
+	SPEC_PASS			= 2,
+	SPEC_FAIL			= 3,
+};
+
+enum region_type {
+	REGION_NORMAL			= 0,
+	REGION_EDGE			= 1,
+	REGION_CORNER			= 2,
+	REGION_NOTCH			= 3,
+	REGION_TYPE_COUNT		= 4,
+	/* REGION type should be continuous number start from 0,
+	 * since REGION_TYPE_COUNT is used for type count
+	 */
+};
+
+enum grip_write_mode {
+	G_NONE				= 0,
+	G_SET_EDGE_HANDLER		= 1,
+	G_SET_EDGE_ZONE			= 2,
+	G_SET_NORMAL_MODE		= 4,
+	G_SET_LANDSCAPE_MODE	= 8,
+	G_CLR_LANDSCAPE_MODE	= 16,
+};
+enum grip_set_data {
+	ONLY_EDGE_HANDLER		= 0,
+	GRIP_ALL_DATA			= 1,
+};
+
+enum TOUCH_POWER_MODE {
+	SEC_TS_STATE_POWER_OFF = 0,
+	SEC_TS_STATE_SUSPEND,
+	SEC_TS_STATE_LPM,
+	SEC_TS_STATE_POWER_ON
+};
+
+enum TOUCH_SYSTEM_MODE {
+	TOUCH_SYSTEM_MODE_BOOT		= 0,
+	TOUCH_SYSTEM_MODE_CALIBRATION	= 1,
+	TOUCH_SYSTEM_MODE_TOUCH		= 2,
+	TOUCH_SYSTEM_MODE_SELFTEST	= 3,
+	TOUCH_SYSTEM_MODE_FLASH		= 4,
+	TOUCH_SYSTEM_MODE_LOWPOWER	= 5,
+	TOUCH_SYSTEM_MODE_SLEEP		= 6
+};
+
+enum TOUCH_MODE_STATE {
+	TOUCH_MODE_STATE_IDLE		= 0,
+	TOUCH_MODE_STATE_HOVER		= 1,
+	TOUCH_MODE_STATE_STOP		= 1,
+	TOUCH_MODE_STATE_TOUCH		= 2,
+	TOUCH_MODE_STATE_NOISY		= 3,
+	TOUCH_MODE_STATE_CAL		= 4,
+	TOUCH_MODE_STATE_CAL2		= 5,
+	TOUCH_MODE_STATE_WAKEUP		= 10
+};
+
+enum {
+	TEST_OPEN			= (0x1 << 0),
+	TEST_NODE_VARIANCE		= (0x1 << 1),
+	TEST_SHORT			= (0x1 << 2),
+	TEST_SELF_NODE			= (0x1 << 5),
+	TEST_NOT_SAVE			= (0x1 << 7),
+	TEST_HIGH_FREQ			= (0x1 << 8),
+};
+
+enum switch_system_mode {
+	TO_TOUCH_MODE			= 0,
+	TO_LOWPOWER_MODE		= 1,
+	TO_SELFTEST_MODE		= 2,
+	TO_FLASH_MODE			= 3,
+};
+
+enum noise_mode_param {
+	NOISE_MODE_DEFALUT	= 0x00,
+	NOISE_MODE_OFF		= 0x10,
+	NOISE_MODE_FORCE_ON	= 0x11,
+};
+
+enum {
+	TYPE_RAW_DATA			= 0,	/* Total - Offset : delta data
+						 **/
+	TYPE_SIGNAL_DATA		= 1,	/* Signal - Filtering &
+						 * Normalization
+						 **/
+	TYPE_AMBIENT_BASELINE		= 2,	/* Cap Baseline
+						 **/
+	TYPE_AMBIENT_DATA		= 3,	/* Cap Ambient
+						 **/
+	TYPE_REMV_BASELINE_DATA		= 4,
+	TYPE_DECODED_DATA		= 5,	/* Raw */
+	TYPE_REMV_AMB_DATA		= 6,	/* TYPE_RAW_DATA -
+						 * TYPE_AMBIENT_DATA
+						 **/
+	TYPE_NORM2_DATA			= 15,	/* After fs norm. data
+						 **/
+	TYPE_OFFSET_DATA_SEC		= 19,	/* Cap Offset in SEC
+						 * Manufacturing Line
+						 **/
+	TYPE_OFFSET_DATA_SDC		= 29,	/* Cap Offset in SDC
+						 * Manufacturing Line
+						 **/
+	TYPE_NOI_P2P_MIN		= 30,	/* Peak-to-peak noise Min
+						 **/
+	TYPE_NOI_P2P_MAX		= 31,	/* Peak-to-peak noise Max
+						 **/
+	TYPE_OFFSET_DATA_SDC_CM2	= 129,
+	TYPE_OFFSET_DATA_SDC_NOT_SAVE	= 229,
+	TYPE_INVALID_DATA		= 0xFF,	/* Invalid data type for
+						 * release factory mode
+						 **/
+};
+
+enum RESET_MODE {
+	RESET_MODE_NA		= 0x00,
+	RESET_MODE_SW		= 0x01,
+	RESET_MODE_HW		= 0x02,
+	RESET_MODE_AUTO		= (RESET_MODE_SW | RESET_MODE_HW),
+};
+
+enum CUSTOMLIB_EVENT_TYPE {
+	CUSTOMLIB_EVENT_TYPE_SPAY			= 0x04,
+	CUSTOMLIB_EVENT_TYPE_PRESSURE_TOUCHED		= 0x05,
+	CUSTOMLIB_EVENT_TYPE_PRESSURE_RELEASED		= 0x06,
+	CUSTOMLIB_EVENT_TYPE_AOD			= 0x08,
+	CUSTOMLIB_EVENT_TYPE_AOD_PRESS			= 0x09,
+	CUSTOMLIB_EVENT_TYPE_AOD_LONGPRESS		= 0x0A,
+	CUSTOMLIB_EVENT_TYPE_AOD_DOUBLETAB		= 0x0B,
+	CUSTOMLIB_EVENT_TYPE_AOD_HOMEKEY_PRESS		= 0x0C,
+	CUSTOMLIB_EVENT_TYPE_AOD_HOMEKEY_RELEASE	= 0x0D,
+	CUSTOMLIB_EVENT_TYPE_AOD_HOMEKEY_RLS_NO_HAPTIC	= 0x0E
+};
+
+enum {
+	SEC_TS_BUS_REF_SCREEN_ON	= 0x01,
+	SEC_TS_BUS_REF_IRQ		= 0x02,
+	SEC_TS_BUS_REF_RESET		= 0x04,
+	SEC_TS_BUS_REF_FW_UPDATE	= 0x08,
+	SEC_TS_BUS_REF_INPUT_DEV	= 0x10,
+	SEC_TS_BUS_REF_READ_INFO	= 0x20,
+	SEC_TS_BUS_REF_SYSFS		= 0x40,
+	SEC_TS_BUS_REF_FORCE_ACTIVE	= 0x80,
+	SEC_TS_BUS_REF_BUGREPORT	= 0x100
+};
+
+enum {
+	SEC_TS_ERR_NA = 0,
+	SEC_TS_ERR_INIT,
+	SEC_TS_ERR_ALLOC_FRAME,
+	SEC_TS_ERR_ALLOC_FRAME_SS,
+	SEC_TS_ERR_ALLOC_GAINTABLE,
+	SEC_TS_ERR_REG_INPUT_DEV,
+	SEC_TS_ERR_REG_INPUT_PAD_DEV
+};
+
+#define CMD_RESULT_WORD_LEN		10
+
+#define SEC_TS_IO_RESET_CNT		3
+#define SEC_TS_IO_RETRY_CNT		3
+#define SEC_TS_WAIT_RETRY_CNT		10
+
+#define SEC_TS_MODE_CUSTOMLIB_SPAY			(1 << 1)
+#define SEC_TS_MODE_CUSTOMLIB_AOD			(1 << 2)
+#define SEC_TS_MODE_CUSTOMLIB_FORCE_KEY	(1 << 6)
+
+#define SEC_TS_MODE_LOWPOWER_FLAG   (SEC_TS_MODE_CUSTOMLIB_SPAY |\
+				    SEC_TS_MODE_CUSTOMLIB_AOD |\
+				    SEC_TS_MODE_CUSTOMLIB_FORCE_KEY)
+
+#define SEC_TS_AOD_GESTURE_PRESS		(1 << 7)
+#define SEC_TS_AOD_GESTURE_LONGPRESS		(1 << 6)
+#define SEC_TS_AOD_GESTURE_DOUBLETAB		(1 << 5)
+
+#define SEC_TS_CUSTOMLIB_EVENT_PRESSURE_TOUCHED		(1 << 6)
+#define SEC_TS_CUSTOMLIB_EVENT_PRESSURE_RELEASED		(1 << 7)
+
+enum sec_ts_cover_id {
+	SEC_TS_FLIP_WALLET = 0,
+	SEC_TS_VIEW_COVER,
+	SEC_TS_COVER_NOTHING1,
+	SEC_TS_VIEW_WIRELESS,
+	SEC_TS_COVER_NOTHING2,
+	SEC_TS_CHARGER_COVER,
+	SEC_TS_VIEW_WALLET,
+	SEC_TS_LED_COVER,
+	SEC_TS_CLEAR_FLIP_COVER,
+	SEC_TS_QWERTY_KEYBOARD_EUR,
+	SEC_TS_QWERTY_KEYBOARD_KOR,
+	SEC_TS_MONTBLANC_COVER = 100,
+};
+
+enum sec_fw_update_status {
+	SEC_NOT_UPDATE = 0,
+	SEC_NEED_FW_UPDATE,
+	SEC_NEED_CALIBRATION_ONLY,
+	SEC_NEED_FW_UPDATE_N_CALIBRATION,
+};
+
+enum tsp_hw_parameter {
+	TSP_ITO_CHECK		= 1,
+	TSP_RAW_CHECK		= 2,
+	TSP_MULTI_COUNT		= 3,
+	TSP_WET_MODE		= 4,
+	TSP_COMM_ERR_COUNT	= 5,
+	TSP_MODULE_ID		= 6,
+};
+
+enum {
+	HEATMAP_OFF	= 0,
+	HEATMAP_PARTIAL	= 1,
+	HEATMAP_FULL	= 2
+};
+
+enum {
+	GRIP_PRESCREEN_OFF	= 0,
+	GRIP_PRESCREEN_MODE_1	= 1,
+	GRIP_PRESCREEN_MODE_2	= 2,
+	GRIP_PRESCREEN_MODE_3	= 3
+};
+
+enum {
+	GRIP_PRESCREEN_TIMEOUT_MIN	= 0,
+	GRIP_PRESCREEN_TIMEOUT_MAX	= 480
+};
+
+enum {
+	ENCODED_ENABLE_OFF	= 0,
+	ENCODED_ENABLE_ON	= 1
+};
+
+/* Motion filter finite state machine (FSM) states
+ * SEC_TS_MF_FILTERED        - default coordinate filtering
+ * SEC_TS_MF_UNFILTERED      - unfiltered single-touch coordinates
+ * SEC_TS_MF_FILTERED_LOCKED - filtered coordinates. Locked until touch is
+ *			       lifted.
+ */
+enum motion_filter_state_t {
+	SEC_TS_MF_FILTERED         = 0,
+	SEC_TS_MF_UNFILTERED       = 1,
+	SEC_TS_MF_FILTERED_LOCKED  = 2
+};
+
+#if IS_ENABLED(CONFIG_TOUCHSCREEN_HEATMAP)
+/* Local heatmap */
+#define LOCAL_HEATMAP_WIDTH 7
+#define LOCAL_HEATMAP_HEIGHT 7
+
+struct heatmap_report {
+	int8_t offset_x;
+	uint8_t size_x;
+	int8_t offset_y;
+	uint8_t size_y;
+	/* data is in BE order; order should be enforced after data is read */
+	strength_t data[LOCAL_HEATMAP_WIDTH * LOCAL_HEATMAP_HEIGHT];
+} __packed;
+
+struct heatmap_data {
+	ktime_t timestamp;
+	uint16_t size_x;
+	uint16_t size_y;
+	uint8_t *data;
+} __packed;
+#endif
+
+#define TEST_MODE_MIN_MAX		false
+#define TEST_MODE_ALL_NODE		true
+#define TEST_MODE_READ_FRAME		0
+#define TEST_MODE_READ_CHANNEL		1
+#define TEST_MODE_READ_ALL		2
+
+/* factory test mode */
+struct sec_ts_test_mode {
+	u8 type;
+	short min[REGION_TYPE_COUNT];
+	short max[REGION_TYPE_COUNT];
+	bool allnode;
+	u8 frame_channel;
+	enum spec_check_type spec_check;
+};
+
+struct sec_ts_fw_file {
+	u8 *data;
+	u32 pos;
+	size_t size;
+};
+
+/*
+ * write 0xE4 [ 11 | 10 | 01 | 00 ]
+ * MSB <-------------------> LSB
+ * read 0xE4
+ * mapping sequnce : LSB -> MSB
+ * struct sec_ts_test_result {
+ * * assy : front + OCTA assay
+ * * module : only OCTA
+ *	 union {
+ *		 struct {
+ *			 u8 assy_count:2;		-> 00
+ *			 u8 assy_result:2;		-> 01
+ *			 u8 module_count:2;	-> 10
+ *			 u8 module_result:2;	-> 11
+ *		 } __attribute__ ((packed));
+ *		 unsigned char data[1];
+ *	 };
+ *};
+ */
+struct sec_ts_test_result {
+	union {
+		struct {
+			u8 assy_count:2;
+			u8 assy_result:2;
+			u8 module_count:2;
+			u8 module_result:2;
+		} __packed;
+		unsigned char data[1];
+	};
+};
+
+/* 8 byte */
+struct sec_ts_gesture_status {
+	u8 eid:2;
+	u8 stype:4;
+	u8 sf:2;
+	u8 gesture_id;
+	u8 gesture_data_1;
+	u8 gesture_data_2;
+	u8 gesture_data_3;
+	u8 gesture_data_4;
+	u8 reserved_1;
+	u8 left_event_5_0:6;
+	u8 reserved_2:2;
+} __packed;
+
+
+/* status id for sec_ts event */
+#define SEC_TS_EVENT_STATUS_ID_HOPPING		0x33
+#define SEC_TS_EVENT_STATUS_ID_REPORT_RATE	0x34
+#define SEC_TS_EVENT_STATUS_ID_VSYNC		0x35
+#define SEC_TS_EVENT_STATUS_ID_NOISE		0x64
+#define SEC_TS_EVENT_STATUS_ID_WLC		0x66
+#define SEC_TS_EVENT_STATUS_ID_GRIP		0x69
+#define SEC_TS_EVENT_STATUS_ID_FOD		0x6B
+#define SEC_TS_EVENT_STATUS_ID_PALM		0x70
+
+/* 8 byte */
+struct sec_ts_fod_event {
+	struct {
+		u8 type;
+		u8 id;
+		u8 status;
+		u8 x_b7_b0;
+		union {
+			struct {
+				u8 y_b11_b8:4;
+				u8 x_b11_b8:4;
+			};
+			u8 x_y_b11_b8;
+		};
+		u8 y_b7_b0;
+		u8 reserved[2];
+	};
+} __packed;
+
+/* 8 byte */
+struct sec_ts_event_status {
+	union {
+		struct {
+			u8 eid:2;
+			u8 stype:4;
+			u8 sf:2;
+			u8 status_id;
+			u8 status_data_1;
+			u8 status_data_2;
+			u8 status_data_3;
+			u8 status_data_4;
+			u8 status_data_5;
+			u8 left_event_5_0:6;
+			u8 reserved_2:2;
+		}  __packed;
+		u8 data[8];
+	};
+} __packed;
+
+/* 8 byte */
+struct sec_ts_event_coordinate {
+	u8 eid:2;
+	u8 tid:4;
+	u8 tchsta:2;
+	u8 x_11_4;
+	u8 y_11_4;
+	u8 y_3_0:4;
+	u8 x_3_0:4;
+	u8 major;
+	u8 minor;
+	u8 z:6;
+	u8 ttype_3_2:2;
+	u8 left_event:6;
+	u8 ttype_1_0:2;
+} __packed;
+
+/* 8 byte */
+struct sec_ts_event_hopping {
+	u8 eid:2;
+	u8 stype:4;
+	u8 sf:2;
+	u8 event_id;
+	u8 id:4;
+	u8 cause: 4;
+	u8 prev_id;
+	u8 noise_lvl[2];
+	u8 reserved_6;
+	u8 reserved_7;
+} __packed;
+
+/* not fixed */
+struct sec_ts_coordinate {
+	u8 id;
+	u8 ttype;
+	u8 action;
+	u16 x;
+	u16 y;
+	u8 z;
+	u8 hover_flag;
+	u8 glove_flag;
+	u8 touch_height;
+	u16 mcount;
+	u16 major;
+	u16 minor;
+	bool palm;
+	u8 left_event;
+	bool grip;
+	/* for debug purpose. */
+	u16 x_pressed;	/* x coord on first down timing. */
+	u16 y_pressed;	/* y coord on first down timing. */
+	ktime_t ktime_pressed;
+	ktime_t ktime_released;
+};
+
+struct sec_ts_health_check {
+	ktime_t int_ktime;
+	u64 int_idx;
+	u64 coord_idx;
+	u64 status_idx;
+	/* Slot active bit from FW. */
+	unsigned long active_bit;
+	/* Check whether have coord, status or unknown event. */
+	bool coord_updated;
+	bool status_updated;
+};
+
+struct sec_ts_data {
+	u32 isr_pin;
+
+	u32 crc_addr;
+	u32 fw_addr;
+	u32 para_addr;
+	u32 flash_page_size;
+	u8 boot_ver[3];
+
+	struct device *dev;
+#ifdef I2C_INTERFACE
+	struct i2c_client *client;
+#else
+	struct spi_device *client;
+#endif
+	struct input_dev *input_dev;
+	struct input_dev *input_dev_pad;
+	struct input_dev *input_dev_touch;
+	struct sec_ts_plat_data *plat_data;
+	struct sec_ts_coordinate coord[MAX_SUPPORT_TOUCH_COUNT +
+					MAX_SUPPORT_HOVER_COUNT];
+
+	ktime_t timestamp; /* time that the event was first received from
+			    * the touch IC, acquired during hard interrupt,
+			    * in CLOCK_MONOTONIC
+			    **/
+
+	s64 longest_duration; /* ms unit */
+
+	u8 lowpower_mode;
+	u8 lowpower_status;
+	u8 dex_mode;
+	char *dex_name;
+	u8 brush_mode;
+	u8 touchable_area;
+	volatile bool input_closed;
+
+	struct mutex bus_mutex;
+	u16 bus_refmask;
+	struct completion bus_resumed;
+	struct completion boot_completed;
+
+	unsigned int touch_count;	/* active touch slot(s). */
+	int tx_count;
+	int rx_count;
+	int io_burstmax;
+	int ta_status;
+	volatile int power_status;
+	int raw_status;
+	int touchkey_glove_mode_status;
+	u16 touch_functions;
+	u8 charger_mode;
+	struct sec_ts_event_coordinate touchtype;
+	u8 gesture_status[6];
+	u8 cal_status;
+	struct mutex lock;
+	struct mutex device_mutex;
+	struct mutex io_mutex;
+	struct mutex eventlock;
+
+	struct drm_bridge panel_bridge;
+	struct drm_connector *connector;
+	bool is_panel_lp_mode;
+	int display_refresh_rate;	/* Display rate in Hz */
+
+	struct pm_qos_request pm_qos_req;
+
+	/* Stop changing charger mode by notifier */
+	u8 ignore_charger_nb;
+	/* Stop changing motion filter and keep fw design */
+	u8 use_default_mf;
+	/* Motion filter finite state machine (FSM) state */
+	enum motion_filter_state_t mf_state;
+	/* Time of initial single-finger touch down. This timestamp is used to
+	 * compute the duration a single finger is touched before it is lifted.
+	 */
+	ktime_t mf_downtime;
+
+	u8 print_format;
+	u8 ms_frame_type;
+	u8 ss_frame_type;
+	int heatmap_dump;
+#if IS_ENABLED(CONFIG_TOUCHSCREEN_HEATMAP)
+	struct v4l2_heatmap v4l2;
+	struct heatmap_data mutual_strength_heatmap;
+	strength_t *heatmap_buff;
+	strength_t *encoded_buff;
+	bool heatmap_init_done;
+	bool v4l2_mutual_strength_updated;
+#endif
+
+#if IS_ENABLED(CONFIG_TOUCHSCREEN_OFFLOAD)
+	struct touch_offload_context offload;
+#endif
+
+#ifdef USE_POWER_RESET_WORK
+	struct delayed_work reset_work;
+	volatile bool reset_is_on_going;
+#endif
+
+#ifdef SEC_TS_FW_UPDATE_ON_PROBE
+	struct work_struct fw_update_work;
+#else
+	struct delayed_work fw_update_work;
+	struct workqueue_struct *fw_update_wq;
+#endif
+
+#ifdef USE_CHARGER_WORK
+	struct work_struct charger_work;	/* charger work */
+#endif
+	struct work_struct suspend_work;
+	struct work_struct resume_work;
+	struct workqueue_struct *event_wq;	/* Used for event handler,
+						 * suspend, resume threads
+						 **/
+	struct completion resume_done;
+	struct sec_cmd_data sec;
+	union {
+		short *pFrame;
+		short *pFrameMS;
+	};
+
+	/* only available if sec_ts_read_frame_and_channel() be called */
+	short *pFrameSS;
+
+#ifdef USE_STIM_PAD
+	u8 *gainTable;
+#endif
+
+	bool probe_done;
+	bool reinit_done;
+	bool flip_enable;
+	int cover_type;
+	u8 cover_cmd;
+	u16 rect_data[4];
+
+	int tspid_val;
+	int tspicid_val;
+
+	bool use_customlib;
+	unsigned int scrub_id;
+	unsigned int scrub_x;
+	unsigned int scrub_y;
+
+	u8 grip_edgehandler_direction;
+	int grip_edgehandler_start_y;
+	int grip_edgehandler_end_y;
+	u16 grip_edge_range;
+	u8 grip_deadzone_up_x;
+	u8 grip_deadzone_dn_x;
+	int grip_deadzone_y;
+	u8 grip_landscape_mode;
+	int grip_landscape_edge;
+	u16 grip_landscape_deadzone;
+
+#ifdef CONFIG_TOUCHSCREEN_DUMP_MODE
+	struct delayed_work ghost_check;
+#endif
+	u8 tsp_dump_lock;
+
+	int nv;
+	int cal_count;
+	int tune_fix_ver;
+	bool external_factory;
+
+	int report_rate;
+	int vsync;
+	int wet_mode;
+
+	unsigned char ito_test[4];		/* ito panel tx/rx chanel */
+	unsigned char check_multi;
+	unsigned int multi_count;		/* multi touch count */
+	unsigned int palm_count;
+	unsigned int wet_count;			/* wet mode count */
+	unsigned int dive_count;		/* dive mode count */
+	unsigned int comm_err_count;		/* comm error count */
+	unsigned int io_err_count;		/* io error count */
+	unsigned int hw_reset_count;
+	/*
+	 * accumulated count of pressed
+	 * touch from resume to suspend.
+	 */
+	unsigned int pressed_count;
+	unsigned int checksum_result;		/* checksum result */
+	unsigned char module_id[4];
+	unsigned int all_finger_count;
+	unsigned int all_force_count;
+	unsigned int all_aod_tap_count;
+	unsigned int all_spay_count;
+	unsigned int max_z_value;
+	unsigned int min_z_value;
+	unsigned int sum_z_value;
+	unsigned char pressure_cal_base;
+	unsigned char pressure_cal_delta;
+
+#ifdef USE_PRESSURE_SENSOR
+	short pressure_left;
+	short pressure_center;
+	short pressure_right;
+	u8 pressure_user_level;
+#endif
+	union {
+		u32 debug;
+		struct {
+		u32 debug_events : 1;
+		u32 debug_status : 1;
+		u32 debug_reserved : 30;
+		};
+	};
+
+	int fs_postcal_mean;
+
+	bool is_fw_corrupted;
+	union {
+		u8 cali_report[8];
+		struct {
+		u8 cali_report_try_cnt;
+		u8 cali_report_pass_cnt;
+		u8 cali_report_fail_cnt;
+		u8 cali_report_status;
+		u8 cali_report_param_ver[4];
+		};
+	};
+
+	/* slot id active state(bit mask) for grip/palm
+	 **/
+	unsigned long tid_palm_state;
+	unsigned long tid_grip_state;
+	/* slot id active state(bit mask) for all touch types
+	 **/
+	unsigned long tid_touch_state;
+	/* Record the state that grip/palm was leaved once ever after any
+	 * touch pressed. This state will set to default after all active
+	 * touch released.
+	 **/
+	bool palms_leaved_once;
+	bool grips_leaved_once;
+
+#if IS_ENABLED(CONFIG_TOUCHSCREEN_TBN)
+	u32 tbn_register_mask;
+#endif
+
+	struct power_supply *wireless_psy;
+	struct power_supply *usb_psy;
+	struct notifier_block psy_nb;
+	bool wlc_online;
+	bool usb_present;
+	bool force_wlc;
+	ktime_t usb_changed_ktime;
+	ktime_t wlc_changed_ktime;
+
+	ktime_t bugreport_ktime_start;
+	ktime_t ktime_resume;
+	u64 int_cnt;
+	u64 coord_event_cnt;
+	u64 status_event_cnt;
+
+	int (*sec_ts_write)(struct sec_ts_data *ts, u8 reg,
+				u8 *data, int len);
+
+	int (*sec_ts_read)(struct sec_ts_data *ts, u8 reg,
+				    u8 *data, int len);
+	int (*sec_ts_read_heap)(struct sec_ts_data *ts, u8 reg,
+				    u8 *data, int len);
+
+	int (*sec_ts_write_burst)(struct sec_ts_data *ts,
+					   u8 *data, int len);
+	int (*sec_ts_write_burst_heap)(struct sec_ts_data *ts,
+					   u8 *data, int len);
+
+	int (*sec_ts_read_bulk)(struct sec_ts_data *ts,
+					 u8 *data, int len);
+	int (*sec_ts_read_bulk_heap)(struct sec_ts_data *ts,
+					 u8 *data, int len);
+
+	int (*sec_ts_read_customlib)(struct sec_ts_data *ts,
+				     u8 *data, int len);
+
+	/* alloc for io read buffer */
+	u8 io_read_buf[IO_PREALLOC_READ_BUF_SZ];
+	/* alloc for io write buffer */
+	u8 io_write_buf[IO_PREALLOC_WRITE_BUF_SZ];
+};
+
+struct sec_ts_plat_data {
+	int fod_x;
+	int fod_y;
+	int max_x;
+	int max_y;
+	unsigned int irq_gpio;
+	int irq_type;
+	int io_burstmax;
+	int always_lpmode;
+	int bringup;
+	int mis_cal_check;
+	int heatmap_mode;
+	int grip_prescreen_mode;
+	int grip_prescreen_timeout;
+	bool is_heatmap_enabled;
+	int encoded_enable;
+	int encoded_frame_counter;
+	int encoded_skip_counter;
+#ifdef PAT_CONTROL
+	int pat_function;
+	int afe_base;
+#endif
+	const char *firmware_name;
+	const char *model_name;
+	const char *project_name;
+	struct regulator *regulator_vdd;
+	struct regulator *regulator_avdd;
+
+	u32 panel_revision;
+	u8 core_version_of_ic[4];
+	u8 core_version_of_bin[4];
+	u8 config_version_of_ic[4];
+	u8 config_version_of_bin[4];
+	u8 img_version_of_ic[4];
+	u8 img_version_of_bin[4];
+
+	struct pinctrl *pinctrl;
+
+	int (*power)(void *data, bool on);
+	void (*enable_sync)(bool on);
+	int tsp_icid;
+	int tsp_id;
+	int vsync_gpio;
+	int switch_gpio;
+	int reset_gpio;
+
+	bool regulator_boot_on;
+	bool support_mt_pressure;
+	bool support_dex;
+	bool support_sidegesture;
+
+	struct drm_panel *panel;
+	u32 initial_panel_index;
+	u32 offload_id;
+
+	/* convert mm to pixel for major and minor */
+	u8 mm2px;
+};
+
+void sec_ts_hc_dump(struct sec_ts_data *ts);
+void sec_ts_debug_dump(struct sec_ts_data *ts);
+int sec_ts_stop_device(struct sec_ts_data *ts);
+int sec_ts_start_device(struct sec_ts_data *ts);
+int sec_ts_hw_reset(struct sec_ts_data *ts, bool wait_for_done);
+int sec_ts_sw_reset(struct sec_ts_data *ts, bool wait_for_done);
+int sec_ts_system_reset(struct sec_ts_data *ts,
+			enum RESET_MODE mode,
+			bool wait_for_done,
+			bool sense_on);
+int sec_ts_set_lowpowermode(struct sec_ts_data *ts, u8 mode);
+int sec_ts_firmware_update_on_probe(struct sec_ts_data *ts, bool force_update);
+int sec_ts_firmware_update_on_hidden_menu(struct sec_ts_data *ts,
+					    int update_type);
+int sec_ts_glove_mode_enables(struct sec_ts_data *ts, int mode);
+int sec_ts_set_cover_type(struct sec_ts_data *ts, bool enable);
+int sec_ts_wait_for_ready(struct sec_ts_data *ts, unsigned int ack);
+int sec_ts_wait_for_ready_with_count(struct sec_ts_data *ts, unsigned int ack,
+				     unsigned int count);
+int sec_ts_try_wake(struct sec_ts_data *ts, bool wake_setting);
+int sec_ts_set_bus_ref(struct sec_ts_data *ts, u16 ref, bool enable);
+
+int sec_ts_function(int (*func_init)(void *device_data),
+		    void (*func_remove)(void));
+int sec_ts_fn_init(struct sec_ts_data *ts);
+int sec_ts_read_calibration_report(struct sec_ts_data *ts);
+int sec_ts_execute_force_calibration(struct sec_ts_data *ts, int cal_mode);
+int sec_ts_fix_tmode(struct sec_ts_data *ts, u8 mode, u8 state);
+int sec_ts_release_tmode(struct sec_ts_data *ts);
+int get_tsp_nvm_data(struct sec_ts_data *ts, u8 offset);
+void set_tsp_nvm_data_clear(struct sec_ts_data *ts, u8 offset);
+#ifdef SEC_TS_SUPPORT_CUSTOMLIB
+int sec_ts_set_custom_library(struct sec_ts_data *ts);
+int sec_ts_check_custom_library(struct sec_ts_data *ts);
+#endif
+void sec_ts_unlocked_release_all_finger(struct sec_ts_data *ts);
+void sec_ts_locked_release_all_finger(struct sec_ts_data *ts);
+void sec_ts_fn_remove(struct sec_ts_data *ts);
+void sec_ts_delay(unsigned int ms);
+int sec_ts_read_information(struct sec_ts_data *ts);
+#ifdef PAT_CONTROL
+void set_pat_magic_number(struct sec_ts_data *ts);
+#endif
+int sec_ts_run_rawdata_type(struct sec_ts_data *ts, struct sec_cmd_data *sec);
+void sec_ts_run_rawdata_all(struct sec_ts_data *ts, bool full_read);
+int execute_selftest(struct sec_ts_data *ts, u32 option);
+int execute_p2ptest(struct sec_ts_data *ts);
+int sec_ts_read_raw_data(struct sec_ts_data *ts,
+		struct sec_cmd_data *sec, struct sec_ts_test_mode *mode);
+u8 sec_ts_run_cal_check(struct sec_ts_data *ts);
+
+#if (1)//!defined(CONFIG_SAMSUNG_PRODUCT_SHIP)
+int sec_ts_raw_device_init(struct sec_ts_data *ts);
+#endif
+void sec_ts_raw_device_exit(struct sec_ts_data *ts);
+
+extern struct class *sec_class;
+
+#if defined(CONFIG_FB_MSM_MDSS_SAMSUNG)
+extern int get_lcd_attached(char *mode);
+#endif
+
+#if defined(CONFIG_EXYNOS_DECON_FB)
+extern int get_lcd_info(char *arg);
+#endif
+
+#ifdef CONFIG_MOTOR_DRV_MAX77865
+extern int haptic_homekey_press(void);
+extern int haptic_homekey_release(void);
+#else
+#define haptic_homekey_press() {}
+#define haptic_homekey_release() {}
+#endif
+
+extern bool tsp_init_done;
+
+extern struct sec_ts_data *ts_dup;
+
+#ifdef CONFIG_BATTERY_SAMSUNG
+extern unsigned int lpcharge;
+#endif
+
+extern void set_grip_data_to_ic(struct sec_ts_data *ts, u8 flag);
+extern void sec_ts_set_grip_type(struct sec_ts_data *ts, u8 set_type);
+
+
+#endif
diff --git a/sec_ts_fac_spec.h b/sec_ts_fac_spec.h
new file mode 100644
index 0000000..c0ae9f7
--- /dev/null
+++ b/sec_ts_fac_spec.h
@@ -0,0 +1,518 @@
+/* GC1 rawcap gap spec */
+
+/* Cm region definition table
+ * 0 : Normal
+ * 1 : Edge
+ * 2 : Corner
+ * 3 : Notch
+ */
+const int cm_region[34][16] = {
+	{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
+	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+	{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
+	{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
+};
+
+/* Cm spec by region
+ * region = {NORMAL, EDGE, CORNER, NOTCH}
+ * CM_MAX = max, CM_MIN = min, CM_MM = max - min
+ */
+const short cm_max[4] = { 720, 720, 1024, 1024 };
+const short cm_min[4] = { 190, 190,    0,    0 };
+const short cm_mm[4]  = { 700, 700, 1024, 1024 };
+
+const int cm_gap[34][16] = {
+	{60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60},
+	{20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20},
+	{20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20},
+	{20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20},
+	{20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20},
+	{20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20},
+	{20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20},
+	{20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20},
+	{20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20},
+	{20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20},
+	{20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20},
+	{20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20},
+	{20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20},
+	{20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20},
+	{20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20},
+	{20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20},
+	{20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20},
+	{20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20},
+	{20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20},
+	{20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20},
+	{20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20},
+	{20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20},
+	{20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20},
+	{20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20},
+	{20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20},
+	{20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20},
+	{20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20},
+	{20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20},
+	{20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20},
+	{20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20},
+	{20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20},
+	{20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20},
+	{60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60},
+	{60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60},
+};
+
+const int cm2_region[34][16] = {
+	{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
+	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+	{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
+	{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
+};
+
+const short cm2_max[4] = { 500, 500, 1024, 1024 };
+const short cm2_min[4] = {  97,  97,    0,    0 };
+const short cm2_mm[4]  = { 500, 500, 1024, 1024 };
+
+const int cm2_gap[34][16] = {
+	{80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80},
+	{80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80},
+	{80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80},
+	{80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80},
+	{80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80},
+	{80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80},
+	{80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80},
+	{80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80},
+	{80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80},
+	{80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80},
+	{80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80},
+	{80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80},
+	{80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80},
+	{80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80},
+	{80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80},
+	{80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80},
+	{80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80},
+	{80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80},
+	{80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80},
+	{80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80},
+	{80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80},
+	{80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80},
+	{80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80},
+	{80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80},
+	{80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80},
+	{80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80},
+	{80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80},
+	{80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80},
+	{80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80},
+	{80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80},
+	{80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80},
+	{80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80},
+	{80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80},
+	{80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80},
+};
+
+const int noi_min[34][16] = {
+	{-30, -30, -30, -30, -30, -30, -30, -30,
+		-30, -30, -30, -30, -30, -30, -30, -30},
+	{-30, -30, -30, -30, -30, -30, -30, -30,
+		-30, -30, -30, -30, -30, -30, -30, -30},
+	{-30, -30, -30, -30, -30, -30, -30, -30,
+		-30, -30, -30, -30, -30, -30, -30, -30},
+	{-30, -30, -30, -30, -30, -30, -30, -30,
+		-30, -30, -30, -30, -30, -30, -30, -30},
+	{-30, -30, -30, -30, -30, -30, -30, -30,
+		-30, -30, -30, -30, -30, -30, -30, -30},
+	{-30, -30, -30, -30, -30, -30, -30, -30,
+		-30, -30, -30, -30, -30, -30, -30, -30},
+	{-30, -30, -30, -30, -30, -30, -30, -30,
+		-30, -30, -30, -30, -30, -30, -30, -30},
+	{-30, -30, -30, -30, -30, -30, -30, -30,
+		-30, -30, -30, -30, -30, -30, -30, -30},
+	{-30, -30, -30, -30, -30, -30, -30, -30,
+		-30, -30, -30, -30, -30, -30, -30, -30},
+	{-30, -30, -30, -30, -30, -30, -30, -30,
+		-30, -30, -30, -30, -30, -30, -30, -30},
+	{-30, -30, -30, -30, -30, -30, -30, -30,
+		-30, -30, -30, -30, -30, -30, -30, -30},
+	{-30, -30, -30, -30, -30, -30, -30, -30,
+		-30, -30, -30, -30, -30, -30, -30, -30},
+	{-30, -30, -30, -30, -30, -30, -30, -30,
+		-30, -30, -30, -30, -30, -30, -30, -30},
+	{-30, -30, -30, -30, -30, -30, -30, -30,
+		-30, -30, -30, -30, -30, -30, -30, -30},
+	{-30, -30, -30, -30, -30, -30, -30, -30,
+		-30, -30, -30, -30, -30, -30, -30, -30},
+	{-30, -30, -30, -30, -30, -30, -30, -30,
+		-30, -30, -30, -30, -30, -30, -30, -30},
+	{-30, -30, -30, -30, -30, -30, -30, -30,
+		-30, -30, -30, -30, -30, -30, -30, -30},
+	{-30, -30, -30, -30, -30, -30, -30, -30,
+		-30, -30, -30, -30, -30, -30, -30, -30},
+	{-30, -30, -30, -30, -30, -30, -30, -30,
+		-30, -30, -30, -30, -30, -30, -30, -30},
+	{-30, -30, -30, -30, -30, -30, -30, -30,
+		-30, -30, -30, -30, -30, -30, -30, -30},
+	{-30, -30, -30, -30, -30, -30, -30, -30,
+		-30, -30, -30, -30, -30, -30, -30, -30},
+	{-30, -30, -30, -30, -30, -30, -30, -30,
+		-30, -30, -30, -30, -30, -30, -30, -30},
+	{-30, -30, -30, -30, -30, -30, -30, -30,
+		-30, -30, -30, -30, -30, -30, -30, -30},
+	{-30, -30, -30, -30, -30, -30, -30, -30,
+		-30, -30, -30, -30, -30, -30, -30, -30},
+	{-30, -30, -30, -30, -30, -30, -30, -30,
+		-30, -30, -30, -30, -30, -30, -30, -30},
+	{-30, -30, -30, -30, -30, -30, -30, -30,
+		-30, -30, -30, -30, -30, -30, -30, -30},
+	{-30, -30, -30, -30, -30, -30, -30, -30,
+		-30, -30, -30, -30, -30, -30, -30, -30},
+	{-30, -30, -30, -30, -30, -30, -30, -30,
+		-30, -30, -30, -30, -30, -30, -30, -30},
+	{-30, -30, -30, -30, -30, -30, -30, -30,
+		-30, -30, -30, -30, -30, -30, -30, -30},
+	{-30, -30, -30, -30, -30, -30, -30, -30,
+		-30, -30, -30, -30, -30, -30, -30, -30},
+	{-30, -30, -30, -30, -30, -30, -30, -30,
+		-30, -30, -30, -30, -30, -30, -30, -30},
+	{-30, -30, -30, -30, -30, -30, -30, -30,
+		-30, -30, -30, -30, -30, -30, -30, -30},
+	{-30, -30, -30, -30, -30, -30, -30, -30,
+		-30, -30, -30, -30, -30, -30, -30, -30},
+	{-30, -30, -30, -30, -30, -30, -30, -30,
+		-30, -30, -30, -30, -30, -30, -30, -30},
+};
+
+const int noi_max[34][16] = {
+	{30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30},
+	{30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30},
+	{30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30},
+	{30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30},
+	{30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30},
+	{30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30},
+	{30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30},
+	{30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30},
+	{30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30},
+	{30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30},
+	{30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30},
+	{30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30},
+	{30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30},
+	{30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30},
+	{30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30},
+	{30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30},
+	{30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30},
+	{30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30},
+	{30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30},
+	{30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30},
+	{30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30},
+	{30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30},
+	{30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30},
+	{30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30},
+	{30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30},
+	{30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30},
+	{30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30},
+	{30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30},
+	{30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30},
+	{30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30},
+	{30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30},
+	{30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30},
+	{30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30},
+	{30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30},
+};
+
+const int noi_mm = 60;
+
+const int cm_stdev_max = 15000;
+
+const int cs_tx_max = -7530;
+
+const int cs_tx_min = -20060;
+
+const int cs_tx_mm = 25000;
+
+const int cs_rx_max = -7530;
+
+const int cs_rx_min = -20060;
+
+const int cs_rx_mm = 25000;
+
+/* fs_precal high limit : +20% of fs target */
+const int fs_precal_h[34][16] = {
+	{336, 336, 336, 336, 336, 336, 336, 336,
+		336, 336, 336, 336, 336, 336, 336, 336},
+	{336, 336, 336, 336, 336, 336, 336, 336,
+		336, 336, 336, 336, 336, 336, 336, 336},
+	{336, 336, 336, 336, 336, 336, 336, 336,
+		336, 336, 336, 336, 336, 336, 336, 336},
+	{336, 336, 336, 336, 336, 336, 336, 336,
+		336, 336, 336, 336, 336, 336, 336, 336},
+	{336, 336, 336, 336, 336, 336, 336, 336,
+		336, 336, 336, 336, 336, 336, 336, 336},
+	{336, 336, 336, 336, 336, 336, 336, 336,
+		336, 336, 336, 336, 336, 336, 336, 336},
+	{336, 336, 336, 336, 336, 336, 336, 336,
+		336, 336, 336, 336, 336, 336, 336, 336},
+	{336, 336, 336, 336, 336, 336, 336, 336,
+		336, 336, 336, 336, 336, 336, 336, 336},
+	{336, 336, 336, 336, 336, 336, 336, 336,
+		336, 336, 336, 336, 336, 336, 336, 336},
+	{336, 336, 336, 336, 336, 336, 336, 336,
+		336, 336, 336, 336, 336, 336, 336, 336},
+	{336, 336, 336, 336, 336, 336, 336, 336,
+		336, 336, 336, 336, 336, 336, 336, 336},
+	{336, 336, 336, 336, 336, 336, 336, 336,
+		336, 336, 336, 336, 336, 336, 336, 336},
+	{336, 336, 336, 336, 336, 336, 336, 336,
+		336, 336, 336, 336, 336, 336, 336, 336},
+	{336, 336, 336, 336, 336, 336, 336, 336,
+		336, 336, 336, 336, 336, 336, 336, 336},
+	{336, 336, 336, 336, 336, 336, 336, 336,
+		336, 336, 336, 336, 336, 336, 336, 336},
+	{336, 336, 336, 336, 336, 336, 336, 336,
+		336, 336, 336, 336, 336, 336, 336, 336},
+	{336, 336, 336, 336, 336, 336, 336, 336,
+		336, 336, 336, 336, 336, 336, 336, 336},
+	{336, 336, 336, 336, 336, 336, 336, 336,
+		336, 336, 336, 336, 336, 336, 336, 336},
+	{336, 336, 336, 336, 336, 336, 336, 336,
+		336, 336, 336, 336, 336, 336, 336, 336},
+	{336, 336, 336, 336, 336, 336, 336, 336,
+		336, 336, 336, 336, 336, 336, 336, 336},
+	{336, 336, 336, 336, 336, 336, 336, 336,
+		336, 336, 336, 336, 336, 336, 336, 336},
+	{336, 336, 336, 336, 336, 336, 336, 336,
+		336, 336, 336, 336, 336, 336, 336, 336},
+	{336, 336, 336, 336, 336, 336, 336, 336,
+		336, 336, 336, 336, 336, 336, 336, 336},
+	{336, 336, 336, 336, 336, 336, 336, 336,
+		336, 336, 336, 336, 336, 336, 336, 336},
+	{336, 336, 336, 336, 336, 336, 336, 336,
+		336, 336, 336, 336, 336, 336, 336, 336},
+	{336, 336, 336, 336, 336, 336, 336, 336,
+		336, 336, 336, 336, 336, 336, 336, 336},
+	{336, 336, 336, 336, 336, 336, 336, 336,
+		336, 336, 336, 336, 336, 336, 336, 336},
+	{336, 336, 336, 336, 336, 336, 336, 336,
+		336, 336, 336, 336, 336, 336, 336, 336},
+	{336, 336, 336, 336, 336, 336, 336, 336,
+		336, 336, 336, 336, 336, 336, 336, 336},
+	{336, 336, 336, 336, 336, 336, 336, 336,
+		336, 336, 336, 336, 336, 336, 336, 336},
+	{336, 336, 336, 336, 336, 336, 336, 336,
+		336, 336, 336, 336, 336, 336, 336, 336},
+	{336, 336, 336, 336, 336, 336, 336, 336,
+		336, 336, 336, 336, 336, 336, 336, 336},
+	{336, 336, 336, 336, 336, 336, 336, 336,
+		336, 336, 336, 336, 336, 336, 336, 336},
+	{336, 336, 336, 336, 336, 336, 336, 336,
+		336, 336, 336, 336, 336, 336, 336, 336},
+};
+
+/* fs_mean high limit : +4% of fs_mean target */
+const int fs_mean_target_h = 269;
+
+/* fs_mean low limit : -4% of fs_mean target */
+const int fs_mean_target_l = 291;
+
+const int fs_postcal_uniform_spec = 4;
+
+/* fs_precal low limit : -20% of fs target */
+const int fs_precal_l[34][16] = {
+	{224, 224, 224, 224, 224, 224, 224, 224,
+		224, 224, 224, 224, 224, 224, 224, 224},
+	{224, 224, 224, 224, 224, 224, 224, 224,
+		224, 224, 224, 224, 224, 224, 224, 224},
+	{224, 224, 224, 224, 224, 224, 224, 224,
+		224, 224, 224, 224, 224, 224, 224, 224},
+	{224, 224, 224, 224, 224, 224, 224, 224,
+		224, 224, 224, 224, 224, 224, 224, 224},
+	{224, 224, 224, 224, 224, 224, 224, 224,
+		224, 224, 224, 224, 224, 224, 224, 224},
+	{224, 224, 224, 224, 224, 224, 224, 224,
+		224, 224, 224, 224, 224, 224, 224, 224},
+	{224, 224, 224, 224, 224, 224, 224, 224,
+		224, 224, 224, 224, 224, 224, 224, 224},
+	{224, 224, 224, 224, 224, 224, 224, 224,
+		224, 224, 224, 224, 224, 224, 224, 224},
+	{224, 224, 224, 224, 224, 224, 224, 224,
+		224, 224, 224, 224, 224, 224, 224, 224},
+	{224, 224, 224, 224, 224, 224, 224, 224,
+		224, 224, 224, 224, 224, 224, 224, 224},
+	{224, 224, 224, 224, 224, 224, 224, 224,
+		224, 224, 224, 224, 224, 224, 224, 224},
+	{224, 224, 224, 224, 224, 224, 224, 224,
+		224, 224, 224, 224, 224, 224, 224, 224},
+	{224, 224, 224, 224, 224, 224, 224, 224,
+		224, 224, 224, 224, 224, 224, 224, 224},
+	{224, 224, 224, 224, 224, 224, 224, 224,
+		224, 224, 224, 224, 224, 224, 224, 224},
+	{224, 224, 224, 224, 224, 224, 224, 224,
+		224, 224, 224, 224, 224, 224, 224, 224},
+	{224, 224, 224, 224, 224, 224, 224, 224,
+		224, 224, 224, 224, 224, 224, 224, 224},
+	{224, 224, 224, 224, 224, 224, 224, 224,
+		224, 224, 224, 224, 224, 224, 224, 224},
+	{224, 224, 224, 224, 224, 224, 224, 224,
+		224, 224, 224, 224, 224, 224, 224, 224},
+	{224, 224, 224, 224, 224, 224, 224, 224,
+		224, 224, 224, 224, 224, 224, 224, 224},
+	{224, 224, 224, 224, 224, 224, 224, 224,
+		224, 224, 224, 224, 224, 224, 224, 224},
+	{224, 224, 224, 224, 224, 224, 224, 224,
+		224, 224, 224, 224, 224, 224, 224, 224},
+	{224, 224, 224, 224, 224, 224, 224, 224,
+		224, 224, 224, 224, 224, 224, 224, 224},
+	{224, 224, 224, 224, 224, 224, 224, 224,
+		224, 224, 224, 224, 224, 224, 224, 224},
+	{224, 224, 224, 224, 224, 224, 224, 224,
+		224, 224, 224, 224, 224, 224, 224, 224},
+	{224, 224, 224, 224, 224, 224, 224, 224,
+		224, 224, 224, 224, 224, 224, 224, 224},
+	{224, 224, 224, 224, 224, 224, 224, 224,
+		224, 224, 224, 224, 224, 224, 224, 224},
+	{224, 224, 224, 224, 224, 224, 224, 224,
+		224, 224, 224, 224, 224, 224, 224, 224},
+	{224, 224, 224, 224, 224, 224, 224, 224,
+		224, 224, 224, 224, 224, 224, 224, 224},
+	{224, 224, 224, 224, 224, 224, 224, 224,
+		224, 224, 224, 224, 224, 224, 224, 224},
+	{224, 224, 224, 224, 224, 224, 224, 224,
+		224, 224, 224, 224, 224, 224, 224, 224},
+	{224, 224, 224, 224, 224, 224, 224, 224,
+		224, 224, 224, 224, 224, 224, 224, 224},
+	{224, 224, 224, 224, 224, 224, 224, 224,
+		224, 224, 224, 224, 224, 224, 224, 224},
+	{224, 224, 224, 224, 224, 224, 224, 224,
+		224, 224, 224, 224, 224, 224, 224, 224},
+	{224, 224, 224, 224, 224, 224, 224, 224,
+		224, 224, 224, 224, 224, 224, 224, 224},
+};
+
+const int fs_target[34][16] = {
+	{280, 280, 280, 280, 280, 280, 280, 280,
+		280, 280, 280, 280, 280, 280, 280, 280},
+	{280, 280, 280, 280, 280, 280, 280, 280,
+		280, 280, 280, 280, 280, 280, 280, 280},
+	{280, 280, 280, 280, 280, 280, 280, 280,
+		280, 280, 280, 280, 280, 280, 280, 280},
+	{280, 280, 280, 280, 280, 280, 280, 280,
+		280, 280, 280, 280, 280, 280, 280, 280},
+	{280, 280, 280, 280, 280, 280, 280, 280,
+		280, 280, 280, 280, 280, 280, 280, 280},
+	{280, 280, 280, 280, 280, 280, 280, 280,
+		280, 280, 280, 280, 280, 280, 280, 280},
+	{280, 280, 280, 280, 280, 280, 280, 280,
+		280, 280, 280, 280, 280, 280, 280, 280},
+	{280, 280, 280, 280, 280, 280, 280, 280,
+		280, 280, 280, 280, 280, 280, 280, 280},
+	{280, 280, 280, 280, 280, 280, 280, 280,
+		280, 280, 280, 280, 280, 280, 280, 280},
+	{280, 280, 280, 280, 280, 280, 280, 280,
+		280, 280, 280, 280, 280, 280, 280, 280},
+	{280, 280, 280, 280, 280, 280, 280, 280,
+		280, 280, 280, 280, 280, 280, 280, 280},
+	{280, 280, 280, 280, 280, 280, 280, 280,
+		280, 280, 280, 280, 280, 280, 280, 280},
+	{280, 280, 280, 280, 280, 280, 280, 280,
+		280, 280, 280, 280, 280, 280, 280, 280},
+	{280, 280, 280, 280, 280, 280, 280, 280,
+		280, 280, 280, 280, 280, 280, 280, 280},
+	{280, 280, 280, 280, 280, 280, 280, 280,
+		280, 280, 280, 280, 280, 280, 280, 280},
+	{280, 280, 280, 280, 280, 280, 280, 280,
+		280, 280, 280, 280, 280, 280, 280, 280},
+	{280, 280, 280, 280, 280, 280, 280, 280,
+		280, 280, 280, 280, 280, 280, 280, 280},
+	{280, 280, 280, 280, 280, 280, 280, 280,
+		280, 280, 280, 280, 280, 280, 280, 280},
+	{280, 280, 280, 280, 280, 280, 280, 280,
+		280, 280, 280, 280, 280, 280, 280, 280},
+	{280, 280, 280, 280, 280, 280, 280, 280,
+		280, 280, 280, 280, 280, 280, 280, 280},
+	{280, 280, 280, 280, 280, 280, 280, 280,
+		280, 280, 280, 280, 280, 280, 280, 280},
+	{280, 280, 280, 280, 280, 280, 280, 280,
+		280, 280, 280, 280, 280, 280, 280, 280},
+	{280, 280, 280, 280, 280, 280, 280, 280,
+		280, 280, 280, 280, 280, 280, 280, 280},
+	{280, 280, 280, 280, 280, 280, 280, 280,
+		280, 280, 280, 280, 280, 280, 280, 280},
+	{280, 280, 280, 280, 280, 280, 280, 280,
+		280, 280, 280, 280, 280, 280, 280, 280},
+	{280, 280, 280, 280, 280, 280, 280, 280,
+		280, 280, 280, 280, 280, 280, 280, 280},
+	{280, 280, 280, 280, 280, 280, 280, 280,
+		280, 280, 280, 280, 280, 280, 280, 280},
+	{280, 280, 280, 280, 280, 280, 280, 280,
+		280, 280, 280, 280, 280, 280, 280, 280},
+	{280, 280, 280, 280, 280, 280, 280, 280,
+		280, 280, 280, 280, 280, 280, 280, 280},
+	{280, 280, 280, 280, 280, 280, 280, 280,
+		280, 280, 280, 280, 280, 280, 280, 280},
+	{280, 280, 280, 280, 280, 280, 280, 280,
+		280, 280, 280, 280, 280, 280, 280, 280},
+	{280, 280, 280, 280, 280, 280, 280, 280,
+		280, 280, 280, 280, 280, 280, 280, 280},
+	{280, 280, 280, 280, 280, 280, 280, 280,
+		280, 280, 280, 280, 280, 280, 280, 280},
+	{280, 280, 280, 280, 280, 280, 280, 280,
+		280, 280, 280, 280, 280, 280, 280, 280},
+};
+
+const int cs_tx_gap = 3600;
+
+const int cs_rx_gap = 3600;
diff --git a/sec_ts_fn.c b/sec_ts_fn.c
new file mode 100644
index 0000000..b7818c1
--- /dev/null
+++ b/sec_ts_fn.c
@@ -0,0 +1,9067 @@
+/* drivers/input/touchscreen/sec_ts_fn.c
+ *
+ * Copyright (C) 2015 Samsung Electronics Co., Ltd.
+ * http://www.samsungsemi.com/
+ *
+ * Core file for Samsung TSC driver
+ *
+ * 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 "sec_ts.h"
+#ifdef USE_SPEC_CHECK
+#include "sec_ts_fac_spec.h"
+#endif
+
+static void fw_update(void *device_data);
+static void get_fw_ver_bin(void *device_data);
+static void get_fw_ver_ic(void *device_data);
+static void get_config_ver(void *device_data);
+#ifdef PAT_CONTROL
+static void get_pat_information(void *device_data);
+static void set_external_factory(void *device_data);
+#endif
+static void get_threshold(void *device_data);
+static void module_off_master(void *device_data);
+static void module_on_master(void *device_data);
+static void get_chip_vendor(void *device_data);
+static void get_chip_name(void *device_data);
+static void set_mis_cal_spec(void *device_data);
+static void get_mis_cal_info(void *device_data);
+static void get_wet_mode(void *device_data);
+static void get_x_num(void *device_data);
+static void get_y_num(void *device_data);
+static void get_x_cross_routing(void *device_data);
+static void get_y_cross_routing(void *device_data);
+static void get_checksum_data(void *device_data);
+static void run_reference_read(void *device_data);
+static void run_reference_read_all(void *device_data);
+static void get_reference(void *device_data);
+static void run_rawcap_read(void *device_data);
+static void run_rawcap_read_all(void *device_data);
+static void run_rawcap_combo_read_all(void *device_data);
+static void run_rawcap_gap_combo_read_all(void *device_data);
+static void run_rawcap_factory_read_all(void *device_data);
+static void run_rawcap_high_freq_read_all(void *device_data);
+static void get_rawcap(void *device_data);
+static void run_rawcap_gap_read_all(void *device_data);
+static void run_delta_read(void *device_data);
+static void run_delta_read_all(void *device_data);
+static void get_delta(void *device_data);
+static void run_rawdata_stdev_read(void *device_data);
+static void run_rawdata_p2p_read_all(void *device_data);
+static void run_rawdata_read_type(void *device_data);
+static void run_rawdata_read_all(void *device_data);
+static void run_self_reference_read(void *device_data);
+static void run_self_reference_read_all(void *device_data);
+static void run_self_rawcap_read(void *device_data);
+static void run_self_rawcap_read_all(void *device_data);
+static void run_self_rawcap_gap_read_all(void *device_data);
+static void run_self_delta_read(void *device_data);
+static void run_self_delta_read_all(void *device_data);
+static void run_force_calibration(void *device_data);
+static void get_force_calibration(void *device_data);
+#ifdef USE_PRESSURE_SENSOR
+static void run_force_pressure_calibration(void *device_data);
+static void set_pressure_test_mode(void *device_data);
+static void run_pressure_filtered_strength_read_all(void *device_data);
+static void run_pressure_strength_read_all(void *device_data);
+static void run_pressure_rawdata_read_all(void *device_data);
+static void run_pressure_offset_read_all(void *device_data);
+static void set_pressure_strength(void *device_data);
+static void set_pressure_rawdata(void *device_data);
+static void set_pressure_data_index(void *device_data);
+static void get_pressure_strength(void *device_data);
+static void get_pressure_rawdata(void *device_data);
+static void get_pressure_data_index(void *device_data);
+static void set_pressure_strength_clear(void *device_data);
+static void get_pressure_threshold(void *device_data);
+static void set_pressure_user_level(void *device_data);
+static void get_pressure_user_level(void *device_data);
+#endif
+#ifdef USE_STIM_PAD
+static void run_fs_cal_pre_press(void *device_data);
+static void run_fs_cal_get_data(void *device_data);
+static void run_fs_cal_post_press(void *device_data);
+static void enable_fs_cal_table(void *device_data);
+static void enable_gain_limit(void *device_data);
+#endif
+static void enable_coordinate_report(void *device_data);
+static void run_trx_short_test(void *device_data);
+static void set_tsp_test_result(void *device_data);
+static void get_tsp_test_result(void *device_data);
+static void increase_disassemble_count(void *device_data);
+static void get_disassemble_count(void *device_data);
+static void glove_mode(void *device_data);
+static void clear_cover_mode(void *device_data);
+static void dead_zone_enable(void *device_data);
+static void drawing_test_enable(void *device_data);
+static void set_lowpower_mode(void *device_data);
+static void set_wirelesscharger_mode(void *device_data);
+static void spay_enable(void *device_data);
+static void set_aod_rect(void *device_data);
+static void get_aod_rect(void *device_data);
+static void aod_enable(void *device_data);
+static void set_grip_data(void *device_data);
+static void dex_enable(void *device_data);
+static void brush_enable(void *device_data);
+static void force_touch_active(void *device_data);
+static void set_touchable_area(void *device_data);
+static void set_log_level(void *device_data);
+static void debug(void *device_data);
+static void set_touch_mode(void *device_data);
+static void not_support_cmd(void *device_data);
+static void set_palm_detection_enable(void *device_data);
+static void set_grip_detection_enable(void *device_data);
+static void set_wet_mode_enable(void *device_data);
+static void set_noise_mode_enable(void *device_data);
+static void set_continuous_report_enable(void *device_data);
+static void set_charger_nb_enable(void *device_data);
+static void set_print_format(void *device_data);
+static void run_cal_check(void *device_data);
+
+static struct sec_cmd sec_cmds[] = {
+	{SEC_CMD("fw_update", fw_update),},
+	{SEC_CMD("get_fw_ver_bin", get_fw_ver_bin),},
+	{SEC_CMD("get_fw_ver_ic", get_fw_ver_ic),},
+	{SEC_CMD("get_config_ver", get_config_ver),},
+#ifdef PAT_CONTROL
+	{SEC_CMD("get_pat_information", get_pat_information),},
+	{SEC_CMD("set_external_factory", set_external_factory),},
+#endif
+	{SEC_CMD("get_threshold", get_threshold),},
+	{SEC_CMD("module_off_master", module_off_master),},
+	{SEC_CMD("module_on_master", module_on_master),},
+	{SEC_CMD("get_chip_vendor", get_chip_vendor),},
+	{SEC_CMD("get_chip_name", get_chip_name),},
+	{SEC_CMD("set_mis_cal_spec", set_mis_cal_spec),},
+	{SEC_CMD("get_mis_cal_info", get_mis_cal_info),},
+	{SEC_CMD("get_wet_mode", get_wet_mode),},
+	{SEC_CMD("get_x_num", get_x_num),},
+	{SEC_CMD("get_y_num", get_y_num),},
+	{SEC_CMD("get_x_cross_routing", get_x_cross_routing),},
+	{SEC_CMD("get_y_cross_routing", get_y_cross_routing),},
+	{SEC_CMD("get_checksum_data", get_checksum_data),},
+	{SEC_CMD("run_reference_read", run_reference_read),},
+	{SEC_CMD("run_reference_read_all", run_reference_read_all),},
+	{SEC_CMD("get_reference", get_reference),},
+	{SEC_CMD("run_rawcap_read", run_rawcap_read),},
+	{SEC_CMD("run_rawcap_read_all", run_rawcap_read_all),},
+	{SEC_CMD("run_rawcap_combo_read_all", run_rawcap_combo_read_all),},
+	{SEC_CMD("run_rawcap_gap_combo_read_all", run_rawcap_gap_combo_read_all),},
+	{SEC_CMD("run_rawcap_factory_read_all",
+		 run_rawcap_factory_read_all),},
+	{SEC_CMD("get_rawcap", get_rawcap),},
+	{SEC_CMD("run_rawcap_gap_read_all", run_rawcap_gap_read_all),},
+	{SEC_CMD("run_delta_read", run_delta_read),},
+	{SEC_CMD("run_delta_read_all", run_delta_read_all),},
+	{SEC_CMD("get_delta", get_delta),},
+	{SEC_CMD("run_rawdata_stdev_read", run_rawdata_stdev_read),},
+	{SEC_CMD("run_rawdata_p2p_read_all", run_rawdata_p2p_read_all),},
+	{SEC_CMD("run_rawdata_read_type", run_rawdata_read_type),},
+	{SEC_CMD("run_rawdata_read_all", run_rawdata_read_all),},
+	{SEC_CMD("run_self_reference_read", run_self_reference_read),},
+	{SEC_CMD("run_self_reference_read_all", run_self_reference_read_all),},
+	{SEC_CMD("run_self_rawcap_read", run_self_rawcap_read),},
+	{SEC_CMD("run_self_rawcap_read_all", run_self_rawcap_read_all),},
+	{SEC_CMD("run_self_rawcap_gap_read_all",
+		 run_self_rawcap_gap_read_all),},
+	{SEC_CMD("run_rawcap_high_freq_read_all",
+		 run_rawcap_high_freq_read_all),},
+	{SEC_CMD("run_self_delta_read", run_self_delta_read),},
+	{SEC_CMD("run_self_delta_read_all", run_self_delta_read_all),},
+	{SEC_CMD("run_force_calibration", run_force_calibration),},
+	{SEC_CMD("get_force_calibration", get_force_calibration),},
+#ifdef USE_PRESSURE_SENSOR
+	{SEC_CMD("run_force_pressure_calibration",
+		 run_force_pressure_calibration),},
+	{SEC_CMD("set_pressure_test_mode", set_pressure_test_mode),},
+	{SEC_CMD("run_pressure_filtered_strength_read_all",
+		 run_pressure_filtered_strength_read_all),},
+	{SEC_CMD("run_pressure_strength_read_all",
+		 run_pressure_strength_read_all),},
+	{SEC_CMD("run_pressure_rawdata_read_all",
+		 run_pressure_rawdata_read_all),},
+	{SEC_CMD("run_pressure_offset_read_all",
+		 run_pressure_offset_read_all),},
+	{SEC_CMD("set_pressure_strength", set_pressure_strength),},
+	{SEC_CMD("set_pressure_rawdata", set_pressure_rawdata),},
+	{SEC_CMD("set_pressure_data_index", set_pressure_data_index),},
+	{SEC_CMD("get_pressure_strength", get_pressure_strength),},
+	{SEC_CMD("get_pressure_rawdata", get_pressure_rawdata),},
+	{SEC_CMD("get_pressure_data_index", get_pressure_data_index),},
+	{SEC_CMD("set_pressure_strength_clear", set_pressure_strength_clear),},
+	{SEC_CMD("get_pressure_threshold", get_pressure_threshold),},
+	{SEC_CMD("set_pressure_user_level", set_pressure_user_level),},
+	{SEC_CMD("get_pressure_user_level", get_pressure_user_level),},
+#endif
+#ifdef USE_STIM_PAD
+	{SEC_CMD("run_fs_cal_pre_press", run_fs_cal_pre_press),},
+	{SEC_CMD("run_fs_cal_get_data", run_fs_cal_get_data),},
+	{SEC_CMD("run_fs_cal_post_press", run_fs_cal_post_press),},
+	{SEC_CMD("enable_fs_cal_table", enable_fs_cal_table),},
+	{SEC_CMD("enable_gain_limit", enable_gain_limit),},
+#endif
+	{SEC_CMD("enable_coordinate_report", enable_coordinate_report),},
+	{SEC_CMD("run_trx_short_test", run_trx_short_test),},
+	{SEC_CMD("set_tsp_test_result", set_tsp_test_result),},
+	{SEC_CMD("get_tsp_test_result", get_tsp_test_result),},
+	{SEC_CMD("increase_disassemble_count", increase_disassemble_count),},
+	{SEC_CMD("get_disassemble_count", get_disassemble_count),},
+	{SEC_CMD("glove_mode", glove_mode),},
+	{SEC_CMD("clear_cover_mode", clear_cover_mode),},
+	{SEC_CMD("dead_zone_enable", dead_zone_enable),},
+	{SEC_CMD("drawing_test_enable", drawing_test_enable),},
+	{SEC_CMD("set_lowpower_mode", set_lowpower_mode),},
+	{SEC_CMD("set_wirelesscharger_mode", set_wirelesscharger_mode),},
+	{SEC_CMD("spay_enable", spay_enable),},
+	{SEC_CMD("set_aod_rect", set_aod_rect),},
+	{SEC_CMD("get_aod_rect", get_aod_rect),},
+	{SEC_CMD("aod_enable", aod_enable),},
+	{SEC_CMD("set_grip_data", set_grip_data),},
+	{SEC_CMD("dex_enable", dex_enable),},
+	{SEC_CMD("brush_enable", brush_enable),},
+	{SEC_CMD("force_touch_active", force_touch_active),},
+	{SEC_CMD("set_touchable_area", set_touchable_area),},
+	{SEC_CMD("set_log_level", set_log_level),},
+	{SEC_CMD("debug", debug),},
+	{SEC_CMD("set_touch_mode", set_touch_mode),},
+	{SEC_CMD("set_palm_detection_enable", set_palm_detection_enable),},
+	{SEC_CMD("set_grip_detection_enable", set_grip_detection_enable),},
+	{SEC_CMD("set_wet_mode_enable", set_wet_mode_enable),},
+	{SEC_CMD("set_noise_mode_enable", set_noise_mode_enable),},
+	{SEC_CMD("set_continuous_report_enable",
+		set_continuous_report_enable),},
+	{SEC_CMD("set_charger_nb_enable", set_charger_nb_enable),},
+	{SEC_CMD("set_print_format", set_print_format),},
+	{SEC_CMD("run_cal_check", run_cal_check),},
+	{SEC_CMD("not_support_cmd", not_support_cmd),},
+};
+
+static void set_palm_detection_enable(void *device_data)
+{
+	struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data;
+	struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
+	char buff[4] = { 0 };
+	u8 para = 0x0;
+	int ret;
+
+	input_info(true, &ts->client->dev,
+		"%s: %d\n", __func__, sec->cmd_param[0]);
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, true);
+	sec_cmd_set_default_result(sec);
+
+	if (sec->cmd_param[0] == 1)
+		para = 0x1;
+	else if (sec->cmd_param[0] == 0)
+		para = 0x0;
+	else {
+		input_info(true, &ts->client->dev,
+			"%s: param error! param = %d\n",
+			__func__, sec->cmd_param[0]);
+		goto err_out;
+	}
+
+	ret = ts->sec_ts_write(ts, SEC_TS_CMD_SET_PALM_DETEC, &para, 1);
+	if (ret < 0) {
+		input_err(true, &ts->client->dev,
+			 "%s: write reg %#x para %#x failed, returned %i\n",
+			__func__, SEC_TS_CMD_SET_PALM_DETEC, para, ret);
+		goto err_out;
+	}
+
+	scnprintf(buff, sizeof(buff), "%s", "OK");
+	sec->cmd_state = SEC_CMD_STATUS_OK;
+	sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+	return;
+
+err_out:
+	scnprintf(buff, sizeof(buff), "%s", "NG");
+	sec->cmd_state = SEC_CMD_STATUS_FAIL;
+	sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+}
+
+static void set_grip_detection_enable(void *device_data)
+{
+	struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data;
+	struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
+	char buff[4] = { 0 };
+	u8 para = 0x0;
+	int ret;
+
+	input_info(true, &ts->client->dev,
+		"%s: %d\n", __func__, sec->cmd_param[0]);
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, true);
+	sec_cmd_set_default_result(sec);
+
+	if (sec->cmd_param[0] == 1)
+		para = 0x1F;
+	else if (sec->cmd_param[0] == 0)
+		para = 0x0;
+	else {
+		input_info(true, &ts->client->dev,
+			"%s: param error! param = %d\n",
+			__func__, sec->cmd_param[0]);
+		goto err_out;
+	}
+
+	ret = ts->sec_ts_write(ts, SEC_TS_CMD_SET_GRIP_DETEC, &para, 1);
+	if (ret < 0) {
+		input_err(true, &ts->client->dev,
+			 "%s: write reg %#x para %#x failed, returned %i\n",
+			__func__, SEC_TS_CMD_SET_GRIP_DETEC, para, ret);
+		goto err_out;
+	}
+
+	scnprintf(buff, sizeof(buff), "%s", "OK");
+	sec->cmd_state = SEC_CMD_STATUS_OK;
+	sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+	return;
+
+err_out:
+	scnprintf(buff, sizeof(buff), "%s", "NG");
+	sec->cmd_state = SEC_CMD_STATUS_FAIL;
+	sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+}
+
+static void set_wet_mode_enable(void *device_data)
+{
+	struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data;
+	struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
+	char buff[4] = { 0 };
+	u8 para = 0x0;
+	int ret;
+
+	input_info(true, &ts->client->dev,
+		"%s: %d\n", __func__, sec->cmd_param[0]);
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, true);
+	sec_cmd_set_default_result(sec);
+
+	if (sec->cmd_param[0] == 1)
+		para = 0x0;
+	else if (sec->cmd_param[0] == 0)
+		para = 0x1;
+	else {
+		input_info(true, &ts->client->dev,
+			"%s: param error! param = %d\n",
+			__func__, sec->cmd_param[0]);
+		goto err_out;
+	}
+
+	ret = ts->sec_ts_write(ts, SEC_TS_CMD_SET_WET_MODE, &para, 1);
+	if (ret < 0) {
+		input_err(true, &ts->client->dev,
+			 "%s: write reg %#x para %#x failed, returned %i\n",
+			__func__, SEC_TS_CMD_SET_WET_MODE, para, ret);
+		goto err_out;
+	}
+
+	scnprintf(buff, sizeof(buff), "%s", "OK");
+	sec->cmd_state = SEC_CMD_STATUS_OK;
+	sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+	return;
+
+err_out:
+	scnprintf(buff, sizeof(buff), "%s", "NG");
+	sec->cmd_state = SEC_CMD_STATUS_FAIL;
+	sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+}
+
+static void set_noise_mode_enable(void *device_data)
+{
+	struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data;
+	struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
+	char buff[4] = { 0 };
+	u8 para = 0x0;
+	int ret;
+
+	input_info(true, &ts->client->dev,
+		"%s: %d\n", __func__, sec->cmd_param[0]);
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, true);
+	sec_cmd_set_default_result(sec);
+
+	if (sec->cmd_param[0] == 1)
+		para = NOISE_MODE_DEFALUT;
+	else if (sec->cmd_param[0] == 0)
+		para = NOISE_MODE_OFF;
+	else {
+		input_info(true, &ts->client->dev,
+			"%s: param error! param = %d\n",
+			__func__, sec->cmd_param[0]);
+		goto err_out;
+	}
+
+	ret = ts->sec_ts_write(ts, SEC_TS_CMD_SET_NOISE_MODE, &para, 1);
+	if (ret < 0) {
+		input_err(true, &ts->client->dev,
+			 "%s: write reg %#x para %#x failed, returned %i\n",
+			__func__, SEC_TS_CMD_SET_NOISE_MODE, para, ret);
+		goto err_out;
+	}
+
+	scnprintf(buff, sizeof(buff), "%s", "OK");
+	sec->cmd_state = SEC_CMD_STATUS_OK;
+	sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+	return;
+
+err_out:
+	scnprintf(buff, sizeof(buff), "%s", "NG");
+	sec->cmd_state = SEC_CMD_STATUS_FAIL;
+	sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+}
+
+static void set_continuous_report_enable(void *device_data)
+{
+	struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data;
+	struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
+	char buff[4] = { 0 };
+	u8 para = 0x0;
+	int ret;
+
+	input_info(true, &ts->client->dev,
+		"%s: %d\n", __func__, sec->cmd_param[0]);
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, true);
+	sec_cmd_set_default_result(sec);
+
+	if (sec->cmd_param[0] == 1)
+		para = 0x1;
+	else if (sec->cmd_param[0] == 0)
+		para = 0x0;
+	else {
+		input_info(true, &ts->client->dev,
+			"%s: param error! param = %d\n",
+			__func__, sec->cmd_param[0]);
+		goto err_out;
+	}
+
+	ret = ts->sec_ts_write(ts, SEC_TS_CMD_SET_CONT_REPORT, &para, 1);
+	if (ret < 0) {
+		input_err(true, &ts->client->dev,
+			 "%s: write reg %#x para %#x failed, returned %i\n",
+			__func__, SEC_TS_CMD_SET_CONT_REPORT, para, ret);
+		goto err_out;
+	}
+
+	ts->use_default_mf = para;
+	scnprintf(buff, sizeof(buff), "%s", "OK");
+	sec->cmd_state = SEC_CMD_STATUS_OK;
+	sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+	return;
+
+err_out:
+	scnprintf(buff, sizeof(buff), "%s", "NG");
+	sec->cmd_state = SEC_CMD_STATUS_FAIL;
+	sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+}
+
+static void set_charger_nb_enable(void *device_data)
+{
+	struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data;
+	struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
+	char buff[4] = { 0 };
+
+	input_info(true, &ts->client->dev,
+		"%s: %d\n", __func__, sec->cmd_param[0]);
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, true);
+	sec_cmd_set_default_result(sec);
+
+	if (sec->cmd_param[0] == 1)
+		ts->ignore_charger_nb = 0;
+	else if (sec->cmd_param[0] == 0)
+		ts->ignore_charger_nb = 1;
+	else {
+		input_info(true, &ts->client->dev,
+			"%s: param error! param = %d\n",
+			__func__, sec->cmd_param[0]);
+		goto err_out;
+	}
+
+	scnprintf(buff, sizeof(buff), "%s", "OK");
+	sec->cmd_state = SEC_CMD_STATUS_OK;
+	sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+	return;
+
+err_out:
+	scnprintf(buff, sizeof(buff), "%s", "NG");
+	sec->cmd_state = SEC_CMD_STATUS_FAIL;
+	sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+}
+
+static ssize_t scrub_pos_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct sec_cmd_data *sec = dev_get_drvdata(dev);
+	struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
+	char buff[256] = { 0 };
+
+#ifdef CONFIG_SAMSUNG_PRODUCT_SHIP
+	input_info(true, &ts->client->dev,
+			"%s: scrub_id: %d\n", __func__, ts->scrub_id);
+#else
+	input_info(true, &ts->client->dev,
+			"%s: scrub_id: %d, X: %d, Y: %d\n", __func__,
+			ts->scrub_id, ts->scrub_x, ts->scrub_y);
+#endif
+	snprintf(buff, sizeof(buff), "%d %d %d",
+		 ts->scrub_id, ts->scrub_x, ts->scrub_y);
+
+	ts->scrub_x = 0;
+	ts->scrub_y = 0;
+
+	return snprintf(buf, PAGE_SIZE, "%s", buff);
+}
+
+static DEVICE_ATTR_RO(scrub_pos);
+
+static ssize_t ito_check_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct sec_cmd_data *sec = dev_get_drvdata(dev);
+	struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
+	char buff[256] = { 0 };
+
+	input_info(true, &ts->client->dev, "%s: %02X%02X%02X%02X\n", __func__,
+		ts->ito_test[0], ts->ito_test[1],
+		ts->ito_test[2], ts->ito_test[3]);
+
+	snprintf(buff, sizeof(buff), "%02X%02X%02X%02X",
+		ts->ito_test[0], ts->ito_test[1],
+		ts->ito_test[2], ts->ito_test[3]);
+
+	return snprintf(buf, SEC_CMD_BUF_SIZE, "%s", buff);
+}
+
+static ssize_t raw_check_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct sec_cmd_data *sec = dev_get_drvdata(dev);
+	struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
+	int ii, ret = 0;
+	char *buffer = NULL;
+	char temp[CMD_RESULT_WORD_LEN] = { 0 };
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, true);
+
+	buffer = vzalloc(ts->rx_count * ts->tx_count * 6);
+	if (!buffer) {
+		sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+		return -ENOMEM;
+	}
+
+	memset(buffer, 0x00, ts->rx_count * ts->tx_count * 6);
+
+	for (ii = 0; ii < (ts->rx_count * ts->tx_count - 1); ii++) {
+		snprintf(temp, CMD_RESULT_WORD_LEN, "%d ", ts->pFrame[ii]);
+		strncat(buffer, temp, CMD_RESULT_WORD_LEN);
+
+		memset(temp, 0x00, CMD_RESULT_WORD_LEN);
+	}
+
+	snprintf(temp, CMD_RESULT_WORD_LEN, "%d", ts->pFrame[ii]);
+	strncat(buffer, temp, CMD_RESULT_WORD_LEN);
+
+	ret = snprintf(buf, ts->rx_count * ts->tx_count * 6, buffer);
+	vfree(buffer);
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+	return ret;
+}
+
+static ssize_t multi_count_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct sec_cmd_data *sec = dev_get_drvdata(dev);
+	struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
+
+	input_info(true, &ts->client->dev, "%s: %d\n", __func__,
+		ts->multi_count);
+
+	return snprintf(buf, SEC_CMD_BUF_SIZE, "%d", ts->multi_count);
+}
+
+static ssize_t multi_count_store(struct device *dev,
+				    struct device_attribute *attr,
+				    const char *buf, size_t count)
+{
+	struct sec_cmd_data *sec = dev_get_drvdata(dev);
+	struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
+
+	ts->multi_count = 0;
+
+	input_info(true, &ts->client->dev, "%s: clear\n", __func__);
+
+	return count;
+}
+
+static ssize_t wet_mode_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct sec_cmd_data *sec = dev_get_drvdata(dev);
+	struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
+
+	input_info(true, &ts->client->dev, "%s: %d, %d\n", __func__,
+		ts->wet_count, ts->dive_count);
+
+	return snprintf(buf, SEC_CMD_BUF_SIZE, "%d", ts->wet_count);
+}
+
+static ssize_t wet_mode_store(struct device *dev,
+				    struct device_attribute *attr,
+				    const char *buf, size_t count)
+{
+	struct sec_cmd_data *sec = dev_get_drvdata(dev);
+	struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
+
+	ts->wet_count = 0;
+	ts->dive_count = 0;
+
+	input_info(true, &ts->client->dev, "%s: clear\n", __func__);
+
+	return count;
+}
+
+static ssize_t comm_err_count_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct sec_cmd_data *sec = dev_get_drvdata(dev);
+	struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
+
+	input_info(true, &ts->client->dev, "%s: %d\n", __func__,
+		ts->multi_count);
+
+	return snprintf(buf, SEC_CMD_BUF_SIZE, "%d", ts->comm_err_count);
+}
+
+static ssize_t comm_err_count_store(struct device *dev,
+				    struct device_attribute *attr,
+				    const char *buf, size_t count)
+{
+	struct sec_cmd_data *sec = dev_get_drvdata(dev);
+	struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
+
+	ts->comm_err_count = 0;
+
+	input_info(true, &ts->client->dev, "%s: clear\n", __func__);
+
+	return count;
+}
+
+static ssize_t module_id_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct sec_cmd_data *sec = dev_get_drvdata(dev);
+	struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
+	char buff[256] = { 0 };
+
+	input_info(true, &ts->client->dev, "%s: %d\n", __func__,
+		ts->multi_count);
+
+	snprintf(buff, sizeof(buff), "SE%02X%02X%02X%02X%02X%02X%02X",
+		ts->plat_data->panel_revision,
+		ts->plat_data->img_version_of_bin[2],
+		ts->plat_data->img_version_of_bin[3], ts->nv, ts->cal_count,
+		ts->pressure_cal_base, ts->pressure_cal_delta);
+
+	return snprintf(buf, SEC_CMD_BUF_SIZE, "%s", buff);
+}
+
+static ssize_t vendor_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct sec_cmd_data *sec = dev_get_drvdata(dev);
+	struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
+	unsigned char buffer[10] = { 0 };
+
+	snprintf(buffer, 5, ts->plat_data->firmware_name + 8);
+
+	return snprintf(buf, SEC_CMD_BUF_SIZE, "LSI_%s", buffer);
+}
+
+static ssize_t checksum_store(struct device *dev,
+				    struct device_attribute *attr,
+				    const char *buf, size_t count)
+{
+	struct sec_cmd_data *sec = dev_get_drvdata(dev);
+	struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
+
+	ts->checksum_result = 0;
+
+	input_info(true, &ts->client->dev, "%s: clear\n", __func__);
+
+	return count;
+}
+
+static ssize_t checksum_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct sec_cmd_data *sec = dev_get_drvdata(dev);
+	struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
+
+	input_info(true, &ts->client->dev, "%s: %d\n", __func__,
+		ts->checksum_result);
+
+	return snprintf(buf, SEC_CMD_BUF_SIZE, "%d", ts->checksum_result);
+}
+
+static ssize_t holding_time_store(struct device *dev,
+				    struct device_attribute *attr,
+				    const char *buf, size_t count)
+{
+	struct sec_cmd_data *sec = dev_get_drvdata(dev);
+	struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
+
+	ts->longest_duration = 0;
+
+	input_info(true, &ts->client->dev, "%s: clear\n", __func__);
+
+	return count;
+}
+
+static ssize_t holding_time_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct sec_cmd_data *sec = dev_get_drvdata(dev);
+	struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
+
+	input_info(true, &ts->client->dev, "%s: %lld ms\n",
+		__func__, ts->longest_duration);
+
+	return snprintf(buf, SEC_CMD_BUF_SIZE, "%lld ms", ts->longest_duration);
+}
+
+static ssize_t all_touch_count_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct sec_cmd_data *sec = dev_get_drvdata(dev);
+	struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
+
+	input_info(true, &ts->client->dev,
+		"%s: touch: %d, force: %d, aod: %d, spay: %d\n", __func__,
+		ts->all_finger_count, ts->all_force_count,
+		ts->all_aod_tap_count, ts->all_spay_count);
+
+	return snprintf(buf, SEC_CMD_BUF_SIZE,
+			"\"TTCN\":\"%d\",\"TFCN\":\"%d\",\"TACN\":\"%d\",\"TSCN\":\"%d\"",
+			ts->all_finger_count, ts->all_force_count,
+			ts->all_aod_tap_count, ts->all_spay_count);
+}
+
+static ssize_t all_touch_count_store(struct device *dev,
+				    struct device_attribute *attr,
+				    const char *buf, size_t count)
+{
+	struct sec_cmd_data *sec = dev_get_drvdata(dev);
+	struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
+
+	ts->all_force_count = 0;
+	ts->all_aod_tap_count = 0;
+	ts->all_spay_count = 0;
+
+	input_info(true, &ts->client->dev, "%s: clear\n", __func__);
+
+	return count;
+}
+
+static ssize_t z_value_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct sec_cmd_data *sec = dev_get_drvdata(dev);
+	struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
+
+	input_info(true, &ts->client->dev, "%s: max: %d, min: %d, avg: %d\n",
+		   __func__, ts->max_z_value, ts->min_z_value, ts->sum_z_value);
+
+	if (ts->all_finger_count)
+		return snprintf(buf, SEC_CMD_BUF_SIZE,
+				"\"TMXZ\":\"%d\",\"TMNZ\":\"%d\",\"TAVZ\":\"%d\"",
+				ts->max_z_value, ts->min_z_value,
+				ts->sum_z_value / ts->all_finger_count);
+	else
+		return snprintf(buf, SEC_CMD_BUF_SIZE,
+				"\"TMXZ\":\"%d\",\"TMNZ\":\"%d\"",
+				ts->max_z_value, ts->min_z_value);
+
+}
+
+static ssize_t z_value_store(struct device *dev,
+				    struct device_attribute *attr,
+				    const char *buf, size_t count)
+{
+	struct sec_cmd_data *sec = dev_get_drvdata(dev);
+	struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
+
+	ts->max_z_value = 0;
+	ts->min_z_value = 0xFFFFFFFF;
+	ts->sum_z_value = 0;
+	ts->all_finger_count = 0;
+
+	input_info(true, &ts->client->dev, "%s: clear\n", __func__);
+
+	return count;
+}
+
+static ssize_t pressure_enable_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct sec_cmd_data *sec = dev_get_drvdata(dev);
+	struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
+	char buff[256] = { 0 };
+
+	if (ts->lowpower_mode & SEC_TS_MODE_CUSTOMLIB_FORCE_KEY)
+		snprintf(buff, sizeof(buff), "1");
+	else
+		snprintf(buff, sizeof(buff), "0");
+
+	return snprintf(buf, SEC_CMD_BUF_SIZE, "%s\n", buff);
+}
+
+static ssize_t pressure_enable_store(struct device *dev,
+				    struct device_attribute *attr,
+				    const char *buf, size_t count)
+{
+	struct sec_cmd_data *sec = dev_get_drvdata(dev);
+	struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
+	int ret;
+	unsigned long value = 0;
+
+	if (count > 2)
+		return -EINVAL;
+
+	ret = kstrtoul(buf, 10, &value);
+	if (ret != 0)
+		return ret;
+
+	if (!ts->use_customlib)
+		return -EINVAL;
+
+	if (value == 1)
+		ts->lowpower_mode |= SEC_TS_MODE_CUSTOMLIB_FORCE_KEY;
+	else
+		ts->lowpower_mode &= ~SEC_TS_MODE_CUSTOMLIB_FORCE_KEY;
+
+	#ifdef SEC_TS_SUPPORT_CUSTOMLIB
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, true);
+	sec_ts_set_custom_library(ts);
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+	#endif
+
+	return count;
+}
+
+static ssize_t get_lp_dump_show(struct device *dev,
+				struct device_attribute *attr,
+				char *buf)
+{
+	struct sec_cmd_data *sec = dev_get_drvdata(dev);
+	struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
+	u8 string_data[8] = {0, };
+	u16 current_index;
+	int i, ret;
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, true);
+
+	if (ts->power_status == SEC_TS_STATE_POWER_OFF) {
+		input_err(true, &ts->client->dev, "%s: Touch is stopped!\n",
+			  __func__);
+		sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+		return snprintf(buf, SEC_CMD_BUF_SIZE, "TSP turned off");
+	}
+
+	string_data[0] = SEC_TS_CMD_CUSTOMLIB_LP_DUMP & 0xFF;
+	string_data[1] = (SEC_TS_CMD_CUSTOMLIB_LP_DUMP & 0xFF00) >> 8;
+
+	disable_irq(ts->client->irq);
+
+	ret = ts->sec_ts_read_customlib(ts, string_data, 2);
+	if (ret < 0) {
+		input_err(true, &ts->client->dev, "%s: Failed to read rect\n",
+			  __func__);
+		snprintf(buf, SEC_CMD_BUF_SIZE, "NG, Failed to read rect");
+		goto out;
+	}
+
+	current_index = (string_data[1] & 0xFF) << 8 | (string_data[0] & 0xFF);
+	if (current_index > 1000 || current_index < 500) {
+		input_err(true, &ts->client->dev,
+			"Failed to Custom Library LP log %d\n", current_index);
+		snprintf(buf, SEC_CMD_BUF_SIZE,
+			"NG, Failed to Custom Library LP log, current_index=%d",
+			current_index);
+		goto out;
+	}
+
+	input_info(true, &ts->client->dev,
+		"%s: DEBUG current_index = %d\n", __func__, current_index);
+
+	/* Custom Library has 62 stacks for LP dump */
+	for (i = 61; i >= 0; i--) {
+		u16 data0, data1, data2, data3;
+		char buff[30] = {0, };
+		u16 string_addr;
+
+		string_addr = current_index - (8 * i);
+		if (string_addr < 500)
+			string_addr += SEC_TS_CMD_CUSTOMLIB_LP_DUMP;
+		string_data[0] = string_addr & 0xFF;
+		string_data[1] = (string_addr & 0xFF00) >> 8;
+
+		ret = ts->sec_ts_read_customlib(ts, string_data, 8);
+		if (ret < 0) {
+			input_err(true, &ts->client->dev,
+					"%s: Failed to read rect\n", __func__);
+			snprintf(buf, SEC_CMD_BUF_SIZE,
+					"NG, Failed to read rect, addr=%d",
+					string_addr);
+			goto out;
+		}
+
+		data0 = (string_data[1] & 0xFF) << 8 | (string_data[0] & 0xFF);
+		data1 = (string_data[3] & 0xFF) << 8 | (string_data[2] & 0xFF);
+		data2 = (string_data[5] & 0xFF) << 8 | (string_data[4] & 0xFF);
+		data3 = (string_data[7] & 0xFF) << 8 | (string_data[6] & 0xFF);
+		if (data0 || data1 || data2 || data3) {
+			snprintf(buff, sizeof(buff),
+				"%d: %04x%04x%04x%04x\n",
+				string_addr, data0, data1, data2, data3);
+			strncat(buf, buff, SEC_CMD_BUF_SIZE);
+		}
+	}
+
+out:
+	enable_irq(ts->client->irq);
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+	return strlen(buf);
+}
+
+static ssize_t force_recal_count_show(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	struct sec_cmd_data *sec = dev_get_drvdata(dev);
+	struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
+	u8 rbuf[4] = {0, };
+	u32 recal_count;
+	int ret;
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, true);
+
+	if (ts->power_status == SEC_TS_STATE_POWER_OFF) {
+		input_err(true, &ts->client->dev,
+			  "%s: Touch is stopped!\n", __func__);
+		sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+		return snprintf(buf, SEC_CMD_BUF_SIZE, "%d", -ENODEV);
+	}
+
+	ret = ts->sec_ts_read(ts, SEC_TS_READ_FORCE_RECAL_COUNT, rbuf, 4);
+	if (ret < 0) {
+		input_err(true, &ts->client->dev,
+				"%s: Failed to read\n", __func__);
+		sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+		return snprintf(buf, SEC_CMD_BUF_SIZE, "%d", -EIO);
+	}
+
+	recal_count = (rbuf[0] & 0xFF) << 24 | (rbuf[1] & 0xFF) << 16 |
+			(rbuf[2] & 0xFF) << 8 | (rbuf[3] & 0xFF);
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+	return snprintf(buf, SEC_CMD_BUF_SIZE, "%d", recal_count);
+}
+
+
+/* sysfs file node to store heatmap mode
+ * "echo cmd > heatmap_mode" to change
+ * Possible commands:
+ * 0 = HEATMAP_OFF
+ * 1 = HEATMAP_PARTIAL
+ * 2 = HEATMAP_FULL
+ */
+static ssize_t heatmap_mode_store(struct device *dev,
+				struct device_attribute *attr,
+				const char *buf, size_t count)
+{
+#if IS_ENABLED(CONFIG_TOUCHSCREEN_HEATMAP)
+	struct sec_cmd_data *sec = dev_get_drvdata(dev);
+	struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
+	struct sec_ts_plat_data *pdata = ts->plat_data;
+	int result;
+	int val;
+	u8 config;
+
+	result = kstrtoint(buf, 10, &val);
+	if (result < 0 || val < HEATMAP_OFF || val > HEATMAP_FULL) {
+		input_err(true, &ts->client->dev,
+			"%s: Invalid input.\n", __func__);
+		return -EINVAL;
+	}
+
+	pdata->heatmap_mode = val;
+
+	/* reset all heatmap settings when any change */
+	config = 0;
+	result = ts->sec_ts_write(ts,
+			SEC_TS_CMD_HEATMAP_ENABLE, &config, 1);
+	if (result < 0)
+		input_err(true, &ts->client->dev,
+			 "%s: write reg %#x failed, returned %i\n",
+			__func__, SEC_TS_CMD_HEATMAP_ENABLE, result);
+	config = TYPE_INVALID_DATA;
+	result = ts->sec_ts_write(ts,
+			SEC_TS_CMD_MUTU_RAW_TYPE, &config, 1);
+	if (result < 0)
+		input_err(true, &ts->client->dev,
+			 "%s: write reg %#x failed, returned %i\n",
+			__func__, SEC_TS_CMD_MUTU_RAW_TYPE, result);
+
+	return count;
+#else
+	return 0;
+#endif
+}
+
+static ssize_t heatmap_mode_show(struct device *dev,
+			       struct device_attribute *attr, char *buf)
+{
+#if IS_ENABLED(CONFIG_TOUCHSCREEN_HEATMAP)
+	struct sec_cmd_data *sec = dev_get_drvdata(dev);
+	struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
+	const struct sec_ts_plat_data *pdata = ts->plat_data;
+
+	return scnprintf(buf, PAGE_SIZE, "%d\n",
+			 pdata->heatmap_mode);
+#else
+	return scnprintf(buf, PAGE_SIZE, "N/A\n");
+#endif
+}
+
+/* sysfs file node to store grip prescreen mode
+ * "echo cmd > grip_prescreen_mode" to change
+ * Possible commands:
+ * 0 = GRIP_PRESCREEN_OFF
+ * 1 = GRIP_PRESCREEN_MODE_1
+ * 2 = GRIP_PRESCREEN_MODE_2
+ * 3 = GRIP_PRESCREEN_MODE_3
+ */
+static ssize_t grip_prescreen_mode_store(struct device *dev,
+					 struct device_attribute *attr,
+					 const char *buf, size_t count)
+{
+	struct sec_cmd_data *sec = dev_get_drvdata(dev);
+	struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
+	struct sec_ts_plat_data *pdata = ts->plat_data;
+	int result;
+	int val;
+
+	result = kstrtoint(buf, 10, &val);
+	if (result < 0 || val < GRIP_PRESCREEN_OFF ||
+	    val > GRIP_PRESCREEN_MODE_3) {
+		input_err(true, &ts->client->dev,
+			"%s: Invalid input.\n", __func__);
+		return -EINVAL;
+	}
+
+	pdata->grip_prescreen_mode = val;
+
+	return count;
+}
+
+static ssize_t grip_prescreen_mode_show(struct device *dev,
+				        struct device_attribute *attr,
+				        char *buf)
+{
+	struct sec_cmd_data *sec = dev_get_drvdata(dev);
+	struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
+	const struct sec_ts_plat_data *pdata = ts->plat_data;
+
+	return scnprintf(buf, PAGE_SIZE, "%d\n",
+			 pdata->grip_prescreen_mode);
+}
+
+/* sysfs file node to store grip prescreen timeout
+ * "echo timeout > grip_prescreen_timeout" to change
+ * Possible timeout range:
+ *   GRIP_PRESCREEN_TIMEOUT_MIN ~ GRIP_PRESCREEN_TIMEOUT_MAX
+ */
+static ssize_t grip_prescreen_timeout_store(struct device *dev,
+					    struct device_attribute *attr,
+					    const char *buf, size_t count)
+{
+	struct sec_cmd_data *sec = dev_get_drvdata(dev);
+	struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
+	struct sec_ts_plat_data *pdata = ts->plat_data;
+	int result;
+	int val;
+
+	result = kstrtoint(buf, 10, &val);
+	if (result < 0 || val < GRIP_PRESCREEN_TIMEOUT_MIN ||
+	    val > GRIP_PRESCREEN_TIMEOUT_MAX) {
+		input_err(true, &ts->client->dev,
+			"%s: Invalid input.\n", __func__);
+		return -EINVAL;
+	}
+
+	pdata->grip_prescreen_timeout = val;
+
+	return count;
+}
+
+static ssize_t grip_prescreen_timeout_show(struct device *dev,
+					   struct device_attribute *attr,
+					   char *buf)
+{
+	struct sec_cmd_data *sec = dev_get_drvdata(dev);
+	struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
+	const struct sec_ts_plat_data *pdata = ts->plat_data;
+
+	return scnprintf(buf, PAGE_SIZE, "%d\n",
+			 pdata->grip_prescreen_timeout);
+}
+
+/* sysfs file node to store encoded_enable control
+ * "echo cmd > encoded_enable" to change
+ * Possible commands:
+ * 0 = ENCODED_ENABLE_OFF
+ * 1 = ENCODED_ENABLE_ON
+ */
+static ssize_t encoded_enable_store(struct device *dev,
+				    struct device_attribute *attr,
+				    const char *buf, size_t count)
+{
+#if IS_ENABLED(CONFIG_TOUCHSCREEN_HEATMAP)
+	struct sec_cmd_data *sec = dev_get_drvdata(dev);
+	struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
+	struct sec_ts_plat_data *pdata = ts->plat_data;
+	int result;
+	int val;
+
+	result = kstrtoint(buf, 10, &val);
+	if (result < 0 || val < ENCODED_ENABLE_OFF ||
+	    val > ENCODED_ENABLE_ON) {
+		input_err(true, &ts->client->dev,
+			"%s: Invalid input.\n", __func__);
+		return -EINVAL;
+	}
+	pdata->encoded_enable = val;
+
+	return count;
+#else
+	return 0;
+#endif
+}
+
+static ssize_t encoded_enable_show(struct device *dev,
+				   struct device_attribute *attr,
+				   char *buf)
+{
+#if IS_ENABLED(CONFIG_TOUCHSCREEN_HEATMAP)
+	struct sec_cmd_data *sec = dev_get_drvdata(dev);
+	struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
+	const struct sec_ts_plat_data *pdata = ts->plat_data;
+
+	return scnprintf(buf, PAGE_SIZE, "%d\n", pdata->encoded_enable);
+#else
+	return scnprintf(buf, PAGE_SIZE, "N/A\n");
+#endif
+}
+
+
+/* sysfs file node to dump heatmap
+ * "echo cmd > heatmap_dump" to change
+ * Possible commands:
+ * 0 = disable
+ * 1 = enable
+ */
+static ssize_t heatmap_dump_store(struct device *dev,
+				struct device_attribute *attr,
+				const char *buf, size_t count)
+{
+#if IS_ENABLED(CONFIG_TOUCHSCREEN_HEATMAP)
+	struct sec_cmd_data *sec = dev_get_drvdata(dev);
+	struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
+	int result;
+	int val;
+
+	result = kstrtoint(buf, 10, &val);
+	if (result < 0 || val < 0 || val > 1) {
+		input_err(true, &ts->client->dev,
+			"%s: Invalid input.\n", __func__);
+		return -EINVAL;
+	}
+	ts->heatmap_dump = val;
+	return count;
+#else
+	return 0;
+#endif
+}
+
+static ssize_t heatmap_dump_show(struct device *dev,
+			       struct device_attribute *attr, char *buf)
+{
+#if IS_ENABLED(CONFIG_TOUCHSCREEN_HEATMAP)
+	struct sec_cmd_data *sec = dev_get_drvdata(dev);
+	struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
+	struct sec_ts_plat_data *pdata = ts->plat_data;
+	int x, y, max_x, max_y, index = 0;
+
+	index += scnprintf(buf + index, PAGE_SIZE - index,
+			"heatmap dump(mode %d) %s\n",
+			pdata->heatmap_mode,
+			(ts->heatmap_dump) ? "ENABLE" : "DISABLE");
+
+	if (!ts->heatmap_dump)
+		return index;
+
+	max_x = ts->tx_count;
+	max_y = ts->rx_count;
+
+	for (y = 0 ; y < max_y ; y++) {
+		for (x = 0 ; x < max_x ; x++) {
+			index += scnprintf(buf + index,
+				PAGE_SIZE - index,
+				" %3d,",
+				ts->v4l2.frame[y * max_x  + x]);
+			if (x == max_x - 1)
+				index += scnprintf(buf + index,
+					PAGE_SIZE - index, "\n");
+		}
+	}
+
+	return index;
+#else
+	return scnprintf(buf, PAGE_SIZE, "N/A\n");
+#endif
+}
+
+static ssize_t fw_version_show(struct device *dev,
+			       struct device_attribute *attr, char *buf)
+{
+	struct sec_cmd_data *sec = dev_get_drvdata(dev);
+	struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
+	int ret, written = 0;
+	u8 data[3];
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, true);
+	/* If there is no FW file avaiable,
+	 * sec_ts_save_version_of_ic() and sec_ts_save_version_of_bin() will
+	 * no be called. Need to get through SEC_TS_READ_IMG_VERSION cmd.
+	 */
+	if (ts->plat_data->panel_revision == 0 &&
+		ts->plat_data->img_version_of_bin[2] == 0 &&
+		ts->plat_data->img_version_of_bin[3] == 0) {
+		u8 fw_ver[4];
+
+		ret = ts->sec_ts_read(ts, SEC_TS_READ_IMG_VERSION, fw_ver, 4);
+		if (ret < 0) {
+			input_err(true, &ts->client->dev,
+				"%s: firmware version read error\n", __func__);
+			goto out;
+		}
+		written += scnprintf(buf + written, PAGE_SIZE - written,
+			"SE-V%02X.%02X.%02X\n",
+			ts->plat_data->panel_revision,
+			fw_ver[2],
+			fw_ver[3]);
+		written += scnprintf(buf + written, PAGE_SIZE - written,
+			"FW file: N/A\n");
+	} else {
+		written += scnprintf(buf + written, PAGE_SIZE - written,
+			"SE-V%02X.%02X.%02X\n",
+			ts->plat_data->panel_revision,
+			ts->plat_data->img_version_of_ic[2],
+			ts->plat_data->img_version_of_ic[3]);
+		written += scnprintf(buf + written, PAGE_SIZE - written,
+			"FW file: %s\n",
+			ts->plat_data->firmware_name);
+	}
+
+	written += scnprintf(buf + written, PAGE_SIZE - written,
+		"Cal: %02X %02X %02X %02X %02X %02X %02X %02X\n",
+		ts->cali_report[0], ts->cali_report[1], ts->cali_report[2],
+		ts->cali_report[3], ts->cali_report[4], ts->cali_report[5],
+		ts->cali_report[6], ts->cali_report[7]);
+
+	ret = ts->sec_ts_read(ts, SEC_TS_READ_ID, data, sizeof(data));
+	if (ret < 0) {
+		input_err(true, &ts->client->dev,
+					"%s: failed to read device id(%d)\n",
+					__func__, ret);
+		goto out;
+	}
+	written += scnprintf(buf + written, PAGE_SIZE - written,
+		"ID: %02X %02X %02X\n",
+		data[0], data[1], data[2]);
+out:
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+
+	return written;
+}
+
+static ssize_t status_show(struct device *dev,
+			       struct device_attribute *attr, char *buf)
+{
+	struct sec_cmd_data *sec = dev_get_drvdata(dev);
+	struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
+	int written = 0;
+	unsigned char data[4] = { 0 };
+	int ret;
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, true);
+
+	data[0] = 0;
+	ret = ts->sec_ts_read(ts, SEC_TS_READ_BOOT_STATUS, data, 1);
+	if (ret < 0) {
+		input_err(true, &ts->client->dev,
+					"%s: failed to read boot status(%d)\n",
+					__func__, ret);
+		goto out;
+	}
+	written += scnprintf(buf + written, PAGE_SIZE - written,
+			     "Boot status: %#x\n", data[0]);
+
+	memset(data, 0x0, 4);
+	ret = ts->sec_ts_read(ts, SEC_TS_READ_TS_STATUS, data, 4);
+	if (ret < 0) {
+		input_err(true, &ts->client->dev,
+					"%s: failed to touch status(%d)\n",
+					__func__, ret);
+		goto out;
+	}
+	written += scnprintf(buf + written, PAGE_SIZE - written,
+			     "Touch status: %#x, %#x, %#x, %#x\n",
+			     data[0], data[1], data[2], data[3]);
+
+	memset(data, 0x0, 2);
+	ret = ts->sec_ts_read(ts, SEC_TS_CMD_SET_TOUCHFUNCTION, data, 2);
+	if (ret < 0) {
+		input_err(true, &ts->client->dev,
+				"%s: failed to read touch functions(%d)\n",
+				__func__, ret);
+		goto out;
+	}
+	written += scnprintf(buf + written, PAGE_SIZE - written,
+			     "Functions: %#x, %#x\n", data[0], data[1]);
+	written += scnprintf(buf + written, PAGE_SIZE - written,
+			     "Charger mode: %#x\n", ts->charger_mode);
+	written += scnprintf(buf + written, PAGE_SIZE - written,
+			     "Wet mode: %d\n", ts->wet_mode);
+	written += scnprintf(buf + written, PAGE_SIZE - written,
+			     "Fingers#: %d\n", ts->touch_count);
+	written += scnprintf(buf + written, PAGE_SIZE - written,
+			     "Report rate: %d\n", ts->report_rate);
+	written += scnprintf(buf + written, PAGE_SIZE - written,
+			     "Vsync: %d\n", ts->vsync);
+out:
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+	return written;
+}
+
+static DEVICE_ATTR_RO(ito_check);
+static DEVICE_ATTR_RO(raw_check);
+static DEVICE_ATTR_RW(multi_count);
+static DEVICE_ATTR_RW(wet_mode);
+static DEVICE_ATTR_RW(comm_err_count);
+static DEVICE_ATTR_RW(checksum);
+static DEVICE_ATTR_RW(holding_time);
+static DEVICE_ATTR_RW(all_touch_count);
+static DEVICE_ATTR_RW(z_value);
+static DEVICE_ATTR_RO(module_id);
+static DEVICE_ATTR_RO(vendor);
+static DEVICE_ATTR_RW(pressure_enable);
+static DEVICE_ATTR_RO(get_lp_dump);
+static DEVICE_ATTR_RO(force_recal_count);
+static DEVICE_ATTR_RW(heatmap_mode);
+static DEVICE_ATTR_RW(grip_prescreen_mode);
+static DEVICE_ATTR_RW(grip_prescreen_timeout);
+static DEVICE_ATTR_RW(encoded_enable);
+static DEVICE_ATTR_RW(heatmap_dump);
+static DEVICE_ATTR_RO(fw_version);
+static DEVICE_ATTR_RO(status);
+
+
+static struct attribute *cmd_attributes[] = {
+	&dev_attr_scrub_pos.attr,
+	&dev_attr_ito_check.attr,
+	&dev_attr_raw_check.attr,
+	&dev_attr_multi_count.attr,
+	&dev_attr_wet_mode.attr,
+	&dev_attr_comm_err_count.attr,
+	&dev_attr_checksum.attr,
+	&dev_attr_holding_time.attr,
+	&dev_attr_all_touch_count.attr,
+	&dev_attr_z_value.attr,
+	&dev_attr_module_id.attr,
+	&dev_attr_vendor.attr,
+	&dev_attr_pressure_enable.attr,
+	&dev_attr_get_lp_dump.attr,
+	&dev_attr_force_recal_count.attr,
+	&dev_attr_heatmap_mode.attr,
+	&dev_attr_grip_prescreen_mode.attr,
+	&dev_attr_grip_prescreen_timeout.attr,
+	&dev_attr_encoded_enable.attr,
+	&dev_attr_heatmap_dump.attr,
+	&dev_attr_fw_version.attr,
+	&dev_attr_status.attr,
+	NULL,
+};
+
+static struct attribute_group cmd_attr_group = {
+	.attrs = cmd_attributes,
+};
+
+static int sec_ts_check_index(struct sec_ts_data *ts)
+{
+	struct sec_cmd_data *sec = &ts->sec;
+	char buff[SEC_CMD_STR_LEN] = { 0 };
+	int node;
+
+	if (sec->cmd_param[0] < 0 || sec->cmd_param[0] > ts->tx_count
+		|| sec->cmd_param[1] < 0 || sec->cmd_param[1] > ts->rx_count) {
+
+		snprintf(buff, sizeof(buff), "%s", "NG");
+		sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
+		sec->cmd_state = SEC_CMD_STATUS_FAIL;
+		input_info(true, &ts->client->dev,
+			   "%s: parameter error: %u, %u\n",
+			   __func__, sec->cmd_param[0], sec->cmd_param[0]);
+		node = -1;
+		return node;
+	}
+	node = sec->cmd_param[1] * ts->tx_count + sec->cmd_param[0];
+	input_info(true, &ts->client->dev, "%s: node = %d\n", __func__, node);
+
+	return node;
+}
+static void fw_update(void *device_data)
+{
+	struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data;
+	struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
+	char buff[64] = { 0 };
+	int retval = 0;
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, true);
+
+	sec_cmd_set_default_result(sec);
+	if (ts->power_status == SEC_TS_STATE_POWER_OFF) {
+		input_err(true, &ts->client->dev,
+			  "%s: [ERROR] Touch is stopped\n", __func__);
+		snprintf(buff, sizeof(buff), "%s", "TSP turned off");
+		sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
+		sec->cmd_state = SEC_CMD_STATUS_NOT_APPLICABLE;
+
+		sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+		return;
+	}
+
+	retval = sec_ts_firmware_update_on_hidden_menu(ts, sec->cmd_param[0]);
+	if (retval < 0) {
+		snprintf(buff, sizeof(buff), "%s", "NA");
+		sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
+		sec->cmd_state = SEC_CMD_STATUS_FAIL;
+		input_err(true, &ts->client->dev, "%s: failed [%d]\n",
+			  __func__, retval);
+	} else {
+		snprintf(buff, sizeof(buff), "%s", "OK");
+		sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
+		sec->cmd_state = SEC_CMD_STATUS_OK;
+		input_info(true, &ts->client->dev, "%s: success [%d]\n",
+			   __func__, retval);
+	}
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+}
+
+int sec_ts_fix_tmode(struct sec_ts_data *ts, u8 mode, u8 state)
+{
+	int ret;
+	u8 onoff[1] = {STATE_MANAGE_OFF};
+	u8 tBuff[2] = { mode, state };
+
+	input_info(true, &ts->client->dev, "%s: mode %d state %d\n",
+		__func__, mode, state);
+
+	ret = ts->sec_ts_write(ts, SEC_TS_CMD_STATEMANAGE_ON, onoff, 1);
+	if (ret < 0)
+		input_err(true, &ts->client->dev,
+			  "%s: write reg %#x failed, return %i\n",
+			  __func__, SEC_TS_CMD_STATEMANAGE_ON, ret);
+	sec_ts_delay(20);
+
+	ret = ts->sec_ts_write(ts, SEC_TS_CMD_CHG_SYSMODE, tBuff,
+			       sizeof(tBuff));
+	if (ret < 0)
+		input_err(true, &ts->client->dev,
+			  "%s: write reg %#x failed, return %i\n",
+			  __func__, SEC_TS_CMD_CHG_SYSMODE, ret);
+	sec_ts_delay(20);
+
+	return ret;
+}
+
+int sec_ts_release_tmode(struct sec_ts_data *ts)
+{
+	int ret;
+	u8 onoff[1] = {STATE_MANAGE_ON};
+
+	input_info(true, &ts->client->dev, "%s\n", __func__);
+
+	ret = ts->sec_ts_write(ts, SEC_TS_CMD_STATEMANAGE_ON, onoff, 1);
+	if (ret < 0)
+		input_err(true, &ts->client->dev,
+			  "%s: write reg %#x failed, return %i\n",
+			  __func__, SEC_TS_CMD_STATEMANAGE_ON, ret);
+	sec_ts_delay(20);
+
+	return ret;
+}
+
+/* sec_ts_cm_spec_over_check :
+ * apply gap calculation with ts->pFrameMS data
+ * gap = abs(N1 - N2) / MAX(N1, N2) * 100 (%)
+ */
+static int sec_ts_cm_spec_over_check(struct sec_ts_data *ts, short *gap,
+				     bool gap_dir)
+{
+	int i = 0;
+	int j = 0;
+	int gapx, gapy, pos1, pos2;
+	short dpos1, dpos2;
+	int specover_count = 0;
+
+	/* Get x-direction cm gap */
+	if (!gap_dir) {
+		input_dbg(true, &ts->client->dev, "gapX TX\n");
+
+		for (i = 0; i < ts->rx_count; i++) {
+			for (j = 0; j < ts->tx_count - 1; j++) {
+				/* Exclude last line to get gap between two
+				 * lines.
+				 */
+				pos1 = (i * ts->tx_count) + j;
+				pos2 = (i * ts->tx_count) + (j + 1);
+
+				dpos1 = ts->pFrameMS[pos1];
+				dpos2 = ts->pFrameMS[pos2];
+
+				if (dpos1 > dpos2)
+					gapx = 100 - (dpos2 * 100 / dpos1);
+				else
+					gapx = 100 - (dpos1 * 100 / dpos2);
+
+				gap[pos1] = gapx;
+#ifdef USE_SPEC_CHECK
+				if (gapx > cm_gap[i][j])
+					specover_count++;
+#endif
+			}
+		}
+	}
+
+	/* get y-direction cm gap */
+	else {
+		input_dbg(true, &ts->client->dev, "gapY RX\n");
+
+		for (i = 0; i < ts->rx_count - 1; i++) {
+			for (j = 0; j < ts->tx_count; j++) {
+				pos1 = (i * ts->tx_count) + j;
+				pos2 = ((i + 1) * ts->tx_count) + j;
+
+				dpos1 = ts->pFrameMS[pos1];
+				dpos2 = ts->pFrameMS[pos2];
+
+				if (dpos1 > dpos2)
+					gapy = 100 - (dpos2 * 100 / dpos1);
+				else
+					gapy = 100 - (dpos1 * 100 / dpos2);
+
+				gap[pos1] = gapy;
+#ifdef USE_SPEC_CHECK
+				if (gapy > cm_gap[i][j])
+					specover_count++;
+#endif
+			}
+		}
+	}
+
+#ifdef USE_SPEC_CHECK
+	input_info(true, &ts->client->dev, "%s: Gap NG for %d node(s)\n",
+			gap_dir == 0 ? "gapX" : "gapY", specover_count);
+#else
+	input_info(true, &ts->client->dev, "%s\n", __func__);
+#endif
+
+	return specover_count;
+}
+
+/* sec_ts_cs_spec_over_check :
+ * apply gap calculation with `pFrame` data.
+ * Please notice that `pFrame` will be changed dynamically by request.
+ * It could be `ts->pFrameSS` or `ts->pFrameMS` for corresponding purpose.
+ */
+static int sec_ts_cs_spec_over_check(struct sec_ts_data *ts, short *gap,
+				     short *pFrame)
+{
+	int i;
+	int specover_count = 0;
+	short dTmp;
+
+	for (i = 0; i < ts->tx_count - 1; i++) {
+		dTmp = pFrame[i] - pFrame[i + 1];
+		if (dTmp < 0)
+			dTmp *= -1;
+
+		gap[i] = dTmp;
+#ifdef USE_SPEC_CHECK
+		if (dTmp > cs_tx_gap)
+			specover_count++;
+#endif
+	}
+
+	for (i = ts->tx_count; i < ts->tx_count + ts->rx_count - 1; i++) {
+		dTmp = pFrame[i] - pFrame[i + 1];
+		if (dTmp < 0)
+			dTmp *= -1;
+
+		gap[i] = dTmp;
+#ifdef USE_SPEC_CHECK
+		if (dTmp > cs_rx_gap)
+			specover_count++;
+#endif
+	}
+
+#ifdef USE_SPEC_CHECK
+	input_info(true, &ts->client->dev, "%s: Gap NG for %d node(s)\n",
+			__func__, specover_count);
+#else
+	input_info(true, &ts->client->dev, "%s\n", __func__);
+#endif
+
+	return specover_count;
+}
+
+#ifdef USE_STIM_PAD
+static int sec_ts_get_gain_table(struct sec_ts_data *ts)
+{
+	int i, j;
+	int temp;
+	int tmp_dv;
+	unsigned int str_size, str_len = 0;
+	unsigned char *pStr = NULL;
+
+	input_info(true, &ts->client->dev, "%s\n", __func__);
+
+	for (i = 0; i < ts->rx_count; i++) {
+		for (j = 0; j < ts->tx_count; j++) {
+			tmp_dv = ts->pFrame[i * ts->tx_count + j];
+
+			/* skip notch area */
+			if (cm_region[i][j] == REGION_NOTCH) {
+				ts->gainTable[j * ts->rx_count + i] = 0;
+				continue;
+			}
+
+			if (tmp_dv <= 0) {
+				input_info(true, &ts->client->dev,
+					"%s: node[%d,%d] == 0\n", __func__, i,
+					j);
+				tmp_dv = 1;
+			}
+
+			temp = (fs_target[i][j] * 1000) / (tmp_dv) * 64;
+			/* Add 500 to round the result */
+			temp = (temp + 500) / 1000;
+			if (temp > 255)
+				temp = 255;
+			ts->gainTable[j * ts->rx_count + i] = (temp & 0xFF);
+		}
+	}
+
+	str_size = 6 * (ts->tx_count + 1);
+	pStr = kzalloc(str_size, GFP_KERNEL);
+	if (pStr == NULL)
+		return -ENOMEM;
+
+	input_info(true, &ts->client->dev, "%s: Gain Table\n", __func__);
+
+	for (i = 0; i < ts->rx_count; i++) {
+		pStr[0] = 0;
+		str_len = 0;
+		for (j = 0; j < ts->tx_count; j++) {
+			str_len += scnprintf(pStr + str_len, str_size - str_len,
+					" %3d",
+					ts->gainTable[(j * ts->rx_count) + i]);
+		}
+		input_info(true, &ts->client->dev, "%s\n", pStr);
+	}
+
+	kfree(pStr);
+
+	return 0;
+}
+
+static int sec_ts_write_gain_table(struct sec_ts_data *ts)
+{
+	int node_cnt = ts->tx_count * ts->rx_count;
+	u8 *gainTable = NULL;
+	u8 *tCmd = NULL;
+	int copy_max, copy_left, copy_size, copy_cur;
+	int ret = -1;
+
+	input_info(true, &ts->client->dev, "%s\n", __func__);
+
+	/* Write norm table to ic
+	 * divide data into 256 bytes:
+	 * buffer size limit 256 bytes
+	 */
+	gainTable = ts->gainTable;
+
+	copy_max = ts->io_burstmax - 3;
+	copy_left = node_cnt;
+	copy_size = 0;
+	copy_cur = (copy_left > copy_max) ? copy_max : copy_left;
+
+	tCmd = kzalloc(copy_cur + 3, GFP_KERNEL);
+	if (!tCmd)
+		goto ErrorAlloc;
+
+	while (copy_left > 0) {
+		tCmd[0] = SEC_TS_CMD_WRITE_NORM_TABLE;
+		tCmd[1] = (copy_size >> 8) & 0xFF;
+		tCmd[2] = (copy_size >> 0) & 0xFF;
+
+		memcpy(&tCmd[3], &gainTable[copy_size], copy_cur);
+
+		input_info(true, &ts->client->dev,
+			   "%s: left = %d, cur = %d, size = %d\n",
+			   __func__, copy_left, copy_cur, copy_size);
+
+		ret = ts->sec_ts_write_burst_heap(ts, tCmd, 3 + copy_cur);
+		if (ret < 0)
+			input_err(true, &ts->client->dev,
+					"%s: table write failed\n", __func__);
+
+		copy_size += copy_cur;
+		copy_left -= copy_cur;
+		copy_cur = (copy_left > copy_max) ? copy_max : copy_left;
+	}
+
+ErrorAlloc:
+	kfree(tCmd);
+
+	return ret;
+}
+
+/* sec_ts_get_postcal_mean : get mean value for all nodes */
+static int sec_ts_get_postcal_mean(struct sec_ts_data *ts)
+{
+	int i, j;
+	int sum = 0;
+	int nCnt = 0;
+
+	for (i = 0; i < ts->rx_count; i++) {
+		for (j = 0; j < ts->tx_count; j++) {
+			if (cm_region[i][j] == REGION_NOTCH) {
+				/* Count notch nodes, where fs target is 0 */
+				nCnt++;
+				continue;
+			}
+			sum += ts->pFrame[(i * ts->tx_count) + j];
+		}
+	}
+
+	/* exclude notch area from average */
+	sum = sum / (ts->tx_count * ts->rx_count - nCnt);
+
+	return sum;
+}
+
+static int sec_ts_get_postcal_uniformity(struct sec_ts_data *ts, short *diff)
+{
+	int pos1, pos2;
+	short dpos1, dpos2, gap;
+	int i = 0;
+	int j = 0;
+	int specover_cnt = 0;
+
+	for (i = 0; i < ts->rx_count; i++) {
+		for (j = 0; j < ts->tx_count - 1; j++) {
+			/* At the notch boundary, skip (leave gap as 0)
+			 * if node[row][col] or node[row][col+1] is 0,
+			 * it is notch boundary for column direction
+			 */
+			if ((cm_region[i][j] == REGION_NOTCH) ||
+			    (cm_region[i][j + 1] == REGION_NOTCH))
+				continue;
+
+			pos1 = (i * ts->tx_count) + j;
+			pos2 = (i * ts->tx_count) + (j + 1);
+
+			dpos1 = ts->pFrame[pos1];
+			dpos2 = ts->pFrame[pos2];
+
+			gap = (dpos1 > dpos2) ? (dpos1 - dpos2) :
+						(dpos2 - dpos1);
+
+			diff[pos1] = gap;
+		}
+	}
+
+	for (i = 0; i < ts->rx_count - 1; i++) {
+		for (j = 0; j < ts->tx_count; j++) {
+			/* At the notch boundary, skip (leave gap as 0)
+			 * if node[row][col] or node[row+1][col] is 0,
+			 * it is notch boundary for row direction
+			 */
+			if ((cm_region[i][j] == REGION_NOTCH) ||
+			    (cm_region[i + 1][j] == REGION_NOTCH))
+				continue;
+
+			pos1 = (i * ts->tx_count) + j;
+			pos2 = ((i + 1) * ts->tx_count) + j;
+
+			dpos1 = ts->pFrame[pos1];
+			dpos2 = ts->pFrame[pos2];
+
+			gap = (dpos1 > dpos2) ? (dpos1 - dpos2) :
+						(dpos2 - dpos1);
+
+			/* find max gap between x and y direction */
+			if (diff[pos1] < gap)
+				diff[pos1] = gap;
+		}
+	}
+
+	for (i = 0; i < ts->rx_count * ts->tx_count; i++) {
+		/* since spec is in % unit, multiply 100 */
+		diff[i] *= 100;
+		diff[i] /= (ts->fs_postcal_mean);
+		if (diff[i] > fs_postcal_uniform_spec)
+			specover_cnt++;
+	}
+
+	return specover_cnt;
+}
+#endif
+
+static void sec_ts_print_frame(struct sec_ts_data *ts, short *min, short *max)
+{
+	int i = 0;
+	int j = 0;
+	const unsigned int buff_size = 6 * (ts->tx_count + 1);
+	unsigned int buff_len = 0;
+	unsigned char *pStr = NULL;
+
+	input_info(true, &ts->client->dev, "%s\n", __func__);
+
+	pStr = kzalloc(buff_size, GFP_KERNEL);
+	if (pStr == NULL)
+		return;
+
+	buff_len += scnprintf(pStr + buff_len, buff_size - buff_len,
+				"      TX");
+
+	for (i = 0; i < ts->tx_count; i++)
+		buff_len += scnprintf(pStr + buff_len, buff_size - buff_len,
+				" %02d ", i);
+
+	input_info(true, &ts->client->dev, "%s\n", pStr);
+	buff_len = 0;
+	memset(pStr, 0x0, buff_size);
+	buff_len += scnprintf(pStr + buff_len, buff_size - buff_len, " +");
+
+	for (i = 0; i < ts->tx_count; i++)
+		buff_len += scnprintf(pStr + buff_len, buff_size - buff_len,
+				"----");
+
+	input_info(true, &ts->client->dev, "%s\n", pStr);
+
+	for (i = 0; i < ts->rx_count; i++) {
+		buff_len = 0;
+		memset(pStr, 0x0, buff_size);
+		buff_len += scnprintf(pStr + buff_len, buff_size - buff_len,
+				"Rx%02d | ", i);
+
+		for (j = 0; j < ts->tx_count; j++) {
+			buff_len += scnprintf(pStr + buff_len,
+				buff_size - buff_len,
+				" %3d", ts->pFrame[(j * ts->rx_count) + i]);
+
+			if (i > 0) {
+				if (ts->pFrame[(j * ts->rx_count) + i] < *min)
+					*min = ts->pFrame[(j * ts->rx_count) +
+								i];
+
+				if (ts->pFrame[(j * ts->rx_count) + i] > *max)
+					*max = ts->pFrame[(j * ts->rx_count) +
+								i];
+			}
+		}
+		input_info(true, &ts->client->dev, "%s\n", pStr);
+	}
+	kfree(pStr);
+}
+
+static int sec_ts_read_frame(struct sec_ts_data *ts, u8 type, short *min,
+		short *max, enum spec_check_type *spec_check)
+{
+	unsigned int readbytes = 0xFF;
+	unsigned char *pRead = NULL;
+	u8 mode = TYPE_INVALID_DATA;
+	int ret = 0;
+	int i = 0;
+	int j = 0;
+	short *temp = NULL;
+	u8 w_type;
+
+	input_info(true, &ts->client->dev, "%s\n", __func__);
+
+	/* set data length, allocation buffer memory */
+	readbytes = ts->rx_count * ts->tx_count * 2;
+
+	pRead = kzalloc(readbytes, GFP_KERNEL);
+	if (!pRead)
+		return -ENOMEM;
+
+	/* set OPCODE and data type */
+	if (type == TYPE_OFFSET_DATA_SDC_CM2)
+		w_type = TYPE_OFFSET_DATA_SDC;
+	else if (type == TYPE_OFFSET_DATA_SDC_NOT_SAVE)
+		w_type = TYPE_OFFSET_DATA_SDC;
+	else
+		w_type = type;
+
+	/* Set raw type to TYPE_INVALID_DATA if change before */
+	ret = ts->sec_ts_read(ts,
+		SEC_TS_CMD_MUTU_RAW_TYPE, &ts->ms_frame_type, 1);
+	if (ret < 0) {
+		input_err(true, &ts->client->dev,
+			"%s: read rawdata type failed\n",
+			__func__);
+		goto ErrorExit;
+	}
+
+	if (ts->ms_frame_type != TYPE_INVALID_DATA) {
+		ret = ts->sec_ts_write(ts, SEC_TS_CMD_MUTU_RAW_TYPE, &mode, 1);
+		if (ret < 0)
+			input_err(true, &ts->client->dev,
+				"%s: recover rawdata type failed\n", __func__);
+	}
+
+	ret = ts->sec_ts_write(ts, SEC_TS_CMD_MUTU_RAW_TYPE, &w_type, 1);
+	if (ret < 0) {
+		input_err(true, &ts->client->dev,
+			  "%s: Set rawdata type failed\n", __func__);
+		goto ErrorExit;
+	}
+	ts->ms_frame_type = w_type;
+
+	sec_ts_delay(50);
+
+	if (type == TYPE_OFFSET_DATA_SDC || type == TYPE_OFFSET_DATA_SDC_CM2
+		|| type == TYPE_OFFSET_DATA_SDC_NOT_SAVE) {
+		/* excute selftest for real cap offset data, because real cap
+		 * data is not memory data in normal touch.
+		 **/
+		char para = TO_TOUCH_MODE;
+
+		disable_irq(ts->client->irq);
+
+		if (type == TYPE_OFFSET_DATA_SDC)
+			execute_selftest(ts, TEST_OPEN |
+				TEST_NODE_VARIANCE);
+		else if (type == TYPE_OFFSET_DATA_SDC_CM2)
+			execute_selftest(ts, TEST_OPEN |
+				TEST_NOT_SAVE | TEST_HIGH_FREQ);
+		else if (type == TYPE_OFFSET_DATA_SDC_NOT_SAVE)
+			execute_selftest(ts, TEST_OPEN |
+				TEST_NODE_VARIANCE | TEST_NOT_SAVE);
+
+		ret = ts->sec_ts_write(ts, SEC_TS_CMD_SET_POWER_MODE, &para, 1);
+		if (ret < 0) {
+			input_err(true, &ts->client->dev,
+				  "%s: Set powermode failed\n", __func__);
+			enable_irq(ts->client->irq);
+			goto ErrorRelease;
+		}
+
+		/* read data and check ret later */
+		ret = ts->sec_ts_read_heap(ts, SEC_TS_READ_TOUCH_RAWDATA, pRead,
+					readbytes);
+		enable_irq(ts->client->irq);
+	} else
+		/* read data and check ret later */
+		ret = ts->sec_ts_read_heap(ts, SEC_TS_READ_TOUCH_RAWDATA, pRead,
+					readbytes);
+
+	/* check read data */
+	if (ret < 0) {
+		input_err(true, &ts->client->dev,
+				  "%s: read rawdata failed!\n", __func__);
+		goto ErrorRelease;
+	}
+
+	memset(ts->pFrame, 0x00, readbytes);
+
+	for (i = 0; i < readbytes; i += 2)
+		ts->pFrame[i / 2] = pRead[i + 1] + (pRead[i] << 8);
+
+#ifdef DEBUG_MSG
+	input_info(true, &ts->client->dev,
+		   "%s: 02X%02X%02X readbytes=%d\n", __func__,
+		   pRead[0], pRead[1], pRead[2], readbytes);
+#endif
+	sec_ts_print_frame(ts, min, max);
+
+	temp = kzalloc(readbytes, GFP_KERNEL);
+	if (!temp)
+		goto ErrorRelease;
+
+	memcpy(temp, ts->pFrame, ts->tx_count * ts->rx_count * 2);
+	memset(ts->pFrame, 0x00, ts->tx_count * ts->rx_count * 2);
+
+	for (i = 0; i < ts->tx_count; i++) {
+		for (j = 0; j < ts->rx_count; j++)
+			ts->pFrame[(j * ts->tx_count) + i] =
+					temp[(i * ts->rx_count) + j];
+	}
+
+#ifdef USE_SPEC_CHECK
+	/* spec check */
+	if (*spec_check == SPEC_CHECK) {
+		int specover_count = 0;
+		short dTmp = 0;
+
+		if (type == TYPE_OFFSET_DATA_SDC) {
+			unsigned int region = 0;
+			/* set initial value for min, max */
+			for (i = 0; i < REGION_TYPE_COUNT; i++) {
+				min[i] = SHRT_MAX;
+				max[i] = SHRT_MIN;
+			}
+
+			for (i = 0; i < ts->rx_count; i++) {
+				for (j = 0; j < ts->tx_count; j++) {
+					dTmp = ts->pFrame[i * ts->tx_count + j];
+					region = cm_region[i][j];
+
+					if (region == REGION_NOTCH)
+						continue;
+
+					min[region] = min(min[region], dTmp);
+					max[region] = max(max[region], dTmp);
+
+					if (dTmp > cm_max[region])
+						specover_count++;
+					if (dTmp < cm_min[region])
+						specover_count++;
+				}
+			}
+			input_info(true, &ts->client->dev,
+				   "%s: type = %d, specover = %d\n",
+				   __func__, type, specover_count);
+
+			if (specover_count == 0 &&
+			    (max[REGION_NORMAL] - min[REGION_NORMAL] <
+			     cm_mm[REGION_NORMAL]) &&
+			    (max[REGION_EDGE] - min[REGION_EDGE] <
+			     cm_mm[REGION_EDGE]) &&
+			    (max[REGION_CORNER] - min[REGION_CORNER] <
+			     cm_mm[REGION_CORNER]))
+				*spec_check = SPEC_PASS;
+			else
+				*spec_check = SPEC_FAIL;
+		} else if (type == TYPE_NOI_P2P_MIN) {
+			for (i = 0; i < ts->rx_count; i++) {
+				for (j = 0; j < ts->tx_count; j++) {
+					dTmp = ts->pFrame[i * ts->tx_count + j];
+					if (cm_region[i][j] != REGION_NOTCH &&
+					    dTmp < noi_min[i][j])
+						specover_count++;
+				}
+			}
+			input_info(true, &ts->client->dev,
+				   "%s: type = %d, specover = %d\n",
+				   __func__, type, specover_count);
+
+			if (specover_count == 0)
+				*spec_check = SPEC_PASS;
+			else
+				*spec_check = SPEC_FAIL;
+		} else if (type == TYPE_NOI_P2P_MAX) {
+			for (i = 0; i < ts->rx_count; i++) {
+				for (j = 0; j < ts->tx_count; j++) {
+					dTmp = ts->pFrame[i * ts->tx_count + j];
+					if (cm_region[i][j] != REGION_NOTCH &&
+					    dTmp > noi_max[i][j])
+						specover_count++;
+				}
+			}
+			input_info(true, &ts->client->dev,
+				   "%s: type = %d, specover = %d\n",
+				   __func__, type, specover_count);
+
+			if (specover_count == 0)
+				*spec_check = SPEC_PASS;
+			else
+				*spec_check = SPEC_FAIL;
+		}
+	}
+#else
+	*spec_check = SPEC_PASS;
+#endif
+
+	kfree(temp);
+
+ErrorRelease:
+	/* release data monitory (unprepare AFE data memory) */
+	ret = ts->sec_ts_write(ts, SEC_TS_CMD_MUTU_RAW_TYPE, &mode, 1);
+	if (ret < 0)
+		input_err(true, &ts->client->dev,
+			  "%s: Set rawdata type failed\n", __func__);
+	else
+		ts->ms_frame_type = mode;
+
+ErrorExit:
+	kfree(pRead);
+
+	return ret;
+}
+
+/* sec_ts_print_channel :
+ *  output self raw data to kernel logs.
+ *  Please notice that `pFrame` will be changed dynamically by request.
+ *  It could be `ts->pFrame` or `ts->pFrameSS` for corresponding purpose.
+ */
+static void sec_ts_print_channel(struct sec_ts_data *ts, short *pFrame)
+{
+	unsigned char *pStr = NULL;
+	unsigned int str_size, str_len = 0;
+	int i = 0, j = 0, k = 0;
+
+	if (!ts->tx_count)
+		return;
+
+	str_size = 7 * (ts->tx_count + 1);
+	pStr = vzalloc(str_size);
+	if (!pStr)
+		return;
+
+	str_len = scnprintf(pStr, str_size, " TX");
+
+	for (k = 0; k < ts->tx_count; k++) {
+		str_len += scnprintf(pStr + str_len, str_size - str_len,
+				     "    %02d", k);
+	}
+	input_info(true, &ts->client->dev, "%s\n", pStr);
+
+	str_len = scnprintf(pStr, str_size, " +");
+
+	for (k = 0; k < ts->tx_count; k++) {
+		str_len += scnprintf(pStr + str_len, str_size - str_len,
+				     "------");
+	}
+	input_info(true, &ts->client->dev, "%s\n", pStr);
+
+	str_len = scnprintf(pStr, str_size, " | ");
+
+	for (i = 0; i < (ts->tx_count + ts->rx_count) * 2; i += 2) {
+		if (j == ts->tx_count) {
+			input_info(true, &ts->client->dev, "%s\n", pStr);
+			input_info(true, &ts->client->dev, "\n");
+			str_len = scnprintf(pStr, str_size, " RX");
+
+			for (k = 0; k < ts->tx_count; k++) {
+				str_len += scnprintf(pStr + str_len,
+						     str_size - str_len,
+						     "    %02d", k);
+			}
+
+			input_info(true, &ts->client->dev, "%s\n", pStr);
+
+			str_len = scnprintf(pStr, str_size, " +");
+
+			for (k = 0; k < ts->tx_count; k++) {
+				str_len += scnprintf(pStr + str_len,
+						     str_size - str_len,
+						     "------");
+			}
+			input_info(true, &ts->client->dev, "%s\n", pStr);
+
+			str_len = scnprintf(pStr, str_size, " | ");
+		} else if (j && !(j % ts->tx_count)) {
+			input_info(true, &ts->client->dev, "%s\n", pStr);
+			str_len = scnprintf(pStr, str_size, " | ");
+		}
+
+		str_len += scnprintf(pStr + str_len, str_size - str_len, " %5d",
+				     pFrame[j]);
+
+		j++;
+	}
+	input_info(true, &ts->client->dev, "%s\n", pStr);
+	vfree(pStr);
+}
+
+static int sec_ts_read_channel(struct sec_ts_data *ts, u8 type, short *min,
+			       short *max, enum spec_check_type *spec_check)
+{
+	unsigned char *pRead = NULL;
+	u8 mode = TYPE_INVALID_DATA;
+	int ret = 0;
+	int ii = 0;
+	int jj = 0;
+	unsigned int data_length = (ts->tx_count + ts->rx_count) * 2;
+	u8 w_data;
+
+	input_info(true, &ts->client->dev, "%s\n", __func__);
+
+	pRead = kzalloc(data_length, GFP_KERNEL);
+	if (!pRead)
+		return -ENOMEM;
+
+	/* set OPCODE and data type */
+	if (type == TYPE_OFFSET_DATA_SDC_NOT_SAVE)
+		w_data = TYPE_OFFSET_DATA_SDC;
+	else
+		w_data = type;
+	ret = ts->sec_ts_write(ts, SEC_TS_CMD_SELF_RAW_TYPE, &w_data, 1);
+	if (ret < 0) {
+		input_err(true, &ts->client->dev,
+			"%s: Set rawdata type failed\n", __func__);
+		goto out_read_channel;
+	}
+
+	sec_ts_delay(50);
+
+	if (type == TYPE_OFFSET_DATA_SDC ||
+		type == TYPE_OFFSET_DATA_SDC_NOT_SAVE) {
+		/* excute selftest for real cap offset data, because real cap
+		 * data is not memory data in normal touch.
+		 **/
+		char para = TO_TOUCH_MODE;
+
+		disable_irq(ts->client->irq);
+		if (type == TYPE_OFFSET_DATA_SDC)
+			execute_selftest(ts, TEST_SELF_NODE);
+		else if (type == TYPE_OFFSET_DATA_SDC_NOT_SAVE)
+			execute_selftest(ts, TEST_SELF_NODE | TEST_NOT_SAVE);
+		ret = ts->sec_ts_write(ts, SEC_TS_CMD_SET_POWER_MODE, &para, 1);
+		if (ret < 0) {
+			input_err(true, &ts->client->dev,
+				  "%s: set rawdata type failed!\n", __func__);
+			enable_irq(ts->client->irq);
+			goto err_read_data;
+		}
+
+		/* read data and check ret later */
+		ret = ts->sec_ts_read_heap(ts, SEC_TS_READ_TOUCH_SELF_RAWDATA,
+					pRead, data_length);
+		enable_irq(ts->client->irq);
+		/* end */
+	} else
+		/* read data and check ret later */
+		ret = ts->sec_ts_read_heap(ts, SEC_TS_READ_TOUCH_SELF_RAWDATA,
+					pRead, data_length);
+
+	/* check read data */
+	if (ret < 0) {
+		input_err(true, &ts->client->dev,
+				  "%s: read rawdata failed!\n", __func__);
+		goto err_read_data;
+	}
+
+	/* clear all pFrame data */
+	memset(ts->pFrame, 0x00, data_length);
+
+/* d[00] ~ d[14] : TX channel
+ * d[15] ~ d[51] : none
+ * d[52] ~ d[77] : RX channel
+ * d[78] ~ d[103] : none
+ */
+	for (ii = 0; ii < data_length; ii += 2) {
+		ts->pFrame[jj] = ((pRead[ii] << 8) | pRead[ii + 1]);
+		jj++;
+	}
+
+	sec_ts_print_channel(ts, ts->pFrame);
+
+#ifdef USE_SPEC_CHECK
+	if (*spec_check == SPEC_CHECK) {
+		int specover_count = 0;
+
+		if (type == TYPE_OFFSET_DATA_SDC) {
+			min[0] = min[1] = SHRT_MAX;
+			max[0] = max[1] = SHRT_MIN;
+
+			for (ii = 0; ii < ts->tx_count; ii++) {
+				if (ts->pFrame[ii] > cs_tx_max)
+					specover_count++;
+				if (ts->pFrame[ii] < cs_tx_min)
+					specover_count++;
+				min[0] = min(min[0], ts->pFrame[ii]);
+				max[0] = max(max[0], ts->pFrame[ii]);
+			}
+
+			for (ii = ts->tx_count;
+			     ii < ts->tx_count + ts->rx_count; ii++) {
+				if (ts->pFrame[ii] > cs_rx_max)
+					specover_count++;
+				if (ts->pFrame[ii] < cs_rx_min)
+					specover_count++;
+				min[1] = min(min[1], ts->pFrame[ii]);
+				max[1] = max(max[1], ts->pFrame[ii]);
+			}
+		}
+
+		input_info(true, &ts->client->dev,
+			   "%s: type : %d, specover = %d\n",
+			   __func__, type, specover_count);
+		if (specover_count == 0 &&
+			(max[0] - min[0]) < cs_tx_mm &&
+			(max[1] - min[1]) < cs_rx_mm)
+			*spec_check = SPEC_PASS;
+		else
+			*spec_check = SPEC_FAIL;
+	}
+#else
+	*spec_check = SPEC_PASS;
+#endif
+
+err_read_data:
+	/* release data monitory (unprepare AFE data memory) */
+	ret = ts->sec_ts_write(ts, SEC_TS_CMD_SELF_RAW_TYPE, &mode, 1);
+	if (ret < 0)
+		input_err(true, &ts->client->dev,
+			  "%s: Set rawdata type failed\n", __func__);
+
+out_read_channel:
+	kfree(pRead);
+
+	return ret;
+}
+
+int sec_ts_save_mutual_raw_to_buffer(struct sec_ts_data *ts,
+		struct sec_cmd_data *sec, struct sec_ts_test_mode *mode,
+		char *buff, const unsigned int buff_size)
+{
+	int ii, jj;
+	unsigned int buff_len = 0;
+
+	if (mode->spec_check == SPEC_NO_CHECK)
+		buff_len += scnprintf(buff + buff_len,
+				      buff_size - buff_len, "\n");
+	else if (mode->spec_check == SPEC_PASS) {
+		buff_len += scnprintf(buff + buff_len,
+				      buff_size - buff_len,
+				      "OK %d %d\n",
+				      ts->rx_count, ts->tx_count);
+	} else {	/* mode->spec_check == SPEC_FAIL) */
+		buff_len += scnprintf(buff + buff_len,
+				      buff_size - buff_len,
+				      "NG %d %d\n", ts->rx_count,
+				      ts->tx_count);
+	}
+	if (!ts->print_format) {
+		for (ii = 0;
+		     ii < (ts->rx_count * ts->tx_count); ii++) {
+			buff_len += scnprintf(buff + buff_len,
+					      buff_size - buff_len,
+					      "%3d,", ts->pFrame[ii]);
+			if (ii % ts->tx_count == (ts->tx_count - 1))
+				buff_len += scnprintf(buff + buff_len,
+						      buff_size - buff_len,
+						      "\n");
+		}
+	} else {
+		for (ii = 0; ii < ts->tx_count; ii++) {
+			for (jj = 0; jj < ts->rx_count; jj++) {
+				buff_len += scnprintf(
+						buff + buff_len,
+						buff_size - buff_len,
+						"%3d,",
+						ts->pFrame[(jj *
+							ts->tx_count) + ii]);
+			}
+			buff_len += scnprintf(buff + buff_len,
+					      buff_size - buff_len,
+					      "\n");
+		}
+	}
+
+	return buff_len;
+}
+
+int sec_ts_save_self_raw_to_buffer(struct sec_ts_data *ts,
+		struct sec_cmd_data *sec, struct sec_ts_test_mode *mode,
+		char *buff, const unsigned int buff_size)
+{
+	int ii;
+	unsigned int buff_len = 0;
+	short *pFrame = ts->pFrame;
+
+	if (mode->frame_channel == TEST_MODE_READ_ALL)
+		pFrame = ts->pFrameSS;
+
+	if (mode->spec_check == SPEC_NO_CHECK)
+		buff_len += scnprintf(buff + buff_len,
+				      buff_size - buff_len, "\n");
+	else if (mode->spec_check == SPEC_PASS) {
+		buff_len += scnprintf(buff + buff_len,
+				      buff_size - buff_len,
+				      "OK %d %d\n",
+				      ts->rx_count, ts->tx_count);
+	} else {	/* mode->spec_check == SPEC_FAIL) */
+		buff_len += scnprintf(buff + buff_len,
+				      buff_size - buff_len,
+				      "NG %d %d\n",
+				      ts->rx_count, ts->tx_count);
+	}
+	buff_len += scnprintf(buff + buff_len,
+			      buff_size - buff_len, "      ");
+	if (!ts->print_format) {
+		for (ii = 0;
+		     ii < (ts->rx_count + ts->tx_count);
+		     ii++) {
+			buff_len += scnprintf(buff + buff_len,
+					      buff_size - buff_len,
+					      "%3d,", pFrame[ii]);
+			if (ii >= ts->tx_count - 1)
+				buff_len += scnprintf(
+						buff + buff_len,
+						buff_size - buff_len,
+						"\n");
+		}
+	} else {
+		for (ii = ts->tx_count;
+		     ii < (ts->rx_count + ts->tx_count);
+		     ii++) {
+			buff_len += scnprintf(buff + buff_len,
+					      buff_size - buff_len,
+					      "%3d,", pFrame[ii]);
+		}
+		buff_len += scnprintf(buff + buff_len,
+				      buff_size - buff_len, "\n");
+		for (ii = 0; ii < ts->tx_count; ii++) {
+			buff_len += scnprintf(buff + buff_len,
+					      buff_size - buff_len,
+					      "%3d,\n", pFrame[ii]);
+		}
+	}
+
+	return buff_len;
+}
+
+static int sec_ts_read_frame_and_channel(struct sec_ts_data *ts, u8 type,
+		short *min, short *max, enum spec_check_type *spec_check)
+{
+	unsigned int readbytes_mutual = 0xFF;
+	unsigned int readbytes_self = 0xFF;
+	u8 *pReadMutual = NULL;
+	u8 *pReadSelf = NULL;
+	u8 mode = TYPE_INVALID_DATA;
+	int ret = 0;
+	int i = 0;
+	int j = 0;
+	short *temp = NULL;
+	short *pFrame = NULL;
+	u8 w_type;
+
+	input_info(true, &ts->client->dev, "%s\n", __func__);
+
+	/* set data length, allocation buffer memory */
+	readbytes_mutual = ts->rx_count * ts->tx_count * 2;
+	readbytes_self = (ts->rx_count + ts->tx_count) * 2;
+
+	pReadMutual = kzalloc(readbytes_mutual, GFP_KERNEL);
+	pReadSelf = kzalloc(readbytes_self, GFP_KERNEL);
+	if (!pReadMutual || !pReadSelf) {
+		kfree(pReadMutual);
+		kfree(pReadSelf);
+		return -ENOMEM;
+	}
+
+	/* set OPCODE and data type */
+	if (type == TYPE_OFFSET_DATA_SDC_CM2)
+		w_type = TYPE_OFFSET_DATA_SDC;
+	else if (type == TYPE_OFFSET_DATA_SDC_NOT_SAVE)
+		w_type = TYPE_OFFSET_DATA_SDC;
+	else
+		w_type = type;
+
+	ret = ts->sec_ts_write(ts, SEC_TS_CMD_MUTU_RAW_TYPE, &w_type, 1);
+	if (ret < 0) {
+		input_err(true, &ts->client->dev,
+			  "%s: Set rawdata type failed\n", __func__);
+		goto ErrorExit;
+	}
+	ret = ts->sec_ts_write(ts, SEC_TS_CMD_SELF_RAW_TYPE, &w_type, 1);
+	if (ret < 0) {
+		input_err(true, &ts->client->dev,
+			  "%s: Set rawdata type failed\n", __func__);
+		goto ErrorExit;
+	}
+
+	ts->ms_frame_type = w_type;
+	ts->ss_frame_type = w_type;
+
+	sec_ts_delay(50);
+
+	if (type == TYPE_OFFSET_DATA_SDC || type == TYPE_OFFSET_DATA_SDC_CM2
+		|| type == TYPE_OFFSET_DATA_SDC_NOT_SAVE) {
+		/* excute selftest for real cap offset data, because real cap
+		 * data is not memory data in normal touch.
+		 **/
+		char para = TO_TOUCH_MODE;
+
+		disable_irq(ts->client->irq);
+
+		if (type == TYPE_OFFSET_DATA_SDC)
+			execute_selftest(ts, TEST_OPEN |
+				TEST_NODE_VARIANCE | TEST_SELF_NODE);
+		else if (type == TYPE_OFFSET_DATA_SDC_CM2)
+			execute_selftest(ts, TEST_OPEN |
+				TEST_NOT_SAVE | TEST_HIGH_FREQ |
+				TEST_SELF_NODE);
+		else if (type == TYPE_OFFSET_DATA_SDC_NOT_SAVE)
+			execute_selftest(ts, TEST_OPEN |
+				TEST_NODE_VARIANCE | TEST_NOT_SAVE |
+				TEST_SELF_NODE);
+
+		ret = ts->sec_ts_write(ts, SEC_TS_CMD_SET_POWER_MODE, &para, 1);
+		if (ret < 0) {
+			input_err(true, &ts->client->dev,
+				  "%s: Set powermode failed\n", __func__);
+			enable_irq(ts->client->irq);
+			goto ErrorRelease;
+		}
+
+		/* read data and check ret later */
+		ret = ts->sec_ts_read_heap(ts, SEC_TS_READ_TOUCH_RAWDATA,
+					pReadMutual, readbytes_mutual);
+		ret |= ts->sec_ts_read_heap(ts, SEC_TS_READ_TOUCH_SELF_RAWDATA,
+					pReadSelf, readbytes_self);
+		enable_irq(ts->client->irq);
+
+	} else {
+		/* read data and check ret later */
+		ret = ts->sec_ts_read_heap(ts, SEC_TS_READ_TOUCH_RAWDATA,
+					pReadMutual, readbytes_mutual);
+		ret |= ts->sec_ts_read_heap(ts, SEC_TS_READ_TOUCH_SELF_RAWDATA,
+					pReadSelf, readbytes_self);
+	}
+	/* check read data */
+	if (ret < 0) {
+		input_err(true, &ts->client->dev,
+				  "%s: read rawdata failed!\n", __func__);
+		goto ErrorRelease;
+	}
+
+/* handle mutual raw data */
+	pFrame = ts->pFrameMS;
+	/* mutual data decode and print screen */
+	memset(pFrame, 0x00, readbytes_mutual);
+
+	for (i = 0; i < readbytes_mutual; i += 2)
+		pFrame[i / 2] = pReadMutual[i + 1] + (pReadMutual[i] << 8);
+
+#ifdef DEBUG_MSG
+	input_info(true, &ts->client->dev,
+		"%s: 02X%02X%02X readbytes=%d\n", __func__,
+		pReadMutual[0], pReadMutual[1], pReadMutual[2],
+		readbytes_mutual);
+#endif
+	sec_ts_print_frame(ts, min, max);
+
+	temp = kzalloc(readbytes_mutual, GFP_KERNEL);
+	if (!temp)
+		goto ErrorRelease;
+
+	memcpy(temp, pFrame, ts->tx_count * ts->rx_count * 2);
+	memset(pFrame, 0x00, ts->tx_count * ts->rx_count * 2);
+
+	for (i = 0; i < ts->tx_count; i++) {
+		for (j = 0; j < ts->rx_count; j++)
+			pFrame[(j * ts->tx_count) + i] =
+				temp[(i * ts->rx_count) + j];
+	}
+
+#ifdef USE_SPEC_CHECK
+	/* spec check */
+	if (*spec_check == SPEC_CHECK) {
+		int specover_count = 0;
+		short dTmp = 0;
+
+		if (type == TYPE_OFFSET_DATA_SDC) {
+			unsigned int region = 0;
+			/* set initial value for min, max */
+			for (i = 0; i < REGION_TYPE_COUNT; i++) {
+				min[i] = SHRT_MAX;
+				max[i] = SHRT_MIN;
+			}
+
+			for (i = 0; i < ts->rx_count; i++) {
+				for (j = 0; j < ts->tx_count; j++) {
+					dTmp = pFrame[i * ts->tx_count + j];
+					region = cm_region[i][j];
+
+					if (region == REGION_NOTCH)
+						continue;
+
+					min[region] = min(min[region], dTmp);
+					max[region] = max(max[region], dTmp);
+
+					if (dTmp > cm_max[region])
+						specover_count++;
+					if (dTmp < cm_min[region])
+						specover_count++;
+				}
+			}
+			input_info(true, &ts->client->dev,
+				   "%s: type = %d, specover = %d\n",
+				   __func__, type, specover_count);
+
+			if (specover_count == 0 &&
+			    (max[REGION_NORMAL] - min[REGION_NORMAL] <
+			     cm_mm[REGION_NORMAL]) &&
+			    (max[REGION_EDGE] - min[REGION_EDGE] <
+			     cm_mm[REGION_EDGE]) &&
+			    (max[REGION_CORNER] - min[REGION_CORNER] <
+			     cm_mm[REGION_CORNER]))
+				*spec_check = SPEC_PASS;
+			else
+				*spec_check = SPEC_FAIL;
+		} else if (type == TYPE_NOI_P2P_MIN) {
+			for (i = 0; i < ts->rx_count; i++) {
+				for (j = 0; j < ts->tx_count; j++) {
+					dTmp = pFrame[i * ts->tx_count + j];
+					if (cm_region[i][j] != REGION_NOTCH &&
+					    dTmp < noi_min[i][j])
+						specover_count++;
+				}
+			}
+			input_info(true, &ts->client->dev,
+				   "%s: type = %d, specover = %d\n",
+				   __func__, type, specover_count);
+
+			if (specover_count == 0)
+				*spec_check = SPEC_PASS;
+			else
+				*spec_check = SPEC_FAIL;
+		} else if (type == TYPE_NOI_P2P_MAX) {
+			for (i = 0; i < ts->rx_count; i++) {
+				for (j = 0; j < ts->tx_count; j++) {
+					dTmp = pFrame[i * ts->tx_count + j];
+					if (cm_region[i][j] != REGION_NOTCH &&
+					    dTmp > noi_max[i][j])
+						specover_count++;
+				}
+			}
+			input_info(true, &ts->client->dev,
+				   "%s: type = %d, specover = %d\n",
+				   __func__, type, specover_count);
+
+			if (specover_count == 0)
+				*spec_check = SPEC_PASS;
+			else
+				*spec_check = SPEC_FAIL;
+		}
+	}
+#else
+		*spec_check = SPEC_PASS;
+#endif
+
+	kfree(temp);
+
+/* handle self raw data */
+	pFrame = ts->pFrameSS;
+	/* clear all pFrame data */
+	memset(pFrame, 0x00, readbytes_self);
+
+/* d[00] ~ d[14] : TX channel
+ * d[15] ~ d[51] : none
+ * d[52] ~ d[77] : RX channel
+ * d[78] ~ d[103] : none
+ */
+	for (i = 0, j = 0; i < readbytes_self; i += 2) {
+		pFrame[j] = ((pReadSelf[i] << 8) | pReadSelf[i + 1]);
+		j++;
+	}
+
+	sec_ts_print_channel(ts, pFrame);
+
+#ifdef USE_SPEC_CHECK
+	if (*spec_check == SPEC_CHECK) {
+		int specover_count = 0;
+
+		if (type == TYPE_OFFSET_DATA_SDC) {
+			min[0] = min[1] = SHRT_MAX;
+			max[0] = max[1] = SHRT_MIN;
+
+			for (i = 0; i < ts->tx_count; i++) {
+				if (pFrame[i] > cs_tx_max)
+					specover_count++;
+				if (pFrame[i] < cs_tx_min)
+					specover_count++;
+				min[0] = min(min[0], pFrame[i]);
+				max[0] = max(max[0], pFrame[i]);
+			}
+			for (i = ts->tx_count;
+			     i < ts->tx_count + ts->rx_count; i++) {
+				if (pFrame[i] > cs_rx_max)
+					specover_count++;
+				if (pFrame[i] < cs_rx_min)
+					specover_count++;
+				min[1] = min(min[1], pFrame[i]);
+				max[1] = max(max[1], pFrame[i]);
+			}
+		}
+
+		input_info(true, &ts->client->dev,
+			   "%s: type : %d, specover = %d\n",
+			   __func__, type, specover_count);
+		if (specover_count == 0 &&
+			(max[0] - min[0]) < cs_tx_mm &&
+			(max[1] - min[1]) < cs_rx_mm)
+			*spec_check = SPEC_PASS;
+		else
+			*spec_check = SPEC_FAIL;
+	}
+#else
+	*spec_check = SPEC_PASS;
+#endif
+
+
+ErrorRelease:
+	/* release data monitory (unprepare AFE data memory) */
+	ret = ts->sec_ts_write(ts, SEC_TS_CMD_MUTU_RAW_TYPE, &mode, 1);
+	if (ret < 0)
+		input_err(true, &ts->client->dev,
+			  "%s: Set rawdata type failed\n", __func__);
+	else
+		ts->ms_frame_type = mode;
+
+	ret = ts->sec_ts_write(ts, SEC_TS_CMD_SELF_RAW_TYPE, &mode, 1);
+	if (ret < 0)
+		input_err(true, &ts->client->dev,
+			  "%s: Set rawdata type failed\n", __func__);
+	else
+		ts->ss_frame_type = mode;
+ErrorExit:
+	kfree(pReadMutual);
+	kfree(pReadSelf);
+
+	return ret;
+}
+
+#ifdef USE_STIM_PAD
+static int sec_ts_read_gain_table(struct sec_ts_data *ts)
+{
+	int readbytes = ts->tx_count * ts->rx_count;
+	unsigned char *pRead = NULL;
+	short min = 0;
+	short max = 0;
+	int ret;
+	int i;
+
+	/* readbytes : 1 byte for enable/disable info + 1 byte per node */
+	pRead = kzalloc(1 + readbytes, GFP_KERNEL);
+	if (!pRead)
+		return -ENOMEM;
+
+	ret = ts->sec_ts_read_heap(ts, SEC_TS_CMD_READ_NORM_TABLE, pRead,
+				1 + readbytes);
+	if (ret < 0) {
+		input_err(true, &ts->client->dev, "%s: read rawdata failed!\n",
+			  __func__);
+		goto ErrorRead;
+	}
+
+	input_info(true, &ts->client->dev, "%s: gain table is %s\n",
+		   __func__, pRead[0] ? "On." : "Off.");
+
+	for (i = 0; i < readbytes; i++)
+		ts->pFrame[i] = (short)pRead[i + 1];
+
+	sec_ts_print_frame(ts, &min, &max);
+
+ErrorRead:
+	kfree(pRead);
+
+	return ret;
+}
+
+int sec_ts_check_fs_precal(struct sec_ts_data *ts)
+{
+	int i, j;
+	int fail_count = 0;
+	short temp;
+
+	for (i = 0; i < ts->rx_count; i++) {
+		for (j = 0; j < ts->tx_count; j++) {
+			temp = ts->pFrame[i * ts->tx_count + j];
+			if (cm_region[i][j] == REGION_NOTCH)
+				continue;
+			/* check whether fs_precal data is within range */
+			if ((temp > fs_precal_h[i][j]) ||
+				(temp < fs_precal_l[i][j]))
+				fail_count++;
+		}
+	}
+
+	return fail_count;
+}
+#endif
+
+int sec_ts_read_raw_data(struct sec_ts_data *ts,
+		struct sec_cmd_data *sec, struct sec_ts_test_mode *mode)
+{
+	int ret = 0;
+	const unsigned int buff_size = ts->tx_count * ts->rx_count *
+					CMD_RESULT_WORD_LEN;
+	unsigned int buff_len = 0;
+	char *buff;
+
+	buff = kzalloc(buff_size, GFP_KERNEL);
+	if (!buff)
+		goto error_alloc_mem;
+
+	if (ts->power_status == SEC_TS_STATE_POWER_OFF) {
+		input_err(true, &ts->client->dev,
+			  "%s: [ERROR] Touch is stopped\n", __func__);
+		goto error_power_state;
+	}
+
+	input_info(true, &ts->client->dev, "%s: %d, %s\n",
+			__func__, mode->type, mode->allnode ? "ALL" : "");
+
+	ret = sec_ts_fix_tmode(ts, TOUCH_SYSTEM_MODE_TOUCH,
+			       TOUCH_MODE_STATE_TOUCH);
+	if (ret < 0) {
+		input_err(true, &ts->client->dev, "%s: failed to fix tmode\n",
+				__func__);
+		goto error_test_fail;
+	}
+
+	if (mode->frame_channel == TEST_MODE_READ_CHANNEL)
+		ret = sec_ts_read_channel(ts, mode->type, mode->min,
+					  mode->max, &mode->spec_check);
+	else if (mode->frame_channel == TEST_MODE_READ_FRAME)
+		ret = sec_ts_read_frame(ts, mode->type, mode->min,
+					mode->max, &mode->spec_check);
+	else if (mode->frame_channel == TEST_MODE_READ_ALL)
+		ret = sec_ts_read_frame_and_channel(ts, mode->type, mode->min,
+				      mode->max, &mode->spec_check);
+	else
+		ret = -EINVAL;
+
+	if (ret < 0) {
+		input_err(true, &ts->client->dev, "%s: failed to read frame\n",
+				__func__);
+		goto error_test_fail;
+	}
+
+	if (mode->allnode) {
+		if (mode->frame_channel == TEST_MODE_READ_FRAME ||
+		    mode->frame_channel == TEST_MODE_READ_ALL) {
+			buff_len += sec_ts_save_mutual_raw_to_buffer(ts, sec,
+				mode, buff + buff_len, buff_size - buff_len);
+		}
+
+		if (mode->frame_channel == TEST_MODE_READ_CHANNEL ||
+		    mode->frame_channel == TEST_MODE_READ_ALL) {
+			buff_len += sec_ts_save_self_raw_to_buffer(ts, sec,
+				mode, buff + buff_len, buff_size - buff_len);
+		}
+	} else {
+#ifdef USE_SPEC_CHECK
+		buff_len += scnprintf(buff + buff_len, buff_size - buff_len,
+				      "%3d,%3d", mode->min[0], mode->max[0]);
+#else
+		buff_len += scnprintf(buff + buff_len, buff_size - buff_len,
+				      "OK");
+#endif
+	}
+
+	ret = sec_ts_release_tmode(ts);
+	if (ret < 0) {
+		input_err(true, &ts->client->dev,
+			  "%s: failed to release tmode\n", __func__);
+		goto error_test_fail;
+	}
+
+	if (!sec)
+		goto out_rawdata;
+	sec_cmd_set_cmd_result(sec, buff, buff_len);
+	sec->cmd_state = SEC_CMD_STATUS_OK;
+
+out_rawdata:
+	kfree(buff);
+
+	sec_ts_locked_release_all_finger(ts);
+
+	return ret;
+
+error_test_fail:
+error_power_state:
+	kfree(buff);
+error_alloc_mem:
+	if (!sec)
+		return ret;
+
+	sec_cmd_set_cmd_result(sec, "FAIL", 4);
+	sec->cmd_state = SEC_CMD_STATUS_FAIL;
+
+	sec_ts_locked_release_all_finger(ts);
+
+	return ret;
+}
+
+static void get_fw_ver_bin(void *device_data)
+{
+	struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data;
+	struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
+	char buff[16] = { 0 };
+
+	sec_cmd_set_default_result(sec);
+
+	snprintf(buff, sizeof(buff), "SE-V%02X.%02X.%02X",
+		ts->plat_data->panel_revision,
+		ts->plat_data->img_version_of_bin[2],
+		ts->plat_data->img_version_of_bin[3]);
+
+	sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
+	sec->cmd_state = SEC_CMD_STATUS_OK;
+	input_info(true, &ts->client->dev, "%s: %s\n", __func__, buff);
+}
+
+static void get_fw_ver_ic(void *device_data)
+{
+	struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data;
+	struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
+	char buff[16] = { 0 };
+	int ret;
+	u8 fw_ver[4];
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, true);
+
+	sec_cmd_set_default_result(sec);
+
+	if (ts->power_status == SEC_TS_STATE_POWER_OFF) {
+		input_err(true, &ts->client->dev,
+			  "%s: [ERROR] Touch is stopped\n", __func__);
+		snprintf(buff, sizeof(buff), "%s", "TSP turned off");
+		sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
+		sec->cmd_state = SEC_CMD_STATUS_NOT_APPLICABLE;
+		sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+		return;
+	}
+
+	ret = ts->sec_ts_read(ts, SEC_TS_READ_IMG_VERSION, fw_ver, 4);
+	if (ret < 0) {
+		input_err(true, &ts->client->dev,
+			  "%s: firmware version read error\n", __func__);
+		snprintf(buff, sizeof(buff), "%s", "NG");
+		sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
+		sec->cmd_state = SEC_CMD_STATUS_FAIL;
+		sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+		return;
+	}
+
+	snprintf(buff, sizeof(buff), "SE-V%02X.%02X.%02X",
+			ts->plat_data->panel_revision, fw_ver[2], fw_ver[3]);
+
+	sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
+	sec->cmd_state = SEC_CMD_STATUS_OK;
+	input_info(true, &ts->client->dev, "%s: %s\n", __func__, buff);
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+}
+
+static void get_config_ver(void *device_data)
+{
+	struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data;
+	struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
+	char buff[22] = { 0 };
+
+	sec_cmd_set_default_result(sec);
+
+	snprintf(buff, sizeof(buff), "%s_SE_%02X%02X",
+		ts->plat_data->model_name,
+		ts->plat_data->config_version_of_ic[2],
+		ts->plat_data->config_version_of_ic[3]);
+
+	sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
+	sec->cmd_state = SEC_CMD_STATUS_OK;
+	input_info(true, &ts->client->dev, "%s: %s\n", __func__, buff);
+}
+
+#ifdef PAT_CONTROL
+static void get_pat_information(void *device_data)
+{
+	struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data;
+	struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
+	char buff[22] = { 0 };
+
+	sec_cmd_set_default_result(sec);
+
+	/* fixed tune version will be saved at excute autotune */
+	snprintf(buff, sizeof(buff), "P%02XT%04X",
+		ts->cal_count, ts->tune_fix_ver);
+
+	sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
+	sec->cmd_state = SEC_CMD_STATUS_OK;
+	input_info(true, &ts->client->dev, "%s: %s\n", __func__, buff);
+}
+
+static void set_external_factory(void *device_data)
+{
+	struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data;
+	struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
+	char buff[22] = { 0 };
+
+	sec_cmd_set_default_result(sec);
+
+	ts->external_factory = true;
+	snprintf(buff, sizeof(buff), "OK");
+
+	sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
+	sec->cmd_state = SEC_CMD_STATUS_OK;
+	input_info(true, &ts->client->dev, "%s: %s\n", __func__, buff);
+}
+#endif
+
+static void get_threshold(void *device_data)
+{
+	struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data;
+	struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
+	char buff[20] = { 0 };
+	char threshold[2] = { 0 };
+	int ret;
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, true);
+
+	sec_cmd_set_default_result(sec);
+
+	if (ts->power_status == SEC_TS_STATE_POWER_OFF) {
+		input_err(true, &ts->client->dev,
+			  "%s: [ERROR] Touch is stopped\n", __func__);
+		snprintf(buff, sizeof(buff), "%s", "TSP turned off");
+		goto err;
+	}
+
+	ret = ts->sec_ts_write(ts, SEC_TS_CMD_TOUCH_MODE_FOR_THRESHOLD,
+			       threshold, 1);
+	if (ret < 0) {
+		input_err(true, &ts->client->dev,
+			  "%s: threshold write type failed. ret: %d\n",
+			  __func__, ret);
+		snprintf(buff, sizeof(buff), "%s", "NG");
+		goto err;
+	}
+
+	ret = ts->sec_ts_read(ts, SEC_TS_CMD_TOUCH_THRESHOLD, threshold, 2);
+	if (ret < 0) {
+		input_err(true, &ts->client->dev,
+			  "%s: read threshold fail!\n", __func__);
+		snprintf(buff, sizeof(buff), "%s", "NG");
+		goto err;
+	}
+
+	input_info(true, &ts->client->dev, "0x%02X, 0x%02X\n",
+				threshold[0], threshold[1]);
+
+	snprintf(buff, sizeof(buff), "%d", (threshold[0] << 8) | threshold[1]);
+
+	sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
+	sec->cmd_state = SEC_CMD_STATUS_OK;
+	input_info(true, &ts->client->dev, "%s: %s\n", __func__, buff);
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+	return;
+err:
+	sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
+	sec->cmd_state = SEC_CMD_STATUS_NOT_APPLICABLE;
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+}
+
+static void module_off_master(void *device_data)
+{
+	struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data;
+	struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
+	char buff[3] = { 0 };
+	int ret = 0;
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, true);
+
+	ret = sec_ts_stop_device(ts);
+
+	if (ret == 0)
+		snprintf(buff, sizeof(buff), "%s", "OK");
+	else
+		snprintf(buff, sizeof(buff), "%s", "NG");
+
+	sec_cmd_set_default_result(sec);
+	sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
+	if (strncmp(buff, "OK", 2) == 0)
+		sec->cmd_state = SEC_CMD_STATUS_OK;
+	else
+		sec->cmd_state = SEC_CMD_STATUS_FAIL;
+	input_info(true, &ts->client->dev, "%s: %s\n", __func__, buff);
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+}
+
+static void module_on_master(void *device_data)
+{
+	struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data;
+	struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
+	char buff[3] = { 0 };
+	int ret = 0;
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, true);
+
+	ret = sec_ts_start_device(ts);
+
+/* TODO: check this for SPI case
+ *	if (ts->input_dev->disabled) {
+ *		sec_ts_set_lowpowermode(ts, TO_LOWPOWER_MODE);
+ *		ts->power_status = SEC_TS_STATE_LPM;
+ *	}
+ **/
+
+	if (ret == 0)
+		snprintf(buff, sizeof(buff), "%s", "OK");
+	else
+		snprintf(buff, sizeof(buff), "%s", "NG");
+
+	sec_cmd_set_default_result(sec);
+	sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
+	if (strncmp(buff, "OK", 2) == 0)
+		sec->cmd_state = SEC_CMD_STATUS_OK;
+	else
+		sec->cmd_state = SEC_CMD_STATUS_FAIL;
+
+	input_info(true, &ts->client->dev, "%s: %s\n", __func__, buff);
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+}
+
+static void get_chip_vendor(void *device_data)
+{
+	struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data;
+	struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
+	char buff[16] = { 0 };
+
+	strncpy(buff, "SEC", sizeof(buff));
+	sec_cmd_set_default_result(sec);
+	sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
+	sec->cmd_state = SEC_CMD_STATUS_OK;
+	input_info(true, &ts->client->dev, "%s: %s\n", __func__, buff);
+}
+
+static void get_chip_name(void *device_data)
+{
+	struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data;
+	struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
+	char buff[16] = { 0 };
+
+	if (ts->plat_data->img_version_of_ic[0] == 0x02)
+		strncpy(buff, "MC44", sizeof(buff));
+	else if (ts->plat_data->img_version_of_ic[0] == 0x05)
+		strncpy(buff, "A552", sizeof(buff));
+	else if (ts->plat_data->img_version_of_ic[0] == 0x09)
+		strncpy(buff, "Y661", sizeof(buff));
+	else if (ts->plat_data->img_version_of_ic[0] == 0x10)
+		strncpy(buff, "Y761", sizeof(buff));
+	else
+		strncpy(buff, "N/A", sizeof(buff));
+
+	sec_cmd_set_default_result(sec);
+	sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
+	sec->cmd_state = SEC_CMD_STATUS_OK;
+	input_info(true, &ts->client->dev, "%s: %s\n", __func__, buff);
+}
+
+static void set_mis_cal_spec(void *device_data)
+{
+	struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data;
+	struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
+	char buff[16] = { 0 };
+	char wreg[5] = { 0 };
+	int ret;
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, true);
+
+	sec_cmd_set_default_result(sec);
+
+	if (ts->plat_data->mis_cal_check == 0) {
+		input_err(true, &ts->client->dev,
+			  "%s: [ERROR] not support, %d\n", __func__);
+		goto NG;
+	} else if (ts->power_status == SEC_TS_STATE_POWER_OFF) {
+		input_err(true, &ts->client->dev,
+			  "%s: [ERROR] Touch is stopped\n", __func__);
+		goto NG;
+	} else {
+		if ((sec->cmd_param[0] < 0 || sec->cmd_param[0] > 255) ||
+			(sec->cmd_param[1] < 0 || sec->cmd_param[1] > 255) ||
+			(sec->cmd_param[2] < 0 || sec->cmd_param[2] > 255)) {
+			snprintf(buff, sizeof(buff), "%s", "NG");
+			goto NG;
+		} else {
+			wreg[0] = sec->cmd_param[0];
+			wreg[1] = sec->cmd_param[1];
+			wreg[2] = sec->cmd_param[2];
+
+			ret = ts->sec_ts_write(ts, SEC_TS_CMD_MIS_CAL_SPEC,
+					       wreg, 3);
+			if (ret < 0) {
+				input_err(true, &ts->client->dev,
+					  "%s: nvm write failed. ret: %d\n",
+					  __func__, ret);
+				goto NG;
+			} else {
+				input_info(true, &ts->client->dev,
+					   "%s: tx gap=%d, rx gap=%d, peak=%d\n",
+					   __func__, wreg[0], wreg[1], wreg[2]);
+				sec_ts_delay(20);
+			}
+		}
+	}
+
+	snprintf(buff, sizeof(buff), "%s", "OK");
+	sec->cmd_state = SEC_CMD_STATUS_OK;
+	sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
+	sec_cmd_set_cmd_exit(sec);
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+	return;
+
+NG:
+	snprintf(buff, sizeof(buff), "%s", "NG");
+	sec->cmd_state = SEC_CMD_STATUS_FAIL;
+	sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
+	sec_cmd_set_cmd_exit(sec);
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+	return;
+
+
+}
+
+/*
+ *	## Mis Cal result ##
+ *	FF : initial value in Firmware.
+ *	FD : Cal fail case
+ *	F4 : fail case (5F)
+ *	F3 : fail case (5E)
+ *	F2 : power off state
+ *	F1 : not support mis cal concept
+ *	F0 : initial value in fucntion
+ *	08 : Ambient Ambient condition check(PEAK) result 0 (PASS), 1(FAIL)
+ *	04 : Ambient Ambient condition check(DIFF MAX TX)
+ *	     result 0 (PASS), 1(FAIL)
+ *	02 : Ambient Ambient condition check(DIFF MAX RX)
+ *	     result 0 (PASS), 1(FAIL)
+ *	01 : Wet Wet mode result 0 (PASS), 1(FAIL)
+ *	00 : Pass
+ **/
+static void get_mis_cal_info(void *device_data)
+{
+	struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data;
+	struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
+	char buff[16] = { 0 };
+	char mis_cal_data = 0xF0;
+	char wreg[5] = { 0 };
+	int ret;
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, true);
+
+	sec_cmd_set_default_result(sec);
+
+	if (ts->plat_data->mis_cal_check == 0) {
+		input_err(true, &ts->client->dev,
+			  "%s: [ERROR] not support, %d\n", __func__);
+		mis_cal_data = 0xF1;
+		goto NG;
+	} else if (ts->power_status == SEC_TS_STATE_POWER_OFF) {
+		input_err(true, &ts->client->dev,
+			  "%s: [ERROR] Touch is stopped\n", __func__);
+		mis_cal_data = 0xF2;
+		goto NG;
+	} else {
+		ret = ts->sec_ts_read(ts, SEC_TS_CMD_MIS_CAL_READ,
+				      &mis_cal_data, 1);
+		if (ret < 0) {
+			input_err(true, &ts->client->dev,
+				  "%s: fail!, %d\n", __func__, ret);
+			mis_cal_data = 0xF3;
+			goto NG;
+		} else {
+			input_info(true, &ts->client->dev,
+				   "%s: miss cal data : %d\n",
+				   __func__, mis_cal_data);
+		}
+
+		ret = ts->sec_ts_read(ts, SEC_TS_CMD_MIS_CAL_SPEC, wreg, 3);
+		if (ret < 0) {
+			input_err(true, &ts->client->dev,
+				  "%s: fail!, %d\n", __func__, ret);
+			mis_cal_data = 0xF4;
+			goto NG;
+		} else {
+			input_info(true, &ts->client->dev,
+				"%s: miss cal spec : %d,%d,%d\n", __func__,
+				wreg[0], wreg[1], wreg[2]);
+		}
+	}
+
+	snprintf(buff, sizeof(buff), "%d,%d,%d,%d",
+		 mis_cal_data, wreg[0], wreg[1], wreg[2]);
+
+	sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
+	sec->cmd_state = SEC_CMD_STATUS_OK;
+	input_info(true, &ts->client->dev, "%s: %s\n", __func__, buff);
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+	return;
+
+NG:
+	snprintf(buff, sizeof(buff), "%d,%d,%d,%d", mis_cal_data, 0, 0, 0);
+	sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
+	sec->cmd_state = SEC_CMD_STATUS_FAIL;
+	input_info(true, &ts->client->dev, "%s: %s\n", __func__, buff);
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+}
+
+static void get_wet_mode(void *device_data)
+{
+	struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data;
+	struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
+	char buff[16] = { 0 };
+	char wet_mode_info = 0;
+	int ret;
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, true);
+
+	sec_cmd_set_default_result(sec);
+
+	ret = ts->sec_ts_read(ts, SEC_TS_CMD_WET_MODE, &wet_mode_info, 1);
+	if (ret < 0) {
+		input_err(true, &ts->client->dev,
+			  "%s: fail!, %d\n", __func__, ret);
+		goto NG;
+	}
+
+	snprintf(buff, sizeof(buff), "%d", wet_mode_info);
+	sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
+	sec->cmd_state = SEC_CMD_STATUS_OK;
+	input_info(true, &ts->client->dev, "%s: %s\n", __func__, buff);
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+	return;
+
+NG:
+	snprintf(buff, sizeof(buff), "NG");
+	sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
+	sec->cmd_state = SEC_CMD_STATUS_FAIL;
+	input_info(true, &ts->client->dev, "%s: %s\n", __func__, buff);
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+}
+
+static void get_x_num(void *device_data)
+{
+	struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data;
+	struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
+	char buff[16] = { 0 };
+
+	sec_cmd_set_default_result(sec);
+	snprintf(buff, sizeof(buff), "%d", ts->tx_count);
+	sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
+	sec->cmd_state = SEC_CMD_STATUS_OK;
+	input_info(true, &ts->client->dev, "%s: %s\n", __func__, buff);
+}
+
+static void get_y_num(void *device_data)
+{
+	struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data;
+	struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
+	char buff[16] = { 0 };
+
+	sec_cmd_set_default_result(sec);
+	snprintf(buff, sizeof(buff), "%d", ts->rx_count);
+	sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
+	sec->cmd_state = SEC_CMD_STATUS_OK;
+	input_info(true, &ts->client->dev, "%s: %s\n", __func__, buff);
+}
+
+static void get_x_cross_routing(void *device_data)
+{
+	struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data;
+	struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
+	char buff[16] = { 0 };
+
+	sec_cmd_set_default_result(sec);
+	snprintf(buff, sizeof(buff), "NG");
+	sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
+	sec->cmd_state = SEC_CMD_STATUS_OK;
+	input_info(true, &ts->client->dev, "%s: %s\n", __func__, buff);
+}
+
+static void get_y_cross_routing(void *device_data)
+{
+	struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data;
+	struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
+	char buff[16] = { 0 };
+	int ret;
+
+	sec_cmd_set_default_result(sec);
+
+	ret = strncmp(ts->plat_data->model_name, "G935", 4)
+			&& strncmp(ts->plat_data->model_name, "N930", 4);
+	if (ret == 0)
+		snprintf(buff, sizeof(buff), "13,14");
+	else
+		snprintf(buff, sizeof(buff), "NG");
+	sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
+	sec->cmd_state = SEC_CMD_STATUS_OK;
+	input_info(true, &ts->client->dev, "%s: %s\n", __func__, buff);
+}
+
+static void get_checksum_data(void *device_data)
+{
+	struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data;
+	struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
+	char buff[16] = { 0 };
+	char csum_result[4] = { 0 };
+	u8 cal_result;
+	u8 nv_result;
+	u8 temp;
+	u8 csum = 0;
+	int ret, i;
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, true);
+
+	sec_cmd_set_default_result(sec);
+	if (ts->power_status == SEC_TS_STATE_POWER_OFF) {
+		input_err(true, &ts->client->dev,
+			  "%s: [ERROR] Touch is stopped\n", __func__);
+		snprintf(buff, sizeof(buff), "%s", "TSP turned off");
+		goto err;
+	}
+
+	temp = DO_FW_CHECKSUM | DO_PARA_CHECKSUM;
+	ret = ts->sec_ts_write(ts, SEC_TS_CMD_GET_CHECKSUM, &temp, 1);
+	if (ret < 0) {
+		input_err(true, &ts->client->dev,
+			  "%s: send get_checksum_cmd fail!\n", __func__);
+		snprintf(buff, sizeof(buff), "%s", "SendCMDfail");
+		goto err;
+	}
+
+	sec_ts_delay(20);
+
+#ifdef I2C_INTERFACE
+	ret = ts->sec_ts_read_bulk(ts, csum_result, 4);
+#else
+	ret = ts->sec_ts_read(ts, SEC_TS_CMD_GET_CHECKSUM, csum_result, 4);
+#endif
+	if (ret < 0) {
+		input_err(true, &ts->client->dev,
+			  "%s: read get_checksum result fail!\n", __func__);
+		snprintf(buff, sizeof(buff), "%s", "ReadCSUMfail");
+		goto err;
+	}
+
+	nv_result = get_tsp_nvm_data(ts, SEC_TS_NVM_OFFSET_FAC_RESULT);
+	nv_result += get_tsp_nvm_data(ts, SEC_TS_NVM_OFFSET_CAL_COUNT);
+
+	cal_result = sec_ts_read_calibration_report(ts);
+
+	for (i = 0; i < 4; i++)
+		csum += csum_result[i];
+
+	csum += nv_result;
+	csum += cal_result;
+
+	csum = ~csum;
+
+	input_info(true, &ts->client->dev,
+		   "%s: checksum = %02X\n", __func__, csum);
+	snprintf(buff, sizeof(buff), "%02X", csum);
+	sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
+	sec->cmd_state = SEC_CMD_STATUS_OK;
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+	return;
+
+err:
+	sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
+	sec->cmd_state = SEC_CMD_STATUS_NOT_APPLICABLE;
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+}
+
+static void run_reference_read(void *device_data)
+{
+	struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data;
+	struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
+	struct sec_ts_test_mode mode;
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, true);
+
+	sec_cmd_set_default_result(sec);
+
+	memset(&mode, 0x00, sizeof(struct sec_ts_test_mode));
+	mode.type = TYPE_OFFSET_DATA_SEC;
+
+	sec_ts_read_raw_data(ts, sec, &mode);
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+}
+
+static void run_reference_read_all(void *device_data)
+{
+	struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data;
+	struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
+	struct sec_ts_test_mode mode;
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, true);
+
+	sec_cmd_set_default_result(sec);
+
+	memset(&mode, 0x00, sizeof(struct sec_ts_test_mode));
+	mode.type = TYPE_OFFSET_DATA_SEC;
+	mode.allnode = TEST_MODE_ALL_NODE;
+
+	sec_ts_read_raw_data(ts, sec, &mode);
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+}
+
+static void get_reference(void *device_data)
+{
+	struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data;
+	struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
+	char buff[SEC_CMD_STR_LEN] = { 0 };
+	short val = 0;
+	int node = 0;
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, true);
+
+	sec_cmd_set_default_result(sec);
+	if (ts->power_status == SEC_TS_STATE_POWER_OFF) {
+		input_err(true, &ts->client->dev,
+			  "%s: [ERROR] Touch is stopped\n", __func__);
+		snprintf(buff, sizeof(buff), "%s", "TSP turned off");
+		sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
+		sec->cmd_state = SEC_CMD_STATUS_NOT_APPLICABLE;
+
+		sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+		return;
+	}
+
+	node = sec_ts_check_index(ts);
+	if (node < 0) {
+		sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+		return;
+	}
+
+	val = ts->pFrame[node];
+	snprintf(buff, sizeof(buff), "%d", val);
+	sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
+	sec->cmd_state = SEC_CMD_STATUS_OK;
+	input_info(true, &ts->client->dev, "%s: %s\n", __func__, buff);
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+}
+
+static void run_rawcap_read(void *device_data)
+{
+	struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data;
+	struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
+	struct sec_ts_test_mode mode;
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, true);
+
+	sec_cmd_set_default_result(sec);
+
+	memset(&mode, 0x00, sizeof(struct sec_ts_test_mode));
+	mode.type = TYPE_OFFSET_DATA_SDC;
+#ifdef USE_SPEC_CHECK
+	mode.spec_check = SPEC_CHECK;
+#endif
+
+	sec_ts_read_raw_data(ts, sec, &mode);
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+}
+
+static void run_rawcap_read_all(void *device_data)
+{
+	struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data;
+	struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
+	struct sec_ts_test_mode mode;
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, true);
+
+	sec_cmd_set_default_result(sec);
+
+	memset(&mode, 0x00, sizeof(struct sec_ts_test_mode));
+	mode.type = TYPE_OFFSET_DATA_SDC;
+	mode.allnode = TEST_MODE_ALL_NODE;
+#ifdef USE_SPEC_CHECK
+	mode.spec_check = SPEC_CHECK;
+#endif
+
+	sec_ts_read_raw_data(ts, sec, &mode);
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+}
+
+/* run_rawcap_combo_read_all :
+ * Combine Cm/Cs offset test to merge
+ * run_rawcap_read_all() and run_self_rawcap_read_all().
+ */
+static void run_rawcap_combo_read_all(void *device_data)
+{
+	struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data;
+	struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
+	struct sec_ts_test_mode mode;
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, true);
+
+	sec_cmd_set_default_result(sec);
+
+	memset(&mode, 0x00, sizeof(struct sec_ts_test_mode));
+	mode.type = TYPE_OFFSET_DATA_SDC;
+	mode.frame_channel = TEST_MODE_READ_ALL;
+	mode.allnode = TEST_MODE_ALL_NODE;
+#ifdef USE_SPEC_CHECK
+	mode.spec_check = SPEC_CHECK;
+#endif
+
+	sec_ts_read_raw_data(ts, sec, &mode);
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+}
+
+int sec_ts_save_self_gap_raw_to_buffer(struct sec_ts_data *ts,
+		struct sec_ts_test_mode *mode, short *gap,
+		char *buff, const unsigned int buff_size)
+{
+	int i;
+	unsigned int buff_len = 0;
+
+	if (mode->spec_check == SPEC_NO_CHECK)
+		buff_len = scnprintf(buff + buff_len,
+				      buff_size - buff_len, "\n");
+	else if (mode->spec_check == SPEC_PASS) {
+		buff_len = scnprintf(buff + buff_len,
+				      buff_size - buff_len,
+				      "OK\n");
+	} else {	/* mode->spec_check == SPEC_FAIL) */
+		buff_len = scnprintf(buff + buff_len,
+				      buff_size - buff_len,
+				      "NG\n");
+	}
+
+	for (i = 0; i < (ts->tx_count - 1); i++) {
+		buff_len += scnprintf(buff + buff_len, buff_size - buff_len,
+				      "%6d,", gap[i]);
+	}
+
+	buff_len += scnprintf(buff + buff_len, buff_size - buff_len, "\n");
+
+	for (i = ts->tx_count; i < ts->tx_count + (ts->rx_count - 1); i++) {
+		buff_len += scnprintf(buff + buff_len, buff_size - buff_len,
+				      "%6d,\n", gap[i]);
+	}
+	return buff_len;
+}
+
+int sec_ts_save_mutual_gap_raw_to_buffer(struct sec_ts_data *ts,
+		struct sec_ts_test_mode *mode, short *gap_x, short *gap_y,
+		char *buff, const unsigned int buff_size)
+{
+	int i;
+	unsigned int buff_len = 0;
+	short dTmp;
+
+	if (mode->spec_check == SPEC_NO_CHECK)
+		buff_len = scnprintf(buff + buff_len,
+				      buff_size - buff_len, "\n");
+	else if (mode->spec_check == SPEC_PASS) {
+		buff_len = scnprintf(buff + buff_len,
+				      buff_size - buff_len,
+				      "OK\n");
+	} else {	/* mode->spec_check == SPEC_FAIL) */
+		buff_len = scnprintf(buff + buff_len,
+				      buff_size - buff_len,
+				      "NG\n");
+	}
+
+	for (i = 0; i < (ts->tx_count * ts->rx_count); i++) {
+
+		dTmp = (gap_x[i] > gap_y[i]) ? gap_x[i] : gap_y[i];
+		buff_len += scnprintf(buff + buff_len, buff_size - buff_len,
+					  "%3d,", dTmp);
+
+		if (i % ts->tx_count == (ts->tx_count - 1))
+			buff_len += scnprintf(buff + buff_len,
+					      buff_size - buff_len, "\n");
+	}
+	return buff_len;
+}
+/* run_rawcap_factory_read_all :
+ * Combine Cm/Cs offset and gap test to merge
+ * run_rawcap_read_all(), run_self_rawcap_read_all().
+ * run_rawcap_gap_read_all() and run_self_rawcap_gap_read_all().
+ */
+static void run_rawcap_factory_read_all(void *device_data)
+{
+	struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data;
+	struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
+	struct sec_ts_test_mode mode;
+
+	int ret_x, ret_y, ret;
+
+	unsigned int raw_buff_len = 0;
+	unsigned int gap_buff_len = 0;
+
+	short *gap, *gap_x, *gap_y = NULL;
+	char *gap_buff = NULL;
+	char *raw_buff = NULL;
+
+	const unsigned int raw_buff_size = ts->tx_count * ts->rx_count *
+		CMD_RESULT_WORD_LEN + (ts->tx_count + ts->rx_count) *
+		CMD_RESULT_WORD_LEN;
+
+	const unsigned int mutual_gap_buff_size =
+		ts->tx_count * ts->rx_count * 2;
+	const unsigned int mutual_buff_size = ts->tx_count * ts->rx_count * 2
+		* CMD_RESULT_WORD_LEN + 4 * CMD_RESULT_WORD_LEN;
+
+	const int self_gap_buff_size = (ts->tx_count - 1) + (ts->rx_count - 1);
+	const int self_buff_size = self_gap_buff_size * CMD_RESULT_WORD_LEN + 4;
+
+	const int gap_buff_size = mutual_buff_size + self_buff_size;
+
+	const unsigned int X_DIR = 0;
+	const unsigned int Y_DIR = 1;
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, true);
+	sec_cmd_set_default_result(sec);
+
+	memset(&mode, 0x00, sizeof(struct sec_ts_test_mode));
+
+	mode.type = TYPE_OFFSET_DATA_SDC;
+	mode.frame_channel = TEST_MODE_READ_ALL;
+	mode.allnode = TEST_MODE_ALL_NODE;
+#ifdef USE_SPEC_CHECK
+	mode.spec_check = SPEC_CHECK;
+#endif
+
+	raw_buff = kzalloc(raw_buff_size, GFP_KERNEL);
+	gap_x = kzalloc(mutual_gap_buff_size, GFP_KERNEL);
+	gap_y = kzalloc(mutual_gap_buff_size, GFP_KERNEL);
+	gap = kzalloc(self_gap_buff_size, GFP_KERNEL);
+	gap_buff = kzalloc(gap_buff_size, GFP_KERNEL);
+
+
+	if (!raw_buff || !gap_x || !gap_y || !gap || !gap_buff) {
+		sec->cmd_state = SEC_CMD_STATUS_FAIL;
+		sec_cmd_set_cmd_result(sec, "FAIL", 4);
+		goto ErrorAlloc;
+	}
+
+	ret = sec_ts_read_frame_and_channel(ts, mode.type, mode.min, mode.max,
+				&mode.spec_check);
+
+	if (ret < 0) {
+		sec_cmd_set_cmd_result(sec, "FAIL", 4);
+		sec->cmd_state = SEC_CMD_STATUS_FAIL;
+		goto ErrorAlloc;
+	}
+	ret_x = sec_ts_cm_spec_over_check(ts, gap_x, X_DIR);
+	ret_y = sec_ts_cm_spec_over_check(ts, gap_y, Y_DIR);
+
+	ret = sec_ts_cs_spec_over_check(ts, gap, ts->pFrameSS);
+
+#ifdef USE_SPEC_CHECK
+	if (mode.spec_check == SPEC_CHECK) {
+		if (0 != (ret_x + ret_y + ret))
+			mode.spec_check = SPEC_FAIL;
+	}
+#else
+	mode.spec_check = SPEC_PASS;
+#endif
+
+	raw_buff_len = sec_ts_save_mutual_raw_to_buffer(ts, sec,
+		&mode, raw_buff + raw_buff_len, raw_buff_size - raw_buff_len);
+	raw_buff_len += sec_ts_save_self_raw_to_buffer(ts, sec,
+		&mode, raw_buff + raw_buff_len, raw_buff_size - raw_buff_len);
+
+#ifdef USE_SPEC_CHECK
+		raw_buff_len += scnprintf(raw_buff + raw_buff_len,
+					raw_buff_size - raw_buff_len,
+					"%3d,%3d", mode->min[0], mode->max[0]);
+#else
+		raw_buff_len += scnprintf(raw_buff + raw_buff_len,
+					raw_buff_size - raw_buff_len,
+					"OK");
+#endif
+
+	sec_cmd_set_cmd_result(sec, raw_buff, raw_buff_len);
+
+	gap_buff_len = sec_ts_save_mutual_gap_raw_to_buffer(ts,
+		&mode, gap_x, gap_y, gap_buff + gap_buff_len,
+		gap_buff_size - gap_buff_len);
+	gap_buff_len += sec_ts_save_self_gap_raw_to_buffer(ts, &mode, gap,
+		gap_buff + gap_buff_len, gap_buff_size - gap_buff_len);
+
+	sec_cmd_set_cmd_result_2(sec, gap_buff, gap_buff_len);
+
+ErrorAlloc:
+
+	kfree(raw_buff);
+	kfree(gap);
+	kfree(gap_x);
+	kfree(gap_y);
+	kfree(gap_buff);
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+
+}
+
+/* run_rawcap_gap_combo_read_all :
+ * Combine Cm/Cs gap test to merge
+ * run_rawcap_gap_read_all() and run_self_rawcap_gap_read_all()
+ */
+static void run_rawcap_gap_combo_read_all(void *device_data)
+{
+	struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data;
+	struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
+	struct sec_ts_test_mode mode;
+
+	int ret_x, ret_y, ret;
+
+	unsigned int buff_len = 0;
+
+	short *gap, *gap_x, *gap_y = NULL;
+	char *buff = NULL;
+
+	const unsigned int mutual_gap_buff_size =
+		ts->tx_count * ts->rx_count * 2;
+	const unsigned int mutual_buff_size = ts->tx_count * ts->rx_count * 2
+		* CMD_RESULT_WORD_LEN + 4 * CMD_RESULT_WORD_LEN;
+
+	const int self_gap_buff_size = (ts->tx_count - 1) + (ts->rx_count - 1);
+	const int self_buff_size = self_gap_buff_size * CMD_RESULT_WORD_LEN + 4;
+
+	const int buff_size = mutual_buff_size + self_buff_size;
+
+	const unsigned int X_DIR = 0;
+	const unsigned int Y_DIR = 1;
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, true);
+	sec_cmd_set_default_result(sec);
+
+	memset(&mode, 0x00, sizeof(struct sec_ts_test_mode));
+
+	mode.type = TYPE_OFFSET_DATA_SDC;
+	mode.frame_channel = TEST_MODE_READ_ALL;
+	mode.allnode = TEST_MODE_ALL_NODE;
+#ifdef USE_SPEC_CHECK
+	mode.spec_check = SPEC_CHECK;
+#endif
+
+	gap_x = kzalloc(mutual_gap_buff_size, GFP_KERNEL);
+	gap_y = kzalloc(mutual_gap_buff_size, GFP_KERNEL);
+	gap = kzalloc(self_gap_buff_size, GFP_KERNEL);
+	buff = kzalloc(buff_size, GFP_KERNEL);
+
+
+	if (!gap_x || !gap_y || !gap || !buff) {
+		sec->cmd_state = SEC_CMD_STATUS_FAIL;
+		sec_cmd_set_cmd_result(sec, "FAIL", 4);
+		goto ErrorAlloc;
+	}
+
+	ret = sec_ts_read_frame_and_channel(ts, mode.type, mode.min, mode.max,
+				&mode.spec_check);
+
+	if (ret < 0) {
+		sec_cmd_set_cmd_result(sec, "FAIL", 4);
+		sec->cmd_state = SEC_CMD_STATUS_FAIL;
+		goto ErrorAlloc;
+	}
+
+	ret_x = sec_ts_cm_spec_over_check(ts, gap_x, X_DIR);
+	ret_y = sec_ts_cm_spec_over_check(ts, gap_y, Y_DIR);
+
+	ret = sec_ts_cs_spec_over_check(ts, gap, ts->pFrameSS);
+
+
+#ifdef USE_SPEC_CHECK
+	if (mode.spec_check == SPEC_CHECK) {
+		if (0 == (ret_x + ret_y + ret))
+			mode.spec_check = SPEC_PASS;
+		else
+			mode.spec_check = SPEC_FAIL;
+	}
+#else
+	mode.spec_check = SPEC_PASS;
+#endif
+
+	buff_len = sec_ts_save_mutual_gap_raw_to_buffer(ts, &mode, gap_x, gap_y,
+		buff + buff_len, buff_size - buff_len);
+	buff_len += sec_ts_save_self_gap_raw_to_buffer(ts, &mode, gap,
+		buff + buff_len, buff_size - buff_len);
+
+	sec_cmd_set_cmd_result(sec, buff, buff_len);
+
+ErrorAlloc:
+
+	kfree(gap);
+	kfree(gap_x);
+	kfree(gap_y);
+	kfree(buff);
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+
+}
+
+static void get_rawcap(void *device_data)
+{
+	struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data;
+	struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
+	char buff[SEC_CMD_STR_LEN] = { 0 };
+	short val = 0;
+	int node = 0;
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, true);
+
+	sec_cmd_set_default_result(sec);
+	if (ts->power_status == SEC_TS_STATE_POWER_OFF) {
+		input_err(true, &ts->client->dev,
+			  "%s: [ERROR] Touch is stopped\n", __func__);
+		snprintf(buff, sizeof(buff), "%s", "TSP turned off");
+		sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
+		sec->cmd_state = SEC_CMD_STATUS_NOT_APPLICABLE;
+		sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+		return;
+	}
+
+	node = sec_ts_check_index(ts);
+	if (node < 0) {
+		sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+		return;
+	}
+
+	val = ts->pFrame[node];
+	snprintf(buff, sizeof(buff), "%d", val);
+	sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
+	sec->cmd_state = SEC_CMD_STATUS_OK;
+	input_info(true, &ts->client->dev, "%s: %s\n", __func__, buff);
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+}
+
+static void run_rawcap_gap_read_all(void *device_data)
+{
+	struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data;
+	struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
+	struct sec_ts_test_mode mode;
+	int ret_x, ret_y;
+	short *gap_x, *gap_y;
+	char *buff;
+	const unsigned int buff_size = ts->tx_count * ts->rx_count * 2
+		* CMD_RESULT_WORD_LEN + 4 * CMD_RESULT_WORD_LEN;
+	const unsigned int readbytes = ts->tx_count * ts->rx_count * 2;
+	const unsigned int X_DIR = 0;
+	const unsigned int Y_DIR = 1;
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, true);
+
+	sec_cmd_set_default_result(sec);
+
+	memset(&mode, 0x00, sizeof(struct sec_ts_test_mode));
+
+	gap_x = kzalloc(readbytes, GFP_KERNEL);
+	gap_y = kzalloc(readbytes, GFP_KERNEL);
+	buff = kzalloc(buff_size, GFP_KERNEL);
+
+	if (!gap_x || !gap_y || !buff) {
+		sec->cmd_state = SEC_CMD_STATUS_FAIL;
+		sec_cmd_set_cmd_result(sec, "FAIL", 4);
+		goto ErrorAlloc;
+	}
+
+	mode.type = TYPE_OFFSET_DATA_SDC;
+	mode.allnode = TEST_MODE_ALL_NODE;
+#ifdef USE_SPEC_CHECK
+	mode.spec_check = SPEC_CHECK;
+#endif
+
+	sec_ts_read_frame(ts, mode.type, mode.min, mode.max,
+			  &mode.spec_check);
+
+	ret_x = sec_ts_cm_spec_over_check(ts, gap_x, X_DIR);
+
+	ret_y = sec_ts_cm_spec_over_check(ts, gap_y, Y_DIR);
+
+#ifdef USE_SPEC_CHECK
+	if (0 == (ret_x + ret_y)) {
+		mode.spec_check = SPEC_PASS;
+		sec->cmd_state = SEC_CMD_STATUS_OK;
+	} else {
+		mode.spec_check = SPEC_FAIL;
+		sec->cmd_state = SEC_CMD_STATUS_FAIL;
+	}
+#else
+	mode.spec_check = SPEC_PASS;
+#endif
+
+	sec_ts_save_mutual_gap_raw_to_buffer(ts, &mode, gap_x, gap_y,
+		buff, buff_size);
+
+	sec_cmd_set_cmd_result(sec, buff, buff_size);
+
+ErrorAlloc:
+	kfree(buff);
+	kfree(gap_y);
+	kfree(gap_x);
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+}
+
+static void run_rawcap_high_freq_read_all(void *device_data)
+{
+	struct sec_cmd_data *sec =
+		(struct sec_cmd_data *)device_data;
+	struct sec_ts_data *ts =
+		container_of(sec, struct sec_ts_data, sec);
+	struct sec_ts_test_mode mode;
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, true);
+
+	sec_cmd_set_default_result(sec);
+
+	memset(&mode, 0x00, sizeof(struct sec_ts_test_mode));
+	mode.type = TYPE_OFFSET_DATA_SDC_CM2;
+	mode.allnode = TEST_MODE_ALL_NODE;
+
+	sec_ts_read_raw_data(ts, sec, &mode);
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+}
+
+static void run_delta_read(void *device_data)
+{
+	struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data;
+	struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
+	struct sec_ts_test_mode mode;
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, true);
+
+	sec_cmd_set_default_result(sec);
+
+	memset(&mode, 0x00, sizeof(struct sec_ts_test_mode));
+	mode.type = TYPE_SIGNAL_DATA;
+
+	sec_ts_read_raw_data(ts, sec, &mode);
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+}
+
+static void run_delta_read_all(void *device_data)
+{
+	struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data;
+	struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
+	struct sec_ts_test_mode mode;
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, true);
+
+	sec_cmd_set_default_result(sec);
+
+	memset(&mode, 0x00, sizeof(struct sec_ts_test_mode));
+	mode.type = TYPE_SIGNAL_DATA;
+	mode.allnode = TEST_MODE_ALL_NODE;
+
+	sec_ts_read_raw_data(ts, sec, &mode);
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+}
+
+static void get_delta(void *device_data)
+{
+	struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data;
+	struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
+	char buff[SEC_CMD_STR_LEN] = { 0 };
+	short val = 0;
+	int node = 0;
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, true);
+
+	sec_cmd_set_default_result(sec);
+
+	if (ts->power_status == SEC_TS_STATE_POWER_OFF) {
+		input_err(true, &ts->client->dev,
+			  "%s: [ERROR] Touch is stopped\n", __func__);
+		snprintf(buff, sizeof(buff), "%s", "TSP turned off");
+		sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
+		sec->cmd_state = SEC_CMD_STATUS_NOT_APPLICABLE;
+
+		sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+		return;
+	}
+
+	node = sec_ts_check_index(ts);
+	if (node < 0) {
+		sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+		return;
+	}
+
+	val = ts->pFrame[node];
+	snprintf(buff, sizeof(buff), "%d", val);
+	sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
+	sec->cmd_state = SEC_CMD_STATUS_OK;
+	input_info(true, &ts->client->dev, "%s: %s\n", __func__, buff);
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+}
+
+static int sec_ts_read_frame_stdev(struct sec_ts_data *ts,
+	struct sec_cmd_data *sec, u8 type, short *min, short *max,
+	enum spec_check_type *spec_check, bool get_average_only)
+{
+	unsigned char *pRead = NULL;
+	short *pFrameAll = NULL;
+	int *pFrameAvg = NULL;
+	u64 *pFrameStd = NULL;
+	u8 inval_type = TYPE_INVALID_DATA;
+	int node_tot = 0;
+	int ret = 0;
+	int i = 0;
+	int j = 0;
+	int frame_len_byte = 0;
+	int frame_cnt = 0;
+	int frame_tot = 0;
+	int tmp = 0;
+
+	const unsigned int buff_size = ts->tx_count * ts->rx_count *
+					CMD_RESULT_WORD_LEN;
+	unsigned int buff_len = 0;
+	char *pBuff;
+
+	input_info(true, &ts->client->dev, "%s\n", __func__);
+
+	frame_tot = 100;
+
+	/* set data length, allocation buffer memory */
+
+	ret = -ENOMEM;
+	pBuff = kzalloc(buff_size, GFP_KERNEL);
+	if (!pBuff)
+		goto ErrorAlloc;
+
+	/* each node data 2bytes : 1frame bytes = node_tot * 2 */
+	node_tot = ts->rx_count * ts->tx_count;
+	frame_len_byte = node_tot * 2;
+
+	pRead = kzalloc(frame_len_byte, GFP_KERNEL);
+	if (!pRead)
+		goto ErrorAlloc;
+
+	/* memory whole frame data : 1frame bytes * total frame */
+	pFrameAll = kzalloc(frame_len_byte * frame_tot, GFP_KERNEL);
+	if (!pFrameAll)
+		goto ErrorAlloc;
+
+	/* float type : type size is double */
+	pFrameAvg = kzalloc(frame_len_byte * 2, GFP_KERNEL);
+	if (!pFrameAvg)
+		goto ErrorAlloc;
+
+	/* 64-bit to prevent overflow */
+	pFrameStd = kzalloc(frame_len_byte * 4, GFP_KERNEL);
+	if (!pFrameStd)
+		goto ErrorAlloc;
+
+	/* fix touch mode */
+	ret = sec_ts_fix_tmode(ts, TOUCH_SYSTEM_MODE_TOUCH,
+			       TOUCH_MODE_STATE_TOUCH);
+	if (ret < 0) {
+		input_err(true, &ts->client->dev, "%s: failed to fix tmode\n",
+				__func__);
+		goto ErrorAlloc;
+	}
+
+	/* set OPCODE and data type */
+	ret = ts->sec_ts_write(ts, SEC_TS_CMD_MUTU_RAW_TYPE, &type, 1);
+	if (ret < 0) {
+		input_err(true, &ts->client->dev,
+			  "%s: Set rawdata type failed\n", __func__);
+		goto ErrorDataType;
+	}
+
+	sec_ts_delay(50);
+
+	for (frame_cnt = 0; frame_cnt < frame_tot; frame_cnt++) {
+		/* read data */
+		ret = ts->sec_ts_read_heap(ts, SEC_TS_READ_TOUCH_RAWDATA,
+					pRead, frame_len_byte);
+		if (ret < 0) {
+			input_err(true, &ts->client->dev,
+				  "%s: read rawdata failed!\n", __func__);
+			goto ErrorRelease;
+		}
+
+		memset(ts->pFrame, 0x00, frame_len_byte);
+
+		for (i = 0; i < frame_len_byte; i += 2) {
+			ts->pFrame[i / 2] = pRead[i + 1] + (pRead[i] << 8);
+			pFrameAvg[i / 2] += ts->pFrame[i / 2];
+		}
+
+		memcpy(pFrameAll + (frame_len_byte * frame_cnt) / sizeof(short),
+		       ts->pFrame, frame_len_byte);
+	}
+
+	/* get total frame average of each node */
+	/* in the case of getting only average, *1000 not needed */
+	for (j = 0; j < node_tot; j++) {
+		if (!get_average_only)
+			pFrameAvg[j] = pFrameAvg[j] * 1000;
+		pFrameAvg[j] = pFrameAvg[j] / frame_tot;
+	}
+
+	input_info(true, &ts->client->dev, "%s: FrameAvg x 1000\n", __func__);
+
+	/* print frame average x 1000 of each node */
+	for (i = 0; i < ts->rx_count; i++) {
+		buff_len = scnprintf(pBuff, buff_size, "Rx%02d | ", i);
+
+		for (j = 0; j < ts->tx_count; j++) {
+			buff_len += scnprintf(pBuff + buff_len,
+					buff_size - buff_len,
+					" %6d",
+					pFrameAvg[(j * ts->rx_count) + i]);
+		}
+		input_info(true, &ts->client->dev, "%s\n", pBuff);
+	}
+
+	/* when only getting average, put average in
+	 * ts->pFrame and goto set cmd_result
+	 */
+	if (get_average_only) {
+		for (i = 0; i < ts->tx_count; i++) {
+			for (j = 0; j < ts->rx_count; j++) {
+				ts->pFrame[(j * ts->tx_count) + i] =
+					(short)(pFrameAvg[(i * ts->rx_count) +
+							  j]);
+			}
+		}
+		goto OnlyAverage;
+	}
+
+	/* get standard deviation */
+	for (i = 0; i < frame_tot; i++) {
+		for (j = 0; j < node_tot; j++) {
+			tmp = pFrameAll[node_tot * i + j] * 1000;
+			pFrameStd[j] = pFrameStd[j] +
+			    (tmp - pFrameAvg[j]) * (tmp - pFrameAvg[j]);
+		}
+	}
+
+	for (j = 0; j < node_tot; j++)
+		pFrameStd[j] = int_sqrt(pFrameStd[j] / frame_tot);
+
+	/* print standard deviation x 1000 of each node */
+	input_info(true, &ts->client->dev, "%s: FrameStd x 1000\n", __func__);
+
+	*min = *max = pFrameStd[0];
+
+	for (i = 0; i < ts->rx_count; i++) {
+		buff_len = scnprintf(pBuff, buff_size, "Rx%02d | ", i);
+
+		for (j = 0; j < ts->tx_count; j++) {
+			if (i > 0) {
+				if (pFrameStd[(j * ts->rx_count) + i] < *min)
+					*min =
+					    pFrameStd[(j * ts->rx_count) + i];
+
+				if (pFrameStd[(j * ts->rx_count) + i] > *max)
+					*max =
+					    pFrameStd[(j * ts->rx_count) + i];
+			}
+			buff_len += scnprintf(pBuff + buff_len,
+					buff_size - buff_len,
+					" %6d",
+					(int)pFrameStd[(j * ts->rx_count) + i]);
+		}
+		input_info(true, &ts->client->dev, "%s\n", pBuff);
+	}
+	// SQRT(VAR)
+
+	/* Rotate 90 degrees for readability */
+	for (i = 0; i < ts->tx_count; i++) {
+		for (j = 0; j < ts->rx_count; j++) {
+			if (pFrameStd[(i * ts->rx_count) + j] > 32767)
+				/* Reduce to short data type and allow high
+				 * values to saturate.
+				 */
+				ts->pFrame[(j * ts->tx_count) + i] = 32767;
+			else {
+				ts->pFrame[(j * ts->tx_count) + i] =
+					(short)(pFrameStd[(i * ts->rx_count) +
+						j]);
+			}
+		}
+	}
+
+#ifdef USE_SPEC_CHECK
+	if (*spec_check == SPEC_CHECK) {
+		int specover_count = 0;
+
+		for (i = 0; i < ts->tx_count; i++) {
+			for (j = 0; j < ts->rx_count; j++) {
+				if (ts->pFrame[(j * ts->tx_count) + i] >
+				    cm_stdev_max)
+					specover_count++;
+			}
+		}
+
+		if (specover_count == 0)
+			*spec_check = SPEC_PASS;
+		else
+			*spec_check = SPEC_FAIL;
+	}
+#else
+	*spec_check = SPEC_PASS;
+#endif
+
+	if (*spec_check == SPEC_PASS)
+		buff_len = scnprintf(pBuff, buff_size, "OK %d %d\n",
+				ts->rx_count, ts->tx_count);
+	else if (*spec_check == SPEC_FAIL)
+		buff_len = scnprintf(pBuff, buff_size, "NG %d %d\n",
+				ts->rx_count, ts->tx_count);
+	else
+		buff_len = scnprintf(pBuff, buff_size, "\n");
+
+	for (i = 0; i < node_tot; i++) {
+		buff_len += scnprintf(pBuff + buff_len, buff_size - buff_len,
+				      "%4d,", ts->pFrame[i]);
+
+		if (i % ts->tx_count == ts->tx_count - 1)
+			buff_len += scnprintf(pBuff + buff_len,
+					      buff_size - buff_len, "\n");
+	}
+
+	if (!sec)
+		goto ErrorRelease;
+
+	sec_cmd_set_cmd_result(sec, pBuff, buff_len);
+	sec->cmd_state = SEC_CMD_STATUS_OK;
+
+ErrorRelease:
+OnlyAverage:
+	/* release data monitory (unprepare AFE data memory) */
+	ret = ts->sec_ts_write(ts, SEC_TS_CMD_MUTU_RAW_TYPE, &inval_type,
+				   1);
+	if (ret < 0) {
+		input_err(true, &ts->client->dev,
+			  "%s: Set rawdata type failed\n", __func__);
+		goto ErrorAlloc;
+	}
+
+ErrorDataType:
+	/* release mode fix */
+	ret = sec_ts_release_tmode(ts);
+	if (ret < 0) {
+		input_err(true,
+			&ts->client->dev, "%s: failed to release tmode\n",
+			__func__);
+	}
+
+ErrorAlloc:
+	kfree(pFrameStd);
+	kfree(pFrameAvg);
+	kfree(pFrameAll);
+	kfree(pRead);
+	kfree(pBuff);
+
+	return ret;
+}
+
+static void run_rawdata_stdev_read(void *device_data)
+{
+	struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data;
+	struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
+	struct sec_ts_test_mode mode;
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, true);
+
+	sec_cmd_set_default_result(sec);
+
+	memset(&mode, 0x00, sizeof(struct sec_ts_test_mode));
+	mode.type = TYPE_REMV_AMB_DATA;
+#ifdef USE_SPEC_CHECK
+	mode.spec_check = SPEC_CHECK;
+#endif
+
+	sec_ts_read_frame_stdev(ts, sec, mode.type, mode.min, mode.max,
+				&mode.spec_check, false);
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+}
+
+static int sec_ts_read_frame_p2p(struct sec_ts_data *ts,
+		struct sec_cmd_data *sec, struct sec_ts_test_mode mode)
+{
+	const unsigned int frame_size = ts->rx_count * ts->tx_count * 2;
+	short *temp = NULL;
+	unsigned short readbytes;
+	int i;
+	int ret = -1;
+	char para = TO_TOUCH_MODE;
+	const unsigned int buff_size = ts->tx_count * ts->rx_count *
+					CMD_RESULT_WORD_LEN;
+	unsigned int buff_len = 0;
+	char *buff;
+	u8 result = 0x0;
+
+	buff = kzalloc(buff_size, GFP_KERNEL);
+	if (!buff)
+		goto ErrorAllocbuff;
+
+	if (ts->power_status == SEC_TS_STATE_POWER_OFF) {
+		input_err(true, &ts->client->dev,
+			  "%s: [ERROR] Touch is stopped\n", __func__);
+		goto ErrorPowerState;
+	}
+
+	memset(&mode, 0x00, sizeof(struct sec_ts_test_mode));
+
+	disable_irq(ts->client->irq);
+
+	ret = execute_p2ptest(ts);
+	if (ret < 0) {
+		input_err(true, &ts->client->dev, "%s: P2P test failed\n",
+			  __func__);
+		goto ErrorP2PTest;
+	}
+
+	/* get min data */
+	mode.type = TYPE_NOI_P2P_MIN;
+#ifdef USE_SPEC_CHECK
+	mode.spec_check = SPEC_CHECK;
+#endif
+	sec_ts_read_frame(ts, mode.type, mode.min, mode.max,
+			  &mode.spec_check);
+	if (mode.spec_check == SPEC_FAIL)
+		result |= 0x1;
+
+	readbytes = ts->rx_count * ts->tx_count;
+
+	/* 2 bytes for each node data */
+	temp = kzalloc(frame_size, GFP_KERNEL);
+	if (!temp)
+		goto ErrorAlloctemp;
+
+	memcpy(temp, ts->pFrame, frame_size);
+	memset(ts->pFrame, 0x00, frame_size);
+
+	/* get max data */
+	mode.type = TYPE_NOI_P2P_MAX;
+#ifdef USE_SPEC_CHECK
+	mode.spec_check = SPEC_CHECK;
+#endif
+	sec_ts_read_frame(ts, mode.type, mode.min, mode.max,
+			  &mode.spec_check);
+	if (mode.spec_check == SPEC_FAIL)
+		result |= 0x2;
+
+	for (i = 0; i < readbytes; i++) {
+		/* get p2p by subtract min from max data */
+		ts->pFrame[i] = ts->pFrame[i] - temp[i];
+#ifdef USE_SPEC_CHECK
+		if (ts->pFrame[i] > noi_mm)
+			result |= 0x4;
+#endif
+	}
+
+	if (result != 0x0)
+		buff_len += scnprintf(buff + buff_len, buff_size - buff_len,
+				      "NG\n");
+	else
+		buff_len += scnprintf(buff + buff_len, buff_size - buff_len,
+				      "OK\n");
+
+	for (i = 0; i < readbytes; i++) {
+		buff_len += scnprintf(buff + buff_len, buff_size - buff_len,
+				      "%3d,", ts->pFrame[i]);
+		if (i % ts->tx_count == (ts->tx_count - 1))
+			buff_len += scnprintf(buff + buff_len,
+					      buff_size - buff_len, "\n");
+	}
+
+	if (sec) {
+		sec_cmd_set_cmd_result(sec, buff, buff_len);
+		sec->cmd_state = SEC_CMD_STATUS_OK;
+	}
+
+	kfree(temp);
+ErrorAlloctemp:
+ErrorP2PTest:
+	ret = ts->sec_ts_write(ts, SEC_TS_CMD_SET_POWER_MODE, &para, 1);
+	if (ret < 0)
+		input_err(true, &ts->client->dev, "%s: Set powermode failed\n",
+			  __func__);
+
+	enable_irq(ts->client->irq);
+ErrorPowerState:
+	kfree(buff);
+ErrorAllocbuff:
+
+	if (sec && ret < 0) {
+		sec_cmd_set_cmd_result(sec, "NG", 3);
+		sec->cmd_state = SEC_CMD_STATUS_FAIL;
+	}
+
+	return ret;
+}
+
+static void run_rawdata_p2p_read_all(void *device_data)
+{
+	struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data;
+	struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
+	struct sec_ts_test_mode mode;
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, true);
+
+	sec_cmd_set_default_result(sec);
+
+	memset(&mode, 0x00, sizeof(struct sec_ts_test_mode));
+
+	sec_ts_read_frame_p2p(ts, sec, mode);
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+}
+
+/* self reference : send TX power in TX channel, receive in TX channel */
+static void run_self_reference_read(void *device_data)
+{
+	struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data;
+	struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
+	struct sec_ts_test_mode mode;
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, true);
+
+	sec_cmd_set_default_result(sec);
+
+	memset(&mode, 0x00, sizeof(struct sec_ts_test_mode));
+	mode.type = TYPE_OFFSET_DATA_SEC;
+	mode.frame_channel = TEST_MODE_READ_CHANNEL;
+
+	sec_ts_read_raw_data(ts, sec, &mode);
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+}
+
+static void run_self_reference_read_all(void *device_data)
+{
+	struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data;
+	struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
+	struct sec_ts_test_mode mode;
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, true);
+
+	sec_cmd_set_default_result(sec);
+
+	memset(&mode, 0x00, sizeof(struct sec_ts_test_mode));
+	mode.type = TYPE_OFFSET_DATA_SEC;
+	mode.frame_channel = TEST_MODE_READ_CHANNEL;
+	mode.allnode = TEST_MODE_ALL_NODE;
+
+	sec_ts_read_raw_data(ts, sec, &mode);
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+}
+
+static void run_self_rawcap_read(void *device_data)
+{
+	struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data;
+	struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
+	struct sec_ts_test_mode mode;
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, true);
+
+	sec_cmd_set_default_result(sec);
+
+	memset(&mode, 0x00, sizeof(struct sec_ts_test_mode));
+	mode.type = TYPE_OFFSET_DATA_SDC;
+	mode.frame_channel = TEST_MODE_READ_CHANNEL;
+#ifdef USE_SPEC_CHECK
+	mode.spec_check = SPEC_CHECK;
+#endif
+
+	sec_ts_read_raw_data(ts, sec, &mode);
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+}
+
+static void run_self_rawcap_read_all(void *device_data)
+{
+	struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data;
+	struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
+	struct sec_ts_test_mode mode;
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, true);
+
+	sec_cmd_set_default_result(sec);
+
+	memset(&mode, 0x00, sizeof(struct sec_ts_test_mode));
+	mode.type = TYPE_OFFSET_DATA_SDC;
+	mode.frame_channel = TEST_MODE_READ_CHANNEL;
+	mode.allnode = TEST_MODE_ALL_NODE;
+#ifdef USE_SPEC_CHECK
+	mode.spec_check = SPEC_CHECK;
+#endif
+
+	sec_ts_read_raw_data(ts, sec, &mode);
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+}
+
+static void run_self_rawcap_gap_read_all(void *device_data)
+{
+	struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data;
+	struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
+	struct sec_ts_test_mode mode;
+	int ret = 0;
+	char *buff = NULL;
+	short *gap = NULL;
+	const int gap_buff_size = (ts->tx_count - 1) + (ts->rx_count - 1);
+	const int buff_size = gap_buff_size * CMD_RESULT_WORD_LEN + 4;
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, true);
+
+	sec_cmd_set_default_result(sec);
+
+	memset(&mode, 0x00, sizeof(struct sec_ts_test_mode));
+	mode.type = TYPE_OFFSET_DATA_SDC;
+	mode.frame_channel = TEST_MODE_READ_CHANNEL;
+	mode.allnode = TEST_MODE_ALL_NODE;
+#ifdef USE_SPEC_CHECK
+	mode.spec_check = SPEC_CHECK;
+#endif
+
+	gap = kzalloc(gap_buff_size, GFP_KERNEL);
+	buff = kzalloc(buff_size, GFP_KERNEL);
+	if (!gap || !buff) {
+		sec->cmd_state = SEC_CMD_STATUS_FAIL;
+		sec_cmd_set_cmd_result(sec, "FAIL", 4);
+		goto ErrorAlloc;
+	}
+
+	sec_ts_read_channel(ts, mode.type, mode.min, mode.max,
+			    &mode.spec_check);
+
+	/* ret is number of spec over channel */
+	ret = sec_ts_cs_spec_over_check(ts, gap, ts->pFrame);
+
+#ifdef USE_SPEC_CHECK
+	if (ret == 0) {
+		mode.spec_check = SPEC_PASS;
+		sec->cmd_state = SEC_CMD_STATUS_OK;
+	} else {
+		mode.spec_check = SPEC_FAIL;
+		sec->cmd_state = SEC_CMD_STATUS_FAIL;
+	}
+#else
+	mode.spec_check = SPEC_PASS;
+#endif
+
+	sec_ts_save_self_gap_raw_to_buffer(ts, &mode, gap,
+		buff, buff_size);
+
+	sec_cmd_set_cmd_result(sec, buff, buff_size);
+
+ErrorAlloc:
+	kfree(buff);
+	kfree(gap);
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+}
+
+static void run_self_delta_read(void *device_data)
+{
+	struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data;
+	struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
+	struct sec_ts_test_mode mode;
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, true);
+
+	sec_cmd_set_default_result(sec);
+
+	memset(&mode, 0x00, sizeof(struct sec_ts_test_mode));
+	mode.type = TYPE_SIGNAL_DATA;
+	mode.frame_channel = TEST_MODE_READ_CHANNEL;
+
+	sec_ts_read_raw_data(ts, sec, &mode);
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+}
+
+static void run_self_delta_read_all(void *device_data)
+{
+	struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data;
+	struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
+	struct sec_ts_test_mode mode;
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, true);
+
+	sec_cmd_set_default_result(sec);
+
+	memset(&mode, 0x00, sizeof(struct sec_ts_test_mode));
+	mode.type = TYPE_SIGNAL_DATA;
+	mode.frame_channel = TEST_MODE_READ_CHANNEL;
+	mode.allnode = TEST_MODE_ALL_NODE;
+
+	sec_ts_read_raw_data(ts, sec, &mode);
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+}
+
+/* Use TSP NV area
+ * buff[0] : offset from user NVM storage
+ * buff[1] : length of stroed data - 1 (ex. using 1byte, value is  1 - 1 = 0)
+ * buff[2] : write data
+ * buff[..] : cont.
+ */
+void set_tsp_nvm_data_clear(struct sec_ts_data *ts, u8 offset)
+{
+	char buff[4] = { 0 };
+	int ret;
+
+	input_info(true, &ts->client->dev, "%s\n", __func__);
+
+	buff[0] = offset;
+
+	ret = ts->sec_ts_write(ts, SEC_TS_CMD_NVM, buff, 3);
+	if (ret < 0)
+		input_err(true, &ts->client->dev,
+			  "%s: nvm write failed. ret: %d\n", __func__, ret);
+
+	sec_ts_delay(20);
+}
+
+int get_tsp_nvm_data(struct sec_ts_data *ts, u8 offset)
+{
+	char buff[2] = { 0 };
+	int ret;
+
+	/* SENSE OFF -> CELAR EVENT STACK -> READ NV -> SENSE ON */
+	ret = ts->sec_ts_write(ts, SEC_TS_CMD_SENSE_OFF, NULL, 0);
+	if (ret < 0) {
+		input_err(true, &ts->client->dev,
+			  "%s: fail to write Sense_off\n", __func__);
+		goto out_nvm;
+	}
+
+	input_dbg(true, &ts->client->dev, "%s: SENSE OFF\n", __func__);
+
+	sec_ts_delay(100);
+
+	ret = ts->sec_ts_write(ts, SEC_TS_CMD_CLEAR_EVENT_STACK, NULL, 0);
+	if (ret < 0) {
+		input_err(true, &ts->client->dev,
+			  "%s: write clear event failed\n", __func__);
+		goto out_nvm;
+	}
+
+	input_dbg(true, &ts->client->dev, "%s: CLEAR EVENT STACK\n", __func__);
+
+	sec_ts_delay(100);
+
+	sec_ts_locked_release_all_finger(ts);
+
+	/* send NV data using command
+	 * Use TSP NV area : in this model, use only one byte
+	 * buff[0] : offset from user NVM storage
+	 * buff[1] : length of stroed data - 1 (ex. using 1byte,
+	 *           value is  1 - 1 = 0)
+	 **/
+	memset(buff, 0x00, 2);
+	buff[0] = offset;
+	ret = ts->sec_ts_write(ts, SEC_TS_CMD_NVM, buff, 2);
+	if (ret < 0) {
+		input_err(true, &ts->client->dev,
+			"%s: nvm send command failed. ret: %d\n",
+			__func__, ret);
+		goto out_nvm;
+	}
+
+	sec_ts_delay(20);
+
+	/* read NV data
+	 * Use TSP NV area : in this model, use only one byte
+	 */
+#ifdef I2C_INTERFACE
+	ret = ts->sec_ts_read_bulk(ts, buff, 1);
+#else
+	ret = ts->sec_ts_read(ts, SEC_TS_CMD_NVM, buff, 1);
+#endif
+	if (ret < 0) {
+		input_err(true, &ts->client->dev,
+			"%s: nvm send command failed. ret: %d\n",
+			__func__, ret);
+		goto out_nvm;
+	}
+
+	input_info(true, &ts->client->dev,
+		   "%s: offset: %u data: %02X\n", __func__, offset, buff[0]);
+
+out_nvm:
+	ret = ts->sec_ts_write(ts, SEC_TS_CMD_SENSE_ON, NULL, 0);
+	if (ret < 0)
+		input_err(true, &ts->client->dev,
+			  "%s: fail to write Sense_on\n", __func__);
+
+	input_dbg(true, &ts->client->dev, "%s: SENSE ON\n", __func__);
+
+	return buff[0];
+}
+
+int get_tsp_nvm_data_by_size(struct sec_ts_data *ts, u8 offset,
+			     int length, u8 *data)
+{
+	char *buff = NULL;
+	int ret;
+
+	buff = kzalloc(length, GFP_KERNEL);
+	if (!buff)
+		return -ENOMEM;
+
+	input_info(true, &ts->client->dev,
+		   "%s: offset: %u, length: %d, size: %d\n",
+		   __func__, offset, length, sizeof(data));
+
+	/* SENSE OFF -> CELAR EVENT STACK -> READ NV -> SENSE ON */
+	ret = ts->sec_ts_write(ts, SEC_TS_CMD_SENSE_OFF, NULL, 0);
+	if (ret < 0) {
+		input_err(true, &ts->client->dev,
+			  "%s: fail to write Sense_off\n", __func__);
+		goto out_nvm;
+	}
+
+	input_dbg(true, &ts->client->dev, "%s: SENSE OFF\n", __func__);
+
+	sec_ts_delay(100);
+
+	ret = ts->sec_ts_write(ts, SEC_TS_CMD_CLEAR_EVENT_STACK, NULL, 0);
+	if (ret < 0) {
+		input_err(true, &ts->client->dev,
+			  "%s: write clear event failed\n", __func__);
+		goto out_nvm;
+	}
+
+	input_dbg(true, &ts->client->dev, "%s: CLEAR EVENT STACK\n", __func__);
+
+	sec_ts_delay(100);
+
+	sec_ts_locked_release_all_finger(ts);
+
+	/* send NV data using command
+	 * Use TSP NV area : in this model, use only one byte
+	 * buff[0] : offset from user NVM storage
+	 * buff[1] : length of stroed data - 1 (ex. using 1byte,
+	 *           value is  1 - 1 = 0)
+	 **/
+	memset(buff, 0x00, 2);
+	buff[0] = offset;
+	buff[1] = length - 1;
+	ret = ts->sec_ts_write(ts, SEC_TS_CMD_NVM, buff, 2);
+	if (ret < 0) {
+		input_err(true, &ts->client->dev,
+			"%s: nvm send command failed. ret: %d\n",
+			__func__, ret);
+		goto out_nvm;
+	}
+
+	sec_ts_delay(20);
+
+	/* read NV data
+	 * Use TSP NV area : in this model, use only one byte
+	 */
+#ifdef I2C_INTERFACE
+	ret = ts->sec_ts_read_bulk_heap(ts, buff, length);
+#else
+	ret = ts->sec_ts_read(ts, SEC_TS_CMD_NVM, buff, length);
+#endif
+	if (ret < 0) {
+		input_err(true, &ts->client->dev,
+			"%s: nvm send command failed. ret: %d\n",
+			__func__, ret);
+		goto out_nvm;
+	}
+
+	memcpy(data, buff, length);
+
+out_nvm:
+	ret = ts->sec_ts_write(ts, SEC_TS_CMD_SENSE_ON, NULL, 0);
+	if (ret < 0)
+		input_err(true, &ts->client->dev,
+			  "%s: fail to write Sense_on\n", __func__);
+
+	input_dbg(true, &ts->client->dev, "%s: SENSE ON\n", __func__);
+
+	kfree(buff);
+
+	return ret;
+}
+
+#ifdef PAT_CONTROL
+void set_pat_magic_number(struct sec_ts_data *ts)
+{
+	char buff[4] = { 0 };
+	int ret;
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, true);
+
+	input_info(true, &ts->client->dev, "%s\n", __func__);
+	buff[0] = SEC_TS_NVM_OFFSET_CAL_COUNT;
+	buff[1] = 0;
+	buff[2] = PAT_MAGIC_NUMBER;
+
+	input_info(true, &ts->client->dev, "%s: %02X\n", __func__, buff[2]);
+
+	ret = ts->sec_ts_write(ts, SEC_TS_CMD_NVM, buff, 3);
+	if (ret < 0) {
+		input_err(true, &ts->client->dev,
+			"%s: nvm write failed. ret: %d\n", __func__, ret);
+	}
+	sec_ts_delay(20);
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+}
+#endif
+
+
+/* FACTORY TEST RESULT SAVING FUNCTION
+ * bit 3 ~ 0 : OCTA Assy
+ * bit 7 ~ 4 : OCTA module
+ * param[0] : OCTA modue(1) / OCTA Assy(2)
+ * param[1] : TEST NONE(0) / TEST FAIL(1) / TEST PASS(2) : 2 bit
+ */
+
+#define TEST_OCTA_MODULE	1
+#define TEST_OCTA_ASSAY		2
+
+#define TEST_OCTA_NONE		0
+#define TEST_OCTA_FAIL		1
+#define TEST_OCTA_PASS		2
+
+static void set_tsp_test_result(void *device_data)
+{
+	struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data;
+	struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
+	struct sec_ts_test_result *result;
+	char buff[SEC_CMD_STR_LEN] = { 0 };
+	char r_data[1] = { 0 };
+	int ret = 0;
+
+	input_info(true, &ts->client->dev, "%s\n", __func__);
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, true);
+
+	sec_cmd_set_default_result(sec);
+
+	if (ts->power_status == SEC_TS_STATE_POWER_OFF) {
+		input_err(true, &ts->client->dev,
+			  "%s: [ERROR] Touch is stopped\n", __func__);
+		snprintf(buff, sizeof(buff), "%s", "TSP_truned off");
+		sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
+		sec->cmd_state = SEC_CMD_STATUS_NOT_APPLICABLE;
+		sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+		return;
+	}
+
+	r_data[0] = get_tsp_nvm_data(ts, SEC_TS_NVM_OFFSET_FAC_RESULT);
+	if (r_data[0] == 0xFF)
+		r_data[0] = 0;
+
+	result = (struct sec_ts_test_result *)r_data;
+
+	if (sec->cmd_param[0] == TEST_OCTA_ASSAY) {
+		result->assy_result = sec->cmd_param[1];
+		if (result->assy_count < 3)
+			result->assy_count++;
+	}
+
+	if (sec->cmd_param[0] == TEST_OCTA_MODULE) {
+		result->module_result = sec->cmd_param[1];
+		if (result->module_count < 3)
+			result->module_count++;
+	}
+
+	input_info(true, &ts->client->dev,
+		"%s: %d, %d, %d, %d, 0x%X\n", __func__,
+		result->module_result, result->module_count,
+		result->assy_result, result->assy_count, result->data[0]);
+
+	/* Use TSP NV area : in this model, use only one byte
+	 * buff[0] : offset from user NVM storage
+	 * buff[1] : length of stroed data - 1 (ex. using 1byte,
+	 *           value is  1 - 1 = 0)
+	 * buff[2] : write data
+	 **/
+	memset(buff, 0x00, SEC_CMD_STR_LEN);
+	buff[2] = *result->data;
+
+	input_info(true, &ts->client->dev, "%s: command (1)%X, (2)%X: %X\n",
+		__func__, sec->cmd_param[0], sec->cmd_param[1], buff[2]);
+
+	ret = ts->sec_ts_write(ts, SEC_TS_CMD_NVM, buff, 3);
+	if (ret < 0)
+		input_err(true, &ts->client->dev,
+			  "%s: nvm write failed. ret: %d\n", __func__, ret);
+
+	sec_ts_delay(20);
+
+	ts->nv = get_tsp_nvm_data(ts, SEC_TS_NVM_OFFSET_FAC_RESULT);
+
+	snprintf(buff, sizeof(buff), "OK");
+	sec_cmd_set_cmd_result(sec, buff, strlen(buff));
+	sec->cmd_state = SEC_CMD_STATUS_OK;
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+}
+
+static void get_tsp_test_result(void *device_data)
+{
+	struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data;
+	struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
+	char buff[SEC_CMD_STR_LEN] = { 0 };
+	struct sec_ts_test_result *result;
+
+	input_info(true, &ts->client->dev, "%s\n", __func__);
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, true);
+
+	sec_cmd_set_default_result(sec);
+
+	if (ts->power_status == SEC_TS_STATE_POWER_OFF) {
+		input_err(true, &ts->client->dev,
+			  "%s: [ERROR] Touch is stopped\n", __func__);
+		snprintf(buff, sizeof(buff), "%s", "TSP_truned off");
+		sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
+		sec->cmd_state = SEC_CMD_STATUS_NOT_APPLICABLE;
+
+		sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+		return;
+	}
+
+	memset(buff, 0x00, SEC_CMD_STR_LEN);
+	buff[0] = get_tsp_nvm_data(ts, SEC_TS_NVM_OFFSET_FAC_RESULT);
+	if (buff[0] == 0xFF) {
+		set_tsp_nvm_data_clear(ts, SEC_TS_NVM_OFFSET_FAC_RESULT);
+		buff[0] = 0;
+	}
+
+	ts->nv = buff[0];
+
+	result = (struct sec_ts_test_result *)buff;
+
+	input_info(true, &ts->client->dev,
+			 "%s: [0x%X][0x%X] M: %d, M: %d, A: %d, A: %d\n",
+			__func__, *result->data, buff[0],
+			result->module_result, result->module_count,
+			result->assy_result, result->assy_count);
+
+	snprintf(buff, sizeof(buff), "M: %s, M: %d, A: %s, A: %d",
+			result->module_result == 0 ? "NONE" :
+			result->module_result == 1 ? "FAIL" : "PASS",
+			result->module_count,
+			result->assy_result == 0 ? "NONE" :
+			result->assy_result == 1 ? "FAIL" : "PASS",
+			result->assy_count);
+
+	sec_cmd_set_cmd_result(sec, buff, strlen(buff));
+	sec->cmd_state = SEC_CMD_STATUS_OK;
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+}
+
+static void increase_disassemble_count(void *device_data)
+{
+	struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data;
+	struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
+	char buff[3] = { 0 };
+	int ret = 0;
+
+	input_info(true, &ts->client->dev, "%s\n", __func__);
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, true);
+
+	sec_cmd_set_default_result(sec);
+
+	if (ts->power_status == SEC_TS_STATE_POWER_OFF) {
+		input_err(true, &ts->client->dev,
+			  "%s: [ERROR] Touch is stopped\n", __func__);
+		snprintf(buff, sizeof(buff), "%s", "TSP_truned off");
+		sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
+		sec->cmd_state = SEC_CMD_STATUS_NOT_APPLICABLE;
+
+		sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+		return;
+	}
+
+	buff[2] = get_tsp_nvm_data(ts, SEC_TS_NVM_OFFSET_DISASSEMBLE_COUNT);
+
+	input_info(true, &ts->client->dev,
+		   "%s: disassemble count is #1 %d\n", __func__, buff[2]);
+
+	if (buff[2] == 0xFF)
+		buff[2] = 0;
+
+	if (buff[2] < 0xFE)
+		buff[2]++;
+
+	/* Use TSP NV area : in this model, use only one byte
+	 * buff[0] : offset from user NVM storage
+	 * buff[1] : length of stroed data - 1 (ex. using 1byte,
+	 *           value is  1 - 1 = 0)
+	 * buff[2] : write data
+	 **/
+	buff[0] = SEC_TS_NVM_OFFSET_DISASSEMBLE_COUNT;
+	buff[1] = 0;
+
+	ret = ts->sec_ts_write(ts, SEC_TS_CMD_NVM, buff, 3);
+	if (ret < 0)
+		input_err(true, &ts->client->dev,
+			  "%s: nvm write failed. ret: %d\n", __func__, ret);
+
+	sec_ts_delay(20);
+
+	memset(buff, 0x00, 3);
+	buff[0] = get_tsp_nvm_data(ts, SEC_TS_NVM_OFFSET_DISASSEMBLE_COUNT);
+	input_info(true, &ts->client->dev,
+		   "%s: check disassemble count: %d\n", __func__, buff[0]);
+
+	snprintf(buff, sizeof(buff), "OK");
+	sec_cmd_set_cmd_result(sec, buff, strlen(buff));
+	sec->cmd_state = SEC_CMD_STATUS_OK;
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+}
+
+static void get_disassemble_count(void *device_data)
+{
+	struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data;
+	struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
+	char buff[SEC_CMD_STR_LEN] = { 0 };
+
+	input_info(true, &ts->client->dev, "%s\n", __func__);
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, true);
+
+	sec_cmd_set_default_result(sec);
+
+	if (ts->power_status == SEC_TS_STATE_POWER_OFF) {
+		input_err(true, &ts->client->dev,
+			  "%s: [ERROR] Touch is stopped\n", __func__);
+		snprintf(buff, sizeof(buff), "%s", "TSP_truned off");
+		sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
+		sec->cmd_state = SEC_CMD_STATUS_NOT_APPLICABLE;
+
+		sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+		return;
+	}
+
+	memset(buff, 0x00, SEC_CMD_STR_LEN);
+	buff[0] = get_tsp_nvm_data(ts, SEC_TS_NVM_OFFSET_DISASSEMBLE_COUNT);
+	if (buff[0] == 0xFF) {
+		set_tsp_nvm_data_clear(ts, SEC_TS_NVM_OFFSET_DISASSEMBLE_COUNT);
+		buff[0] = 0;
+	}
+
+	input_info(true, &ts->client->dev,
+		   "%s: read disassemble count: %d\n", __func__, buff[0]);
+
+	snprintf(buff, sizeof(buff), "%d", buff[0]);
+
+	sec_cmd_set_cmd_result(sec, buff, strlen(buff));
+	sec->cmd_state = SEC_CMD_STATUS_OK;
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+}
+
+#define GLOVE_MODE_EN		(1 << 0)
+#define CLEAR_COVER_EN		(1 << 1)
+#define FAST_GLOVE_MODE_EN	(1 << 2)
+
+static void glove_mode(void *device_data)
+{
+	struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data;
+	struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
+	char buff[SEC_CMD_STR_LEN] = { 0 };
+	int glove_mode_enables = 0;
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, true);
+
+	sec_cmd_set_default_result(sec);
+
+	if (sec->cmd_param[0] < 0 || sec->cmd_param[0] > 1) {
+		snprintf(buff, sizeof(buff), "NG");
+		sec->cmd_state = SEC_CMD_STATUS_FAIL;
+	} else {
+		int retval;
+
+		if (sec->cmd_param[0])
+			glove_mode_enables |= GLOVE_MODE_EN;
+		else
+			glove_mode_enables &= ~(GLOVE_MODE_EN);
+
+		retval = sec_ts_glove_mode_enables(ts, glove_mode_enables);
+
+		if (retval < 0) {
+			input_err(true, &ts->client->dev,
+				"%s: failed, retval = %d\n", __func__, retval);
+			snprintf(buff, sizeof(buff), "NG");
+			sec->cmd_state = SEC_CMD_STATUS_FAIL;
+		} else {
+			snprintf(buff, sizeof(buff), "OK");
+			sec->cmd_state = SEC_CMD_STATUS_OK;
+		}
+	}
+
+	sec_cmd_set_cmd_result(sec, buff, strlen(buff));
+	sec->cmd_state = SEC_CMD_STATUS_WAITING;
+	sec_cmd_set_cmd_exit(sec);
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+}
+
+static void clear_cover_mode(void *device_data)
+{
+	struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data;
+	struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
+	char buff[SEC_CMD_STR_LEN] = { 0 };
+
+	input_info(true, &ts->client->dev,
+		   "%s...\n", __func__, buff);
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, true);
+
+	sec_cmd_set_default_result(sec);
+
+	if (sec->cmd_param[0] < 0 || sec->cmd_param[0] > 3) {
+		snprintf(buff, sizeof(buff), "%s", "NG");
+		sec->cmd_state = SEC_CMD_STATUS_FAIL;
+	} else {
+		if (sec->cmd_param[0] > 1) {
+			ts->flip_enable = true;
+			ts->cover_type = sec->cmd_param[1];
+			ts->cover_cmd = (u8)ts->cover_type;
+		} else {
+			ts->flip_enable = false;
+		}
+
+		if (!(ts->power_status == SEC_TS_STATE_POWER_OFF) &&
+		    ts->reinit_done) {
+			if (ts->flip_enable)
+				sec_ts_set_cover_type(ts, true);
+			else
+				sec_ts_set_cover_type(ts, false);
+		}
+
+		snprintf(buff, sizeof(buff), "%s", "OK");
+		sec->cmd_state = SEC_CMD_STATUS_OK;
+	}
+	sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
+	sec->cmd_state = SEC_CMD_STATUS_WAITING;
+	sec_cmd_set_cmd_exit(sec);
+
+	input_info(true, &ts->client->dev, "%s: %s\n", __func__, buff);
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+};
+
+static void dead_zone_enable(void *device_data)
+{
+	struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data;
+	struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
+	char buff[SEC_CMD_STR_LEN] = { 0 };
+	int ret;
+	char data = 0;
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, true);
+
+	sec_cmd_set_default_result(sec);
+
+	if (sec->cmd_param[0] < 0 || sec->cmd_param[0] > 1) {
+		snprintf(buff, sizeof(buff), "%s", "NG");
+		sec->cmd_state = SEC_CMD_STATUS_FAIL;
+	} else {
+		data = sec->cmd_param[0];
+
+		ret = ts->sec_ts_write(ts, SEC_TS_CMD_EDGE_DEADZONE, &data, 1);
+		if (ret < 0) {
+			input_err(true, &ts->client->dev,
+				"%s: failed to set deadzone\n", __func__);
+			snprintf(buff, sizeof(buff), "%s", "NG");
+			sec->cmd_state = SEC_CMD_STATUS_FAIL;
+			goto err_set_dead_zone;
+		}
+
+		snprintf(buff, sizeof(buff), "%s", "OK");
+		sec->cmd_state = SEC_CMD_STATUS_OK;
+	}
+
+err_set_dead_zone:
+	sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
+	sec_cmd_set_cmd_exit(sec);
+
+	input_info(true, &ts->client->dev, "%s: %s\n", __func__, buff);
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+};
+
+
+static void drawing_test_enable(void *device_data)
+{
+	struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data;
+	struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
+	char buff[SEC_CMD_STR_LEN] = { 0 };
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, true);
+
+	sec_cmd_set_default_result(sec);
+
+	if (sec->cmd_param[0] < 0 || sec->cmd_param[0] > 1) {
+		snprintf(buff, sizeof(buff), "%s", "NG");
+		sec->cmd_state = SEC_CMD_STATUS_FAIL;
+	} else {
+		if (ts->use_customlib) {
+			if (sec->cmd_param[0])
+				ts->lowpower_mode &=
+					~SEC_TS_MODE_CUSTOMLIB_FORCE_KEY;
+			else
+				ts->lowpower_mode |=
+					SEC_TS_MODE_CUSTOMLIB_FORCE_KEY;
+
+			#ifdef SEC_TS_SUPPORT_CUSTOMLIB
+			ret = sec_ts_set_custom_library(ts);
+			if (ret < 0) {
+				snprintf(buff, sizeof(buff), "%s", "NG");
+				sec->cmd_state = SEC_CMD_STATUS_FAIL;
+			} else {
+				snprintf(buff, sizeof(buff), "%s", "OK");
+				sec->cmd_state = SEC_CMD_STATUS_OK;
+			}
+			#endif
+
+		} else {
+			snprintf(buff, sizeof(buff), "%s", "NA");
+			sec->cmd_state = SEC_CMD_STATUS_NOT_APPLICABLE;
+		}
+	}
+
+	sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
+	sec_cmd_set_cmd_exit(sec);
+
+	input_info(true, &ts->client->dev, "%s: %s\n", __func__, buff);
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+};
+
+static void sec_ts_swap(u8 *a, u8 *b)
+{
+	u8 temp = *a;
+
+	*a = *b;
+	*b = temp;
+}
+
+static void rearrange_sft_result(u8 *data, int length)
+{
+	int i;
+
+	for (i = 0; i < length; i += 4) {
+		sec_ts_swap(&data[i], &data[i + 3]);
+		sec_ts_swap(&data[i + 1], &data[i + 2]);
+	}
+}
+
+int execute_p2ptest(struct sec_ts_data *ts)
+{
+	int rc;
+	u8 tpara[2] = {0x0F, 0x11};
+
+	input_info(true, &ts->client->dev, "%s: P2P test start!\n", __func__);
+	rc = ts->sec_ts_write(ts, SEC_TS_CMD_SET_P2PTEST_MODE, tpara, 2);
+	if (rc < 0) {
+		input_err(true, &ts->client->dev,
+			  "%s: Send P2Ptest Mode cmd failed!\n", __func__);
+		goto err_exit;
+	}
+
+	sec_ts_delay(15);
+
+	tpara[0] = 0x00;
+	tpara[1] = 0x64;
+	rc = ts->sec_ts_write(ts, SEC_TS_CMD_P2PTEST, tpara, 2);
+	if (rc < 0) {
+		input_err(true, &ts->client->dev,
+			  "%s: Send P2Ptest cmd failed!\n", __func__);
+		goto err_exit;
+	}
+
+	sec_ts_delay(1500);
+
+	rc = sec_ts_wait_for_ready(ts, SEC_TS_VENDOR_ACK_P2P_TEST_DONE);
+	if (rc < 0) {
+		input_err(true, &ts->client->dev,
+			  "%s: P2Ptest execution time out!\n", __func__);
+		goto err_exit;
+	}
+
+	input_info(true, &ts->client->dev, "%s: P2P test done!\n", __func__);
+
+err_exit:
+	return rc;
+}
+
+/* execute_selftest options
+ * bit[8] : Enable/disable the panel crack test
+ * bit[7] : Do NOT save
+ * bit[6] : Load self-test configuration only
+ * bit[5] : Get Self capacitance
+ * bit[4] : Reserved
+ * bit[3] : Reserved
+ * bit[2] : Enable/disable the short test
+ * bit[1] : Enable/disable the node variance test
+ * bit[0] : Enable/disable the open test
+ */
+int execute_selftest(struct sec_ts_data *ts, u32 option)
+{
+	int rc;
+	/* Selftest setting
+	 * Get self capacitance
+	 * Enable/disable the short test
+	 * Enable/disable the node variance test
+	 * Enable/disable the open test
+	 */
+	u8 tpara[2] = {(u8)(option & 0xff), (u8)((option & 0xff00) >> 8)};
+	u8 *rBuff;
+	int i;
+	int result_size = SEC_TS_SELFTEST_REPORT_SIZE +
+				ts->tx_count * ts->rx_count * 2;
+
+	rBuff = kzalloc(result_size, GFP_KERNEL);
+	if (!rBuff)
+		return -ENOMEM;
+
+	input_info(true, &ts->client->dev, "%s: Self test start!\n", __func__);
+	rc = ts->sec_ts_write(ts, SEC_TS_CMD_SELFTEST, tpara, 2);
+	if (rc < 0) {
+		input_err(true, &ts->client->dev,
+			  "%s: Send selftest cmd failed!\n", __func__);
+		goto err_exit;
+	}
+
+	sec_ts_delay(1500);
+
+	rc = sec_ts_wait_for_ready(ts, SEC_TS_VENDOR_ACK_SELF_TEST_DONE);
+	if (rc < 0) {
+		input_err(true, &ts->client->dev,
+			  "%s: Selftest execution time out!\n", __func__);
+		goto err_exit;
+	}
+
+	input_info(true, &ts->client->dev, "%s: Self test done!\n", __func__);
+
+	rc = ts->sec_ts_read_heap(ts, SEC_TS_READ_SELFTEST_RESULT, rBuff,
+				result_size);
+	if (rc < 0) {
+		input_err(true, &ts->client->dev,
+			  "%s: Selftest execution time out!\n", __func__);
+		goto err_exit;
+	}
+	rearrange_sft_result(rBuff, result_size);
+
+	for (i = 0; i < 80; i += 4) {
+		if (i % 8 == 0) pr_cont("\n");
+		if (i % 4 == 0) pr_cont("%s sec_ts : ", SECLOG);
+
+		if (i / 4 == 0) pr_cont("SIG");
+		else if (i / 4 == 1) pr_cont("VER");
+		else if (i / 4 == 2) pr_cont("SIZ");
+		else if (i / 4 == 3) pr_cont("CRC");
+		else if (i / 4 == 4) pr_cont("RES");
+		else if (i / 4 == 5) pr_cont("COU");
+		else if (i / 4 == 6) pr_cont("PAS");
+		else if (i / 4 == 7) pr_cont("FAI");
+		else if (i / 4 == 8) pr_cont("CHA");
+		else if (i / 4 == 9) pr_cont("AMB");
+		else if (i / 4 == 10) pr_cont("RXS");
+		else if (i / 4 == 11) pr_cont("TXS");
+		else if (i / 4 == 12) pr_cont("RXO");
+		else if (i / 4 == 13) pr_cont("TXO");
+		else if (i / 4 == 14) pr_cont("RXG");
+		else if (i / 4 == 15) pr_cont("TXG");
+		else if (i / 4 == 16) pr_cont("RXR");
+		else if (i / 4 == 17) pr_cont("TXT");
+		else if (i / 4 == 18) pr_cont("RXT");
+		else if (i / 4 == 19) pr_cont("TXR");
+
+		pr_cont(" %2X, %2X, %2X, %2X  ", rBuff[i], rBuff[i + 1], rBuff[i + 2], rBuff[i + 3]);
+
+
+		if (i / 4 == 4) {
+			/* RX, RX open check. */
+			if ((rBuff[i + 3] & 0x30) != 0)
+				rc = 0;
+			/* TX, RX GND(VDD) short check. */
+			else if ((rBuff[i + 3] & 0xC0) != 0)
+				rc = 0;
+			/* RX-RX, TX-TX short check. */
+			else if ((rBuff[i + 2] & 0x03) != 0)
+				rc = 0;
+			/* TX-RX short check. */
+			else if ((rBuff[i + 2] & 0x04) != 0)
+				rc = 0;
+			else
+				rc = 1;
+
+			ts->ito_test[0] = rBuff[i];
+			ts->ito_test[1] = rBuff[i + 1];
+			ts->ito_test[2] = rBuff[i + 2];
+			ts->ito_test[3] = rBuff[i + 3];
+		}
+
+	}
+
+err_exit:
+	kfree(rBuff);
+	return rc;
+}
+
+#ifdef USE_STIM_PAD
+static void run_fs_cal_pre_press(void *device_data)
+{
+	struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data;
+	struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
+	char buff[SEC_CMD_STR_LEN] = {0};
+	int ret = 0;
+	u8 off[1] = {STATE_MANAGE_OFF};
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, true);
+
+	sec_cmd_set_default_result(sec);
+
+	input_info(true, &ts->client->dev, "%s: initial sequence for fs cal\n",
+		   __func__);
+
+	if (ts->power_status == SEC_TS_STATE_POWER_OFF) {
+		input_err(true, &ts->client->dev, "%s: Touch is stopped!\n",
+			  __func__);
+		goto ErrorPowerOff;
+	}
+
+	ret = ts->sec_ts_write(ts, SEC_TS_CMD_DISABLE_GAIN_LIMIT, off, 1);
+	if (ret < 0) {
+		input_err(true, &ts->client->dev,
+			   "%s: fail to disable gain limit\n", __func__);
+		goto ErrorSendingCmd;
+	}
+
+	ret = sec_ts_fix_tmode(ts, TOUCH_SYSTEM_MODE_TOUCH,
+			       TOUCH_MODE_STATE_TOUCH);
+	if (ret < 0) {
+		input_err(true, &ts->client->dev, "%s: fail to fix tmode\n",
+			  __func__);
+		goto ErrorSendingCmd;
+	}
+
+	ret = ts->sec_ts_write(ts, SEC_TS_CMD_DISABLE_BASELINE_ADAPT, off,
+				   1);
+	if (ret < 0) {
+		input_err(true, &ts->client->dev,
+			  "%s: fail to disable baselineAdapt\n", __func__);
+		goto ErrorSendingCmd;
+	}
+
+	ret = ts->sec_ts_write(ts, SEC_TS_CMD_DISABLE_DF, off, 1);
+	if (ret < 0) {
+		input_err(true, &ts->client->dev, "%s: fail to disable df\n",
+			  __func__);
+		goto ErrorSendingCmd;
+	}
+
+	ret = ts->sec_ts_write(ts, SEC_TS_CMD_SET_TOUCH_ENGINE_MODE,
+				   off, 1);
+	if (ret < 0) {
+		input_err(true, &ts->client->dev,
+			  "%s: fail to disable touch engine\n", __func__);
+		goto ErrorSendingCmd;
+	}
+
+	ret = ts->sec_ts_write(ts, SEC_TS_CMD_RESET_BASELINE, NULL, 0);
+	if (ret < 0) {
+		input_err(true, &ts->client->dev, "%s: fail to fix tmode\n",
+			  __func__);
+		goto ErrorSendingCmd;
+	}
+
+	sec_ts_delay(50);
+
+	input_info(true, &ts->client->dev, "%s: ready to press\n", __func__);
+
+	snprintf(buff, sizeof(buff), "%s", "OK");
+	sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
+	sec->cmd_state = SEC_CMD_STATUS_OK;
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+	return;
+
+ErrorSendingCmd:
+ErrorPowerOff:
+	snprintf(buff, sizeof(buff), "%s", "NG");
+	sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
+	sec->cmd_state = SEC_CMD_STATUS_NOT_APPLICABLE;
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+}
+
+static void run_fs_cal_get_data(void *device_data)
+{
+	struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data;
+	struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
+	struct sec_ts_test_mode mode;
+	short *diff_table = NULL;
+	const bool only_average = true;
+	char *buff;
+	int ret;
+	int i, j;
+	const unsigned int buff_size = ts->tx_count * ts->rx_count *
+				       CMD_RESULT_WORD_LEN;
+	unsigned int buff_len = 0;
+
+	input_info(true, &ts->client->dev, "%s: fs cal with stim pad\n",
+		   __func__);
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, true);
+
+	sec_cmd_set_default_result(sec);
+
+	if (ts->power_status == SEC_TS_STATE_POWER_OFF) {
+		input_err(true, &ts->client->dev, "%s: Touch is stopped!\n",
+			  __func__);
+		sec_cmd_set_cmd_result(sec, "NG", 2);
+		sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+		return;
+	}
+
+	if (sec->cmd_param[0] < 0 || sec->cmd_param[0] > 3) {
+		input_err(true, &ts->client->dev,
+			  "%s: Parameter Error\n", __func__);
+		sec_cmd_set_cmd_result(sec, "NG", 2);
+		sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+		return;
+	}
+
+	buff = kzalloc(buff_size, GFP_KERNEL);
+	if (!buff) {
+		sec_cmd_set_cmd_result(sec, "NG", 2);
+		sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+		return;
+	}
+
+	memset(&mode, 0x00, sizeof(struct sec_ts_test_mode));
+
+	if (sec->cmd_param[0] == 0) {
+		mode.type = TYPE_REMV_AMB_DATA;
+		mode.spec_check = SPEC_NO_CHECK;
+		ret = sec_ts_read_frame_stdev(ts, sec, mode.type, mode.min,
+				mode.max, &mode.spec_check, only_average);
+		if (ret < 0) {
+			buff_len += scnprintf(buff + buff_len,
+					      buff_size - buff_len, "NG");
+			sec->cmd_state = SEC_CMD_STATUS_FAIL;
+			goto SetCmdResult;
+		}
+		ret = sec_ts_check_fs_precal(ts);
+
+		/* ret = NG node count */
+		if (ret > 0) {
+			buff_len += scnprintf(buff + buff_len,
+					      buff_size - buff_len, "NG\n");
+			sec->cmd_state = SEC_CMD_STATUS_FAIL;
+		} else {
+			buff_len += scnprintf(buff + buff_len,
+					      buff_size - buff_len, "OK\n");
+			sec->cmd_state = SEC_CMD_STATUS_OK;
+		}
+
+		for (i = 0; i < ts->tx_count * ts->rx_count; i++) {
+			buff_len += scnprintf(buff + buff_len,
+					      buff_size - buff_len, "%4d,",
+					      ts->pFrame[i]);
+
+			if (i % ts->tx_count == ts->tx_count - 1)
+				buff_len += scnprintf(buff + buff_len,
+						      buff_size - buff_len,
+						      "\n");
+		}
+		/* calculate gain table, and store it to ts->gainTable */
+		sec_ts_get_gain_table(ts);
+
+	} else if (sec->cmd_param[0] == 1) {
+		/* write gaintable(ts->gainTable) to ic */
+		ret = sec_ts_write_gain_table(ts);
+		if (ret < 0) {
+			buff_len += scnprintf(buff + buff_len,
+					      buff_size - buff_len,
+					      "NG %d %d\n",
+					      ts->rx_count, ts->tx_count);
+			sec->cmd_state = SEC_CMD_STATUS_FAIL;
+		} else {
+			buff_len += scnprintf(buff + buff_len,
+					      buff_size - buff_len,
+					      "OK %d %d\n",
+					      ts->rx_count, ts->tx_count);
+			sec->cmd_state = SEC_CMD_STATUS_OK;
+		}
+
+		for (j = 0; j < ts->rx_count; j++) {
+			for (i = 0; i < ts->tx_count; i++) {
+				buff_len += scnprintf(buff + buff_len,
+						buff_size - buff_len,
+						"%4d,",
+						ts->gainTable[i*ts->rx_count
+								+ j]);
+			}
+			buff_len += scnprintf(buff + buff_len,
+					      buff_size - buff_len, "\n");
+		}
+	} else if (sec->cmd_param[0] == 2) {
+		int mean;
+		/* for stim pad fixture 2 */
+		mode.type = TYPE_NORM2_DATA;
+		mode.spec_check = SPEC_NO_CHECK;
+
+		ret = sec_ts_read_frame_stdev(ts, sec, mode.type, mode.min,
+				mode.max, &mode.spec_check, only_average);
+		if (ret < 0) {
+			buff_len += scnprintf(buff + buff_len,
+					      buff_size - buff_len, "NG");
+			sec->cmd_state = SEC_CMD_STATUS_FAIL;
+			goto SetCmdResult;
+		}
+
+		mean = sec_ts_get_postcal_mean(ts);
+		ts->fs_postcal_mean = mean;
+
+		input_info(true, &ts->client->dev,
+			   "%s : FS mean = %d\n", __func__, mean);
+
+		if ((mean > fs_mean_target_h) || (mean < fs_mean_target_l)) {
+			buff_len += scnprintf(buff + buff_len,
+					      buff_size - buff_len,
+					      "NG %d %d\n%d\n",
+					      ts->rx_count, ts->tx_count,
+					      ts->fs_postcal_mean);
+			sec->cmd_state = SEC_CMD_STATUS_FAIL;
+		} else {
+			buff_len += scnprintf(buff + buff_len,
+					      buff_size - buff_len,
+					      "OK %d %d\n%d\n",
+					      ts->rx_count, ts->tx_count,
+					      ts->fs_postcal_mean);
+			sec->cmd_state = SEC_CMD_STATUS_OK;
+		}
+
+		for (i = 0; i < ts->tx_count * ts->rx_count; i++) {
+			buff_len += scnprintf(buff + buff_len,
+					      buff_size - buff_len, "%4d,",
+					      ts->pFrame[i]);
+
+			if (i % ts->tx_count == ts->tx_count - 1)
+				buff_len += scnprintf(buff + buff_len,
+						      buff_size - buff_len,
+						      "\n");
+		}
+	} else { //(sec->cmd_param[0] == 3)
+		/* get fs_uniformity */
+
+		diff_table = kzalloc(ts->tx_count * ts->rx_count * 2,
+				GFP_KERNEL);
+
+		if ((diff_table == NULL) || (ts->fs_postcal_mean == 0)) {
+			input_err(true, &ts->client->dev,
+					"%s: fail to alloc diffTable, postcal mean = %d\n",
+					__func__, ts->fs_postcal_mean);
+			buff_len += scnprintf(buff + buff_len,
+					      buff_size - buff_len, "NG %d %d",
+					      ts->rx_count, ts->tx_count);
+			sec->cmd_state = SEC_CMD_STATUS_FAIL;
+			goto SetCmdResult;
+		}
+
+		ret = sec_ts_get_postcal_uniformity(ts, diff_table);
+
+		if (ret == 0) {
+			buff_len += scnprintf(buff + buff_len,
+					      buff_size - buff_len,
+					      "OK %d %d\n",
+					      ts->rx_count, ts->tx_count);
+			sec->cmd_state = SEC_CMD_STATUS_OK;
+		} else {
+			buff_len += scnprintf(buff + buff_len,
+					      buff_size - buff_len,
+					      "NG %d %d\n",
+					      ts->rx_count, ts->tx_count);
+			sec->cmd_state = SEC_CMD_STATUS_FAIL;
+		}
+
+		for (i = 0; i < ts->tx_count * ts->rx_count; i++) {
+			buff_len += scnprintf(buff + buff_len,
+					      buff_size - buff_len, "%4d,",
+					      diff_table[i]);
+
+			if (i % ts->tx_count == ts->tx_count - 1)
+				buff_len += scnprintf(buff + buff_len,
+						      buff_size - buff_len,
+						      "\n");
+		}
+	}
+
+SetCmdResult:
+
+	sec_cmd_set_cmd_result(sec, buff, buff_len);
+
+	kfree(diff_table);
+	kfree(buff);
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+}
+
+static void run_fs_cal_post_press(void *device_data)
+{
+	struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data;
+	struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
+	char buff[SEC_CMD_STR_LEN] = {0};
+	int ret = 0;
+	u8 on[1] = {STATE_MANAGE_ON};
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, true);
+
+	sec_cmd_set_default_result(sec);
+
+	if (ts->power_status == SEC_TS_STATE_POWER_OFF) {
+		input_err(true, &ts->client->dev, "%s: Touch is stopped!\n",
+			  __func__);
+		goto ErrorPowerOff;
+	}
+
+	ret = ts->sec_ts_write(ts, SEC_TS_CMD_SET_TOUCH_ENGINE_MODE, on, 1);
+	if (ret < 0) {
+		input_err(true, &ts->client->dev,
+			  "%s: fail to enable touch engine\n", __func__);
+		goto ErrorSendingCmd;
+	}
+
+	ret = ts->sec_ts_write(ts, SEC_TS_CMD_DISABLE_DF, on, 1);
+	if (ret < 0) {
+		input_err(true, &ts->client->dev, "%s: fail to enable df\n",
+			  __func__);
+		goto ErrorSendingCmd;
+	}
+
+	ret = ts->sec_ts_write(ts, SEC_TS_CMD_DISABLE_BASELINE_ADAPT, on,
+				   1);
+	if (ret < 0) {
+		input_err(true, &ts->client->dev,
+			  "%s: fail to enable baselineAdapt\n", __func__);
+		goto ErrorSendingCmd;
+	}
+
+	ret = ts->sec_ts_write(ts, SEC_TS_CMD_DISABLE_GAIN_LIMIT, on, 1);
+	if (ret < 0) {
+		input_err(true, &ts->client->dev,
+			  "%s: fail to enable gain limit\n", __func__);
+		goto ErrorSendingCmd;
+	}
+
+	ret = sec_ts_release_tmode(ts);
+	if (ret < 0) {
+		input_err(true, &ts->client->dev, "%s: fail to release tmode\n",
+			  __func__);
+		goto ErrorSendingCmd;
+	}
+
+	snprintf(buff, sizeof(buff), "%s", "OK");
+	sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
+	sec->cmd_state = SEC_CMD_STATUS_OK;
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+	return;
+
+ErrorSendingCmd:
+ErrorPowerOff:
+	snprintf(buff, sizeof(buff), "%s", "NG");
+	sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
+	sec->cmd_state = SEC_CMD_STATUS_NOT_APPLICABLE;
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+}
+
+/* enable_fs_cal_table : enable or disable fs cal table
+ * cmd_param : 0 to disable, 1 to enable
+ * touch mode and state should be fixed before enable or disable
+ */
+static void enable_fs_cal_table(void *device_data)
+{
+	struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data;
+	struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
+	u8 tPara;
+	int ret;
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, true);
+
+	sec_cmd_set_default_result(sec);
+
+	if (sec->cmd_param[0] < 0 || sec->cmd_param[0] > 1) {
+		sec->cmd_state = SEC_CMD_STATUS_FAIL;
+		sec_cmd_set_cmd_result(sec, "NG", 2);
+		sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+		return;
+	}
+
+	ret = sec_ts_fix_tmode(ts, TOUCH_SYSTEM_MODE_TOUCH,
+				TOUCH_MODE_STATE_TOUCH);
+	if (ret < 0) {
+		input_err(true, &ts->client->dev, "%s: fail to fix tmode\n",
+			  __func__);
+		sec->cmd_state = SEC_CMD_STATUS_FAIL;
+		sec_cmd_set_cmd_result(sec, "NG", 2);
+		sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+		return;
+	}
+
+	tPara = sec->cmd_param[0];
+
+	input_info(true, &ts->client->dev, "%s: fs cal table %s\n",
+		   __func__, ((tPara == 0) ? "disable" : "enable"));
+
+	ret = ts->sec_ts_write(ts, SEC_TS_CMD_DISABLE_NORM_TABLE,
+				   &tPara, 1);
+
+	if (ret < 0) {
+		input_err(true, &ts->client->dev,
+			  "%s: cmd write failed\n", __func__);
+		sec->cmd_state = SEC_CMD_STATUS_FAIL;
+		sec_cmd_set_cmd_result(sec, "NG", 2);
+	} else {
+		sec->cmd_state = SEC_CMD_STATUS_OK;
+		sec_cmd_set_cmd_result(sec, "OK", 2);
+	}
+
+	ret = sec_ts_release_tmode(ts);
+	if (ret < 0)
+		input_err(true, &ts->client->dev, "%s: fail to release tmode\n",
+			  __func__);
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+}
+
+static void enable_gain_limit(void *device_data)
+{
+	struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data;
+	struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
+	int ret = 0;
+	u8 tPara;
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, true);
+
+	sec_cmd_set_default_result(sec);
+
+	if (ts->power_status == SEC_TS_STATE_POWER_OFF) {
+		input_err(true, &ts->client->dev, "%s: Touch is stopped!\n",
+			  __func__);
+		sec_cmd_set_cmd_result(sec, "TSP turned off", 14);
+		sec->cmd_state = SEC_CMD_STATUS_NOT_APPLICABLE;
+		sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+		return;
+	}
+
+	if (sec->cmd_param[0] < 0 || sec->cmd_param[0] > 1) {
+		sec->cmd_state = SEC_CMD_STATUS_FAIL;
+		sec_cmd_set_cmd_result(sec, "NG", 2);
+		sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+		return;
+	}
+
+	tPara = sec->cmd_param[0];
+
+	input_info(true, &ts->client->dev, "%s: gain limit %s\n",
+		   __func__, ((tPara == 0) ? "disable" : "enable"));
+
+	ret = ts->sec_ts_write(ts, SEC_TS_CMD_DISABLE_GAIN_LIMIT, &tPara,
+				   1);
+	if (ret < 0) {
+		input_err(true, &ts->client->dev,
+			  "%s: cmd write failed\n", __func__);
+		sec->cmd_state = SEC_CMD_STATUS_FAIL;
+		sec_cmd_set_cmd_result(sec, "NG", 2);
+	} else {
+		sec->cmd_state = SEC_CMD_STATUS_OK;
+		sec_cmd_set_cmd_result(sec, "OK", 2);
+	}
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+}
+#endif
+
+static void enable_coordinate_report(void *device_data)
+{
+	struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data;
+	struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
+	int ret = 0;
+	u8 tPara;
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, true);
+
+	sec_cmd_set_default_result(sec);
+
+	if (ts->power_status == SEC_TS_STATE_POWER_OFF) {
+		input_err(true, &ts->client->dev, "%s: Touch is stopped!\n",
+			  __func__);
+		sec_cmd_set_cmd_result(sec, "TSP turned off", 14);
+		sec->cmd_state = SEC_CMD_STATUS_NOT_APPLICABLE;
+		sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+		return;
+	}
+
+	if (sec->cmd_param[0] < 0 || sec->cmd_param[0] > 1) {
+		sec->cmd_state = SEC_CMD_STATUS_FAIL;
+		sec_cmd_set_cmd_result(sec, "NG", 2);
+		sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+		return;
+	}
+
+	tPara = sec->cmd_param[0];
+
+	input_info(true, &ts->client->dev, "%s: coordinate report %s\n",
+		   __func__, ((tPara == 0) ? "disable" : "enable"));
+
+	ret = ts->sec_ts_write(ts, SEC_TS_CMD_SET_TOUCH_ENGINE_MODE,
+				   &tPara, 1);
+	if (ret < 0) {
+		input_err(true, &ts->client->dev,
+			  "%s: cmd write failed\n", __func__);
+		sec->cmd_state = SEC_CMD_STATUS_FAIL;
+		sec_cmd_set_cmd_result(sec, "NG", 2);
+	} else {
+		sec->cmd_state = SEC_CMD_STATUS_OK;
+		sec_cmd_set_cmd_result(sec, "OK", 2);
+	}
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+}
+
+static void run_trx_short_test(void *device_data)
+{
+	struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data;
+	struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
+	char buff[SEC_CMD_STR_LEN] = {0};
+	int rc;
+	char para = TO_TOUCH_MODE;
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, true);
+
+	sec_cmd_set_default_result(sec);
+
+	if (ts->power_status == SEC_TS_STATE_POWER_OFF) {
+		input_err(true, &ts->client->dev,
+			  "%s: Touch is stopped!\n", __func__);
+		snprintf(buff, sizeof(buff), "%s", "TSP turned off");
+		sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
+		sec->cmd_state = SEC_CMD_STATUS_NOT_APPLICABLE;
+		sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+		return;
+	}
+
+	disable_irq(ts->client->irq);
+
+	rc = execute_selftest(ts, TEST_SHORT | TEST_OPEN | TEST_NODE_VARIANCE);
+	if (rc > 0) {
+		ts->sec_ts_write(ts, SEC_TS_CMD_SET_POWER_MODE, &para, 1);
+		enable_irq(ts->client->irq);
+		snprintf(buff, sizeof(buff), "%s", "OK");
+		sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
+		sec->cmd_state = SEC_CMD_STATUS_OK;
+
+		input_info(true, &ts->client->dev, "%s: %s\n", __func__, buff);
+		sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+		return;
+	}
+
+	ts->sec_ts_write(ts, SEC_TS_CMD_SET_POWER_MODE, &para, 1);
+	enable_irq(ts->client->irq);
+
+	snprintf(buff, sizeof(buff), "%s", "NG");
+	sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
+	sec->cmd_state = SEC_CMD_STATUS_FAIL;
+
+	input_info(true, &ts->client->dev, "%s: %s\n", __func__, buff);
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+}
+
+
+int sec_ts_execute_force_calibration(struct sec_ts_data *ts, int cal_mode)
+{
+	int rc = -1;
+	u8 cmd;
+
+	input_info(true, &ts->client->dev, "%s: %d\n", __func__, cal_mode);
+
+	if (cal_mode == OFFSET_CAL_SEC)
+		cmd = SEC_TS_CMD_FACTORY_PANELCALIBRATION;
+	else if (cal_mode == AMBIENT_CAL)
+		cmd = SEC_TS_CMD_CALIBRATION_AMBIENT;
+#ifdef USE_PRESSURE_SENSOR
+	else if (cal_mode == PRESSURE_CAL)
+		cmd = SEC_TS_CMD_CALIBRATION_PRESSURE;
+#endif
+	else
+		return rc;
+
+	if (ts->sec_ts_write(ts, cmd, NULL, 0) < 0) {
+		input_err(true, &ts->client->dev,
+			  "%s: Write Cal commend failed!\n", __func__);
+		return rc;
+	}
+
+	sec_ts_delay(4000);
+
+	rc = sec_ts_wait_for_ready(ts, SEC_TS_VENDOR_ACK_OFFSET_CAL_DONE);
+
+	return rc;
+}
+
+static void run_force_calibration(void *device_data)
+{
+	struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data;
+	struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
+	char buff[SEC_CMD_STR_LEN] = {0};
+	int rc;
+#ifdef PAT_CONTROL
+	u8 img_ver[4];
+#endif
+	struct sec_ts_test_mode mode;
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, true);
+
+	sec_cmd_set_default_result(sec);
+
+	if (ts->power_status == SEC_TS_STATE_POWER_OFF) {
+		input_err(true, &ts->client->dev,
+			  "%s: Touch is stopped!\n", __func__);
+		snprintf(buff, sizeof(buff), "%s", "TSP turned off");
+		sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
+		sec->cmd_state = SEC_CMD_STATUS_NOT_APPLICABLE;
+
+		sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+		return;
+	}
+
+	sec_ts_read_calibration_report(ts);
+
+	if (ts->touch_count > 0) {
+		snprintf(buff, sizeof(buff), "%s", "NG_FINGER_ON");
+		sec->cmd_state = SEC_CMD_STATUS_FAIL;
+		goto out_force_cal;
+	}
+
+	disable_irq(ts->client->irq);
+
+	rc = sec_ts_execute_force_calibration(ts, OFFSET_CAL_SEC);
+	if (rc < 0) {
+		snprintf(buff, sizeof(buff), "%s", "FAIL");
+		sec->cmd_state = SEC_CMD_STATUS_FAIL;
+	} else {
+#ifdef USE_PRESSURE_SENSOR
+		rc = sec_ts_execute_force_calibration(ts, PRESSURE_CAL);
+		if (rc < 0)
+			input_err(true, &ts->client->dev,
+				"%s: fail to write PRESSURE CAL!\n", __func__);
+#endif
+
+		if (ts->plat_data->mis_cal_check &&
+		    sec_ts_run_cal_check(ts)) {
+			memset(&mode, 0x00,
+			       sizeof(struct sec_ts_test_mode));
+			mode.type = TYPE_AMBIENT_DATA;
+			mode.allnode = TEST_MODE_ALL_NODE;
+
+			sec_ts_read_raw_data(ts, NULL, &mode);
+			snprintf(buff, sizeof(buff), "%s", "MIS CAL");
+			sec->cmd_state = SEC_CMD_STATUS_FAIL;
+
+			enable_irq(ts->client->irq);
+			goto out_force_cal;
+		}
+
+#ifdef PAT_CONTROL
+		ts->cal_count = get_tsp_nvm_data(ts,
+					SEC_TS_NVM_OFFSET_CAL_COUNT);
+
+		if (ts->external_factory == true) {
+			/* for external factory mode */
+			if (ts->cal_count == PAT_MAX_EXT)
+				ts->cal_count = PAT_MAX_EXT;
+			else if (ts->cal_count >= PAT_EXT_FACT &&
+				 ts->cal_count < PAT_MAX_EXT)
+				ts->cal_count++;
+			else
+				ts->cal_count = PAT_EXT_FACT;
+
+			/* not to enter external factory mode without setting
+			 * everytime
+			 **/
+			ts->external_factory = false;
+		} else {
+			/* change from (virtual pat or vpat by external fatory)
+			 * to real pat by forced calibarion by LCIA
+			 **/
+			if (ts->cal_count >= PAT_MAGIC_NUMBER)
+				ts->cal_count = 1;
+			else if (ts->cal_count == PAT_MAX_LCIA)
+				ts->cal_count = PAT_MAX_LCIA;
+			else
+				ts->cal_count++;
+		}
+
+		/* Use TSP NV area : in this model, use only one byte
+		 * buff[0] : offset from user NVM storage
+		 * buff[1] : length of stroed data - 1 (ex. using 1byte,
+				value is 1 - 1 = 0)
+		 * buff[2] : write data
+		 **/
+		buff[0] = SEC_TS_NVM_OFFSET_CAL_COUNT;
+		buff[1] = 0;
+		buff[2] = ts->cal_count;
+		input_info(true, &ts->client->dev,
+			   "%s: write to nvm cal_count(%2X)\n",
+			   __func__, buff[2]);
+
+		rc = ts->sec_ts_write(ts, SEC_TS_CMD_NVM, buff, 3);
+		if (rc < 0) {
+			input_err(true, &ts->client->dev,
+				"%s: nvm write failed. ret: %d\n",
+				__func__, rc);
+		}
+
+		sec_ts_delay(20);
+
+		ts->cal_count = get_tsp_nvm_data(ts,
+						 SEC_TS_NVM_OFFSET_CAL_COUNT);
+
+		rc = ts->sec_ts_read(ts, SEC_TS_READ_IMG_VERSION, img_ver, 4);
+		if (rc < 0) {
+			input_err(true, &ts->client->dev,
+				  "%s: Image version read error\n", __func__);
+		} else {
+			memset(buff, 0x00, SEC_CMD_STR_LEN);
+			buff[0] = get_tsp_nvm_data(ts,
+						SEC_TS_NVM_OFFSET_TUNE_VERSION);
+			if (buff[0] == 0xFF) {
+				set_tsp_nvm_data_clear(ts,
+					SEC_TS_NVM_OFFSET_TUNE_VERSION);
+				set_tsp_nvm_data_clear(ts,
+					SEC_TS_NVM_OFFSET_TUNE_VERSION + 1);
+			}
+
+			ts->tune_fix_ver = (img_ver[2]<<8 | img_ver[3]);
+			buff[0] = SEC_TS_NVM_OFFSET_TUNE_VERSION;
+			buff[1] = 1;// 2bytes
+			buff[2] = img_ver[2];
+			buff[3] = img_ver[3];
+			input_info(true, &ts->client->dev,
+				   "%s: write tune_ver to nvm (%2X %2X)\n",
+				   __func__, buff[2], buff[3]);
+
+			rc = ts->sec_ts_write(ts, SEC_TS_CMD_NVM, buff, 4);
+			if (rc < 0) {
+				input_err(true, &ts->client->dev,
+					"%s: nvm write failed. ret: %d\n",
+					__func__, rc);
+			}
+			sec_ts_delay(20);
+
+			buff[0] = get_tsp_nvm_data(ts,
+					SEC_TS_NVM_OFFSET_TUNE_VERSION);
+			buff[1] = get_tsp_nvm_data(ts,
+					SEC_TS_NVM_OFFSET_TUNE_VERSION + 1);
+			ts->tune_fix_ver = buff[0]<<8 | buff[1];
+			input_info(true, &ts->client->dev,
+				"%s: cal_count [%2X] tune_fix_ver [%04X]\n",
+				__func__, ts->cal_count, ts->tune_fix_ver);
+		}
+#endif
+		snprintf(buff, sizeof(buff), "%s", "OK");
+		sec->cmd_state = SEC_CMD_STATUS_OK;
+	}
+
+	enable_irq(ts->client->irq);
+
+out_force_cal:
+	sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
+
+	input_info(true, &ts->client->dev, "%s: %s\n", __func__, buff);
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+}
+
+static void get_force_calibration(void *device_data)
+{
+	struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data;
+	struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
+	char buff[SEC_CMD_STR_LEN] = {0};
+	int buff_len = sizeof(buff);
+	int written = 0;
+	int rc;
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, true);
+
+	sec_cmd_set_default_result(sec);
+
+	if (ts->power_status == SEC_TS_STATE_POWER_OFF) {
+		input_err(true, &ts->client->dev, "%s: Touch is stopped!\n",
+			  __func__);
+		written += scnprintf(buff + written, buff_len - written,
+			"%s", "TSP turned off");
+		sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
+		sec->cmd_state = SEC_CMD_STATUS_NOT_APPLICABLE;
+
+		sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+		return;
+	}
+
+	rc = sec_ts_read_calibration_report(ts);
+	if (rc < 0) {
+		written += scnprintf(buff + written, buff_len - written,
+			"%s\n", "FAIL");
+		sec->cmd_state = SEC_CMD_STATUS_FAIL;
+	} else if (rc == SEC_TS_STATUS_CALIBRATION_SDC) {
+		written += scnprintf(buff + written, buff_len - written,
+			"%s\n", "OK(MODULE)");
+		sec->cmd_state = SEC_CMD_STATUS_OK;
+	} else if (rc == SEC_TS_STATUS_CALIBRATION_SEC) {
+		written += scnprintf(buff + written, buff_len - written,
+			"%s\n", "OK");
+		sec->cmd_state = SEC_CMD_STATUS_OK;
+	} else {
+		written += scnprintf(buff + written, buff_len - written,
+			"%s\n", "NG");
+		sec->cmd_state = SEC_CMD_STATUS_FAIL;
+	}
+
+	written += scnprintf(buff + written, buff_len - written,
+		"%02X, %02X, %02X, %02X, %02X, %02X, %02X, %02X\n",
+		ts->cali_report[0], ts->cali_report[1], ts->cali_report[2],
+		ts->cali_report[3], ts->cali_report[4], ts->cali_report[5],
+		ts->cali_report[6], ts->cali_report[7]);
+	sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
+
+	input_info(true, &ts->client->dev, "%s: %s\n", __func__, buff);
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+}
+
+#ifdef USE_PRESSURE_SENSOR
+static void run_force_pressure_calibration(void *device_data)
+{
+	struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data;
+	struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
+	char buff[SEC_CMD_STR_LEN] = {0};
+	int rc;
+	char data[3] = { 0 };
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, true);
+
+	sec_cmd_set_default_result(sec);
+
+	if (ts->power_status == SEC_TS_STATE_POWER_OFF) {
+		input_err(true, &ts->client->dev, "%s: Touch is stopped!\n",
+			  __func__);
+		snprintf(buff, sizeof(buff), "%s", "TSP turned off");
+		sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
+		sec->cmd_state = SEC_CMD_STATUS_NOT_APPLICABLE;
+
+		sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+		return;
+	}
+
+	if (ts->touch_count > 0) {
+		snprintf(buff, sizeof(buff), "%s", "NG_FINGER_ON");
+		sec->cmd_state = SEC_CMD_STATUS_FAIL;
+		goto out_force_pressure_cal;
+	}
+
+	disable_irq(ts->client->irq);
+
+	rc = sec_ts_execute_force_calibration(ts, PRESSURE_CAL);
+	if (rc < 0) {
+		snprintf(buff, sizeof(buff), "%s", "FAIL");
+		sec->cmd_state = SEC_CMD_STATUS_FAIL;
+	} else {
+		snprintf(buff, sizeof(buff), "%s", "OK");
+		sec->cmd_state = SEC_CMD_STATUS_OK;
+	}
+
+	ts->pressure_cal_base = get_tsp_nvm_data(ts,
+				SEC_TS_NVM_OFFSET_PRESSURE_BASE_CAL_COUNT);
+	if (ts->pressure_cal_base == 0xFF)
+		ts->pressure_cal_base = 0;
+	if (ts->pressure_cal_base > 0xFD)
+		ts->pressure_cal_base = 0xFD;
+
+	/* Use TSP NV area : in this model, use only one byte
+	 * data[0] : offset from user NVM storage
+	 * data[1] : length of stroed data - 1 (ex. using 1byte,
+	 *           value is  1 - 1 = 0)
+	 * data[2] : write data
+	 **/
+	data[0] = SEC_TS_NVM_OFFSET_PRESSURE_BASE_CAL_COUNT;
+	data[1] = 0;
+	data[2] = ts->pressure_cal_base + 1;
+
+	rc = ts->sec_ts_write(ts, SEC_TS_CMD_NVM, data, 3);
+	if (rc < 0)
+		input_err(true, &ts->client->dev,
+			"%s: nvm write failed. ret: %d\n", __func__, rc);
+
+	ts->pressure_cal_base = get_tsp_nvm_data(ts,
+				SEC_TS_NVM_OFFSET_PRESSURE_BASE_CAL_COUNT);
+
+	input_info(true, &ts->client->dev, "%s: count: %d\n",
+		   __func__, ts->pressure_cal_base);
+
+	enable_irq(ts->client->irq);
+
+out_force_pressure_cal:
+	sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
+
+	input_info(true, &ts->client->dev, "%s: %s\n", __func__, buff);
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+}
+
+static void set_pressure_test_mode(void *device_data)
+{
+	struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data;
+	struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
+	char buff[SEC_CMD_STR_LEN] = {0};
+	int ret;
+	unsigned char data = TYPE_INVALID_DATA;
+	unsigned char enable = 0;
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, true);
+
+	sec_cmd_set_default_result(sec);
+
+	if (ts->power_status == SEC_TS_STATE_POWER_OFF) {
+		input_err(true, &ts->client->dev, "%s: Touch is stopped!\n",
+			  __func__);
+		snprintf(buff, sizeof(buff), "%s", "TSP turned off");
+		sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
+		sec->cmd_state = SEC_CMD_STATUS_NOT_APPLICABLE;
+
+		sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+		return;
+	}
+
+	if (sec->cmd_param[0] == 1) {
+		enable = 0x1;
+		ret = ts->sec_ts_write(ts, SEC_TS_CMD_SET_TEMPERATURE_COMP_MODE,
+				       &enable, 1);
+		if (ret < 0) {
+			snprintf(buff, sizeof(buff), "%s", "NG");
+			sec->cmd_state = SEC_CMD_STATUS_FAIL;
+			goto out_test_mode;
+		}
+
+		ret = sec_ts_fix_tmode(ts, TOUCH_SYSTEM_MODE_TOUCH,
+				       TOUCH_MODE_STATE_TOUCH);
+		if (ret < 0) {
+			snprintf(buff, sizeof(buff), "%s", "NG");
+			sec->cmd_state = SEC_CMD_STATUS_FAIL;
+			goto out_test_mode;
+		}
+
+	} else {
+		ret = ts->sec_ts_write(ts, SEC_TS_CMD_SELECT_PRESSURE_TYPE,
+				       &data, 1);
+		if (ret < 0) {
+			snprintf(buff, sizeof(buff), "%s", "NG");
+			sec->cmd_state = SEC_CMD_STATUS_FAIL;
+			goto out_test_mode;
+		}
+
+		ret = sec_ts_release_tmode(ts);
+		if (ret < 0) {
+			snprintf(buff, sizeof(buff), "%s", "NG");
+			sec->cmd_state = SEC_CMD_STATUS_FAIL;
+			goto out_test_mode;
+		}
+
+		enable = 0x0;
+		ret = ts->sec_ts_write(ts, SEC_TS_CMD_SET_TEMPERATURE_COMP_MODE,
+				       &enable, 1);
+		if (ret < 0) {
+			snprintf(buff, sizeof(buff), "%s", "NG");
+			sec->cmd_state = SEC_CMD_STATUS_FAIL;
+			goto out_test_mode;
+		}
+	}
+
+	snprintf(buff, sizeof(buff), "%s", "OK");
+	sec->cmd_state = SEC_CMD_STATUS_OK;
+
+out_test_mode:
+	sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
+
+	input_info(true, &ts->client->dev, "%s: %s\n", __func__, buff);
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+}
+
+static int read_pressure_data(struct sec_ts_data *ts, u8 type, short *value)
+{
+	unsigned char data[6] = { 0 };
+	short pressure[3] = { 0 };
+	int ret;
+
+	if (ts->power_status == SEC_TS_STATE_POWER_OFF)
+		return -ENODEV;
+
+	ret = ts->sec_ts_read(ts, SEC_TS_CMD_SELECT_PRESSURE_TYPE, data, 1);
+	if (ret < 0)
+		return -EIO;
+
+	if (data[0] != type) {
+		input_info(true, &ts->client->dev, "%s: type change to %02X\n",
+			   __func__, type);
+
+		data[1] = type;
+
+		ret = ts->sec_ts_write(ts, SEC_TS_CMD_SELECT_PRESSURE_TYPE,
+				       &data[1], 1);
+		if (ret < 0)
+			return -EIO;
+
+		sec_ts_delay(30);
+	}
+
+	memset(data, 0x00, 6);
+
+	ret = ts->sec_ts_read(ts, SEC_TS_CMD_READ_PRESSURE_DATA, data, 6);
+	if (ret < 0)
+		return -EIO;
+
+	pressure[0] = (data[0] << 8 | data[1]);
+	pressure[1] = (data[2] << 8 | data[3]);
+	pressure[2] = (data[4] << 8 | data[5]);
+
+	input_info(true, &ts->client->dev,
+		   "%s: Left: %d, Center: %d, Rignt: %d\n",
+		   __func__, pressure[2], pressure[1], pressure[0]);
+
+	memcpy(value, pressure, 3 * 2);
+
+	return ret;
+}
+
+static void run_pressure_filtered_strength_read_all(void *device_data)
+{
+	struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data;
+	struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
+	char buff[SEC_CMD_STR_LEN] = {0};
+	short pressure[3] = { 0 };
+	int ret;
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, true);
+
+	sec_cmd_set_default_result(sec);
+
+	ret = read_pressure_data(ts, TYPE_SIGNAL_DATA, pressure);
+	if (ret < 0) {
+		snprintf(buff, sizeof(buff), "%s", "WRITE FAILED");
+		goto error_read_str;
+	}
+
+	snprintf(buff, sizeof(buff), "%d,%d,%d",
+		 pressure[2], pressure[1], pressure[0]);
+
+	sec->cmd_state = SEC_CMD_STATUS_OK;
+
+	sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
+
+	input_info(true, &ts->client->dev, "%s: %s\n", __func__, buff);
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+	return;
+
+error_read_str:
+	sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
+	sec->cmd_state = SEC_CMD_STATUS_NOT_APPLICABLE;
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+}
+
+static void run_pressure_strength_read_all(void *device_data)
+{
+	struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data;
+	struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
+	char buff[SEC_CMD_STR_LEN] = {0};
+	short pressure[3] = { 0 };
+	int ret;
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, true);
+
+	sec_cmd_set_default_result(sec);
+
+	ret = read_pressure_data(ts, TYPE_REMV_AMB_DATA, pressure);
+	if (ret < 0) {
+		snprintf(buff, sizeof(buff), "%s", "WRITE FAILED");
+		goto error_read_str;
+	}
+
+	snprintf(buff, sizeof(buff), "%d,%d,%d",
+		 pressure[2], pressure[1], pressure[0]);
+
+	sec->cmd_state = SEC_CMD_STATUS_OK;
+
+	sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
+
+	input_info(true, &ts->client->dev, "%s: %s\n", __func__, buff);
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+	return;
+
+error_read_str:
+	sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
+	sec->cmd_state = SEC_CMD_STATUS_NOT_APPLICABLE;
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+}
+
+static void run_pressure_rawdata_read_all(void *device_data)
+{
+	struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data;
+	struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
+	char buff[SEC_CMD_STR_LEN] = {0};
+	short pressure[3] = { 0 };
+	int ret;
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, true);
+
+	sec_cmd_set_default_result(sec);
+
+	ret = read_pressure_data(ts, TYPE_RAW_DATA, pressure);
+	if (ret < 0) {
+		snprintf(buff, sizeof(buff), "%s", "WRITE FAILED");
+		goto error_read_rawdata;
+	}
+
+	snprintf(buff, sizeof(buff), "%d,%d,%d",
+		 pressure[2], pressure[1], pressure[0]);
+
+	sec->cmd_state = SEC_CMD_STATUS_OK;
+
+	sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
+
+	input_info(true, &ts->client->dev, "%s: %s\n", __func__, buff);
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+	return;
+
+error_read_rawdata:
+	sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
+	sec->cmd_state = SEC_CMD_STATUS_NOT_APPLICABLE;
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+}
+
+static void run_pressure_offset_read_all(void *device_data)
+{
+	struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data;
+	struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
+	char buff[SEC_CMD_STR_LEN] = {0};
+	short pressure[3] = { 0 };
+	int ret;
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, true);
+
+	sec_cmd_set_default_result(sec);
+
+	ret = read_pressure_data(ts, TYPE_OFFSET_DATA_SEC, pressure);
+	if (ret < 0) {
+		snprintf(buff, sizeof(buff), "%s", "WRITE FAILED");
+		goto error_read_str;
+	}
+
+	snprintf(buff, sizeof(buff), "%d,%d,%d",
+		 pressure[2], pressure[1], pressure[0]);
+
+	sec->cmd_state = SEC_CMD_STATUS_OK;
+
+	sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
+
+	input_info(true, &ts->client->dev, "%s: %s\n", __func__, buff);
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+	return;
+
+error_read_str:
+	sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
+	sec->cmd_state = SEC_CMD_STATUS_NOT_APPLICABLE;
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+}
+
+static void set_pressure_strength(void *device_data)
+{
+	struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data;
+	struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
+	char buff[SEC_CMD_STR_LEN] = {0};
+	u8 data[8] = { 0 };
+	u8 cal_data[18] = { 0 };
+	int index;
+	int ret;
+	short pressure[3] = { 0 };
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, true);
+
+	sec_cmd_set_default_result(sec);
+
+	if ((sec->cmd_param[0] < 1) || (sec->cmd_param[0] > 4))
+		goto err_cmd_param_str;
+
+	index = sec->cmd_param[0] - 1;
+
+	/* RIGHT */
+	cal_data[0] = (sec->cmd_param[3] >> 8);
+	cal_data[1] = (sec->cmd_param[3] & 0xFF);
+	/* CENTER */
+	cal_data[8] = (sec->cmd_param[2] >> 8);
+	cal_data[9] = (sec->cmd_param[2] & 0xFF);
+	/* LEFT */
+	cal_data[16] = (sec->cmd_param[1] >> 8);
+	cal_data[17] = (sec->cmd_param[1] & 0xFF);
+
+	ret = ts->sec_ts_write(ts, SEC_TS_CMD_SET_GET_PRESSURE, cal_data, 18);
+	if (ret < 0) {
+		input_err(true, &ts->client->dev,
+			  "%s: cmd write failed. ret: %d\n", __func__, ret);
+		goto err_comm_str;
+	}
+
+	sec_ts_delay(30);
+
+	memset(cal_data, 0x00, 18);
+	ret = ts->sec_ts_read(ts, SEC_TS_CMD_SET_GET_PRESSURE, cal_data, 18);
+	if (ret < 0) {
+		input_err(true, &ts->client->dev,
+			  "%s: cmd write failed. ret: %d\n", __func__, ret);
+		goto err_comm_str;
+	}
+
+	pressure[0] = ((cal_data[16] << 8) | cal_data[17]);
+	pressure[1] = ((cal_data[8] << 8) | cal_data[9]);
+	pressure[2] = ((cal_data[0] << 8) | cal_data[1]);
+
+	input_info(true, &ts->client->dev, "%s: [%d] : %d, %d, %d\n",
+		   __func__, pressure[0], pressure[1], pressure[2]);
+
+	/* Use TSP NV area : in this model, use only one byte
+	 * buff[0] : offset from user NVM storage
+	 * buff[1] : [n] length of stroed data - 1 (ex. using 1byte,
+	 *           value is  1 - 1 = 0)
+	 * buff[2] ... [n] : write data ...
+	 **/
+	data[0] = SEC_TS_NVM_OFFSET_PRESSURE_STRENGTH +
+			(index * SEC_TS_NVM_SIZE_PRESSURE_BLOCK);
+	data[1] = SEC_TS_NVM_SIZE_PRESSURE_BLOCK - 1;
+	/* RIGHT */
+	data[2] = (sec->cmd_param[3] >> 8);
+	data[3] = (sec->cmd_param[3] & 0xFF);
+	/* CENTER */
+	data[4] = (sec->cmd_param[2] >> 8);
+	data[5] = (sec->cmd_param[2] & 0xFF);
+	/*LEFT */
+	data[6] = (sec->cmd_param[1] >> 8);
+	data[7] = (sec->cmd_param[1] & 0xFF);
+
+	ret = ts->sec_ts_write(ts, SEC_TS_CMD_NVM, data, 8);
+	if (ret < 0) {
+		input_err(true, &ts->client->dev,
+			  "%s: nvm write failed. ret: %d\n", __func__, ret);
+		goto err_comm_str;
+	}
+
+	sec_ts_delay(20);
+
+	input_info(true, &ts->client->dev, "%s: [%d] : %d, %d, %d\n",
+		__func__, index,
+		(data[6] << 8) + data[7],
+		(data[4] << 8) + data[5],
+		(data[0] << 8) + data[1]);
+
+	memset(data, 0x00, 8);
+
+	data[0] = SEC_TS_NVM_OFFSET_PRESSURE_INDEX;
+	data[1] = 0;
+	data[2] = (u8)(index & 0xFF);
+
+	ret = ts->sec_ts_write(ts, SEC_TS_CMD_NVM, data, 3);
+	if (ret < 0) {
+		input_err(true, &ts->client->dev,
+			  "%s: nvm write failed. ret: %d\n", __func__, ret);
+		goto err_comm_str;
+	}
+
+	sec_ts_delay(20);
+
+	snprintf(buff, sizeof(buff), "%s", "OK");
+
+	sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
+	sec->cmd_state = SEC_CMD_STATUS_OK;
+
+	ts->pressure_cal_delta = get_tsp_nvm_data(ts,
+				SEC_TS_NVM_OFFSET_PRESSURE_DELTA_CAL_COUNT);
+	if (ts->pressure_cal_delta == 0xFF)
+		ts->pressure_cal_delta = 0;
+
+	if (ts->pressure_cal_delta > 0xFD)
+		ts->pressure_cal_delta = 0xFD;
+
+	/* Use TSP NV area : in this model, use only one byte
+	 * data[0] : offset from user NVM storage
+	 * data[1] : length of stroed data - 1 (ex. using 1byte,
+	 *           value is  1 - 1 = 0)
+	 * data[2] : write data
+	 **/
+	data[0] = SEC_TS_NVM_OFFSET_PRESSURE_DELTA_CAL_COUNT;
+	data[1] = 0;
+	data[2] = ts->pressure_cal_delta + 1;
+
+	ret = ts->sec_ts_write(ts, SEC_TS_CMD_NVM, data, 3);
+	if (ret < 0)
+		input_err(true, &ts->client->dev,
+			"%s: nvm write failed. ret: %d\n", __func__, ret);
+
+	ts->pressure_cal_delta = get_tsp_nvm_data(ts,
+				SEC_TS_NVM_OFFSET_PRESSURE_DELTA_CAL_COUNT);
+
+	input_info(true, &ts->client->dev,
+		   "%s: count: %d\n", __func__, ts->pressure_cal_delta);
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+	return;
+
+err_cmd_param_str:
+	input_info(true, &ts->client->dev, "%s: parameter error: %u\n",
+			__func__, sec->cmd_param[0]);
+err_comm_str:
+	snprintf(buff, sizeof(buff), "NG");
+	sec_cmd_set_cmd_result(sec, buff, strlen(buff));
+
+	sec->cmd_state = SEC_CMD_STATUS_FAIL;
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+}
+
+static void set_pressure_rawdata(void *device_data)
+{
+	struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data;
+	struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
+	char buff[SEC_CMD_STR_LEN] = {0};
+	u8 data[8] = { 0 };
+	int index;
+	int ret;
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, true);
+
+	sec_cmd_set_default_result(sec);
+
+	if ((sec->cmd_param[0] < 1) || (sec->cmd_param[0] > 4))
+		goto err_cmd_param_raw;
+
+	index = sec->cmd_param[0] - 1;
+
+	/* Use TSP NV area : in this model, use only one byte
+	 * buff[0] : offset from user NVM storage
+	 * buff[1] : [n] length of stroed data - 1 (ex. using 1byte,
+	 *           value is  1 - 1 = 0)
+	 * buff[2] ... [n] : write data ...
+	 **/
+	data[0] = SEC_TS_NVM_OFFSET_PRESSURE_RAWDATA +
+			(index * SEC_TS_NVM_SIZE_PRESSURE_BLOCK);
+	data[1] = SEC_TS_NVM_SIZE_PRESSURE_BLOCK - 1;
+	data[2] = (sec->cmd_param[3] >> 8);
+	data[3] = (sec->cmd_param[3] & 0xFF);
+	data[4] = (sec->cmd_param[2] >> 8);
+	data[5] = (sec->cmd_param[2] & 0xFF);
+	data[6] = (sec->cmd_param[1] >> 8);
+	data[7] = (sec->cmd_param[1] & 0xFF);
+
+	ret = ts->sec_ts_write(ts, SEC_TS_CMD_NVM, data, 8);
+	if (ret < 0) {
+		input_err(true, &ts->client->dev,
+			  "%s: nvm write failed. ret: %d\n", __func__, ret);
+		goto err_comm_raw;
+	}
+	sec_ts_delay(20);
+
+	memset(data, 0x00, 8);
+
+	ret = get_tsp_nvm_data_by_size(ts, SEC_TS_NVM_OFFSET_PRESSURE_RAWDATA +
+				(index * SEC_TS_NVM_SIZE_PRESSURE_BLOCK),
+				SEC_TS_NVM_SIZE_PRESSURE_BLOCK, data);
+	if (ret < 0) {
+		input_err(true, &ts->client->dev,
+			  "%s: nvm read failed. ret: %d\n", __func__, ret);
+		goto err_comm_raw;
+	}
+
+	snprintf(buff, sizeof(buff), "%s", "OK");
+
+	sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
+	sec->cmd_state = SEC_CMD_STATUS_OK;
+
+	input_info(true, &ts->client->dev, "%s: [%d] : %d, %d, %d\n",
+		__func__, index,
+		(data[4] << 8) + data[5],
+		(data[2] << 8) + data[3],
+		(data[1] << 8) + data[0]);
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+	return;
+
+err_cmd_param_raw:
+	input_info(true, &ts->client->dev, "%s: parameter error: %u\n",
+			__func__, sec->cmd_param[0]);
+err_comm_raw:
+
+	snprintf(buff, sizeof(buff), "NG");
+	sec_cmd_set_cmd_result(sec, buff, strlen(buff));
+
+	sec->cmd_state = SEC_CMD_STATUS_FAIL;
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+}
+
+static void set_pressure_data_index(void *device_data)
+{
+	struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data;
+	struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
+	char buff[SEC_CMD_STR_LEN] = {0};
+	u8 data[8] = { 0 };
+	u8 cal_data[18] = { 0 };
+	int index;
+	int ret;
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, true);
+
+	sec_cmd_set_default_result(sec);
+
+	if ((sec->cmd_param[0] < 0) || (sec->cmd_param[0] > 4))
+		goto err_set_cmd_param_index;
+
+	if (sec->cmd_param[0] == 0) {
+		input_info(true, &ts->client->dev,
+			   "%s: clear calibration result\n", __func__);
+		/* clear pressure calibrated data */
+		ret = ts->sec_ts_write(ts, SEC_TS_CMD_SET_GET_PRESSURE,
+				       cal_data, 18);
+		if (ret < 0) {
+			input_err(true, &ts->client->dev,
+				"%s: cmd write failed. ret: %d\n",
+				__func__, ret);
+			goto err_set_comm_index;
+		}
+
+		sec_ts_delay(30);
+
+		goto clear_index;
+	}
+
+	index = sec->cmd_param[0] - 1;
+
+	ret = get_tsp_nvm_data_by_size(ts, SEC_TS_NVM_OFFSET_PRESSURE_STRENGTH,
+				       24, data);
+	if (ret < 0) {
+		input_err(true, &ts->client->dev,
+			  "%s: nvm read failed. ret: %d\n", __func__, ret);
+		goto err_set_comm_index;
+	}
+
+	cal_data[16] = data[6 * index + 4];
+	cal_data[17] = data[6 * index + 5];	/* LEFT */
+
+	cal_data[8] = data[6 * index + 2];
+	cal_data[9] = data[6 * index + 3];	/* CENTER */
+
+	cal_data[0] = data[6 * index + 0];
+	cal_data[1] = data[6 * index + 1];	/* RIGHT */
+
+	ret = ts->sec_ts_write(ts, SEC_TS_CMD_SET_GET_PRESSURE, cal_data, 18);
+	if (ret < 0) {
+		input_err(true, &ts->client->dev,
+			  "%s: cmd write failed. ret: %d\n", __func__, ret);
+		goto err_set_comm_index;
+	}
+
+	sec_ts_delay(30);
+
+	/* Use TSP NV area : in this model, use only one byte
+	 * buff[0] : offset from user NVM storage
+	 * buff[1] : length of stroed data - 1 (ex. using 1byte,
+	 *           value is  1 - 1 = 0)
+	 * buff[2] : write data
+	 **/
+	memset(data, 0x00, 8);
+	data[0] = SEC_TS_NVM_OFFSET_PRESSURE_INDEX;
+	data[1] = 0;
+	data[2] = (u8)(index & 0xFF);
+
+	ret = ts->sec_ts_write(ts, SEC_TS_CMD_NVM, data, 3);
+	if (ret < 0) {
+		input_err(true, &ts->client->dev,
+			  "%s: nvm write failed. ret: %d\n", __func__, ret);
+		goto err_set_comm_index;
+	}
+
+	sec_ts_delay(20);
+
+clear_index:
+	snprintf(buff, sizeof(buff), "%s", "OK");
+
+	sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
+	sec->cmd_state = SEC_CMD_STATUS_OK;
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+	return;
+
+err_set_cmd_param_index:
+	input_info(true, &ts->client->dev, "%s: parameter error: %u\n",
+			__func__, sec->cmd_param[0]);
+err_set_comm_index:
+
+	snprintf(buff, sizeof(buff), "NG");
+	sec_cmd_set_cmd_result(sec, buff, strlen(buff));
+
+	sec->cmd_state = SEC_CMD_STATUS_FAIL;
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+}
+
+static void get_pressure_strength(void *device_data)
+{
+	struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data;
+	struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
+	char buff[SEC_CMD_STR_LEN] = {0};
+	int index;
+	u8 data[24] = { 0 };
+	short pressure[3] = { 0 };
+	int ret;
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, true);
+
+	sec_cmd_set_default_result(sec);
+
+	if ((sec->cmd_param[0] < 1) || (sec->cmd_param[0] > 4))
+		goto err_get_cmd_param_str;
+
+	index = sec->cmd_param[0] - 1;
+
+	ret = get_tsp_nvm_data_by_size(ts, SEC_TS_NVM_OFFSET_PRESSURE_STRENGTH,
+				       24, data);
+	if (ret < 0) {
+		input_err(true, &ts->client->dev,
+			  "%s: nvm read failed. ret: %d\n", __func__, ret);
+		goto err_get_comm_str;
+	}
+
+	pressure[0] = ((data[6 * index + 4] << 8) + data[6 * index + 5]);
+	pressure[1] = ((data[6 * index + 2] << 8) + data[6 * index + 3]);
+	pressure[2] = ((data[6 * index + 0] << 8) + data[6 * index + 1]);
+
+	snprintf(buff, sizeof(buff), "%d,%d,%d",
+		 pressure[0], pressure[1], pressure[2]);
+
+	sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
+	sec->cmd_state = SEC_CMD_STATUS_OK;
+
+	input_info(true, &ts->client->dev, "%s: [%d] : %d, %d, %d\n",
+		__func__, index, pressure[0], pressure[1], pressure[2]);
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+	return;
+
+err_get_comm_str:
+	input_info(true, &ts->client->dev, "%s: parameter error: %u\n",
+			__func__, sec->cmd_param[0]);
+err_get_cmd_param_str:
+
+	snprintf(buff, sizeof(buff), "NG");
+	sec_cmd_set_cmd_result(sec, buff, strlen(buff));
+
+	sec->cmd_state = SEC_CMD_STATUS_FAIL;
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+}
+
+static void get_pressure_rawdata(void *device_data)
+{
+	struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data;
+	struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
+	char buff[SEC_CMD_STR_LEN] = {0};
+	int index;
+	u8 data[24] = { 0 };
+	short pressure[3] = { 0 };
+	int ret;
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, true);
+
+	sec_cmd_set_default_result(sec);
+
+	if ((sec->cmd_param[0] < 1) || (sec->cmd_param[0] > 4))
+		goto err_get_cmd_param_raw;
+
+	index = sec->cmd_param[0] - 1;
+
+	ret = get_tsp_nvm_data_by_size(ts, SEC_TS_NVM_OFFSET_PRESSURE_RAWDATA,
+				       24, data);
+	if (ret < 0) {
+		input_err(true, &ts->client->dev,
+			  "%s: nvm read failed. ret: %d\n", __func__, ret);
+		goto err_get_comm_raw;
+	}
+
+	pressure[0] = ((data[6 * index + 4] << 8) + data[6 * index + 5]);
+	pressure[1] = ((data[6 * index + 2] << 8) + data[6 * index + 3]);
+	pressure[2] = ((data[6 * index + 0] << 8) + data[6 * index + 1]);
+
+	snprintf(buff, sizeof(buff), "%d,%d,%d",
+		 pressure[0], pressure[1], pressure[2]);
+
+	sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
+	sec->cmd_state = SEC_CMD_STATUS_OK;
+
+	input_info(true, &ts->client->dev, "%s: [%d] : %d, %d, %d\n",
+		__func__, index, pressure[0], pressure[1], pressure[2]);
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+	return;
+err_get_cmd_param_raw:
+	input_info(true, &ts->client->dev, "%s: parameter error: %u\n",
+			__func__, sec->cmd_param[0]);
+err_get_comm_raw:
+
+	snprintf(buff, sizeof(buff), "NG");
+	sec_cmd_set_cmd_result(sec, buff, strlen(buff));
+
+	sec->cmd_state = SEC_CMD_STATUS_FAIL;
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+}
+
+static void get_pressure_data_index(void *device_data)
+{
+	struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data;
+	struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
+	char buff[SEC_CMD_STR_LEN] = {0};
+	int index = 0;
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, true);
+
+	sec_cmd_set_default_result(sec);
+
+	index = get_tsp_nvm_data(ts, SEC_TS_NVM_OFFSET_PRESSURE_INDEX);
+	if (index < 0) {
+		goto err_get_index;
+	} else {
+		if (index == 0xFF)
+			snprintf(buff, sizeof(buff), "%d", 0);
+		else
+			snprintf(buff, sizeof(buff), "%d", index + 1);
+	}
+
+	sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
+	sec->cmd_state = SEC_CMD_STATUS_OK;
+
+	input_info(true, &ts->client->dev, "%s: %d\n",
+		__func__, index);
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+	return;
+
+err_get_index:
+
+	snprintf(buff, sizeof(buff), "NG");
+	sec_cmd_set_cmd_result(sec, buff, strlen(buff));
+
+	sec->cmd_state = SEC_CMD_STATUS_FAIL;
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+}
+static void set_pressure_strength_clear(void *device_data)
+{
+	struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data;
+	struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
+	char buff[SEC_CMD_STR_LEN] = {0};
+	u8 *data;
+	u8 cal_data[18] = { 0 };
+	int ret;
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, true);
+
+	sec_cmd_set_default_result(sec);
+
+	/* clear pressure calibrated data */
+	ret = ts->sec_ts_write(ts, SEC_TS_CMD_SET_GET_PRESSURE, cal_data, 18);
+	if (ret < 0) {
+		input_err(true, &ts->client->dev,
+			  "%s: cmd write failed. ret: %d\n", __func__, ret);
+		goto err_comm_str;
+	}
+
+	sec_ts_delay(30);
+
+	/* Use TSP NV area : in this model, use only one byte
+	 * buff[0] : offset from user NVM storage
+	 * buff[1] : length of stroed data - 1 (ex. using 1byte,
+	 *           value is  1 - 1 = 0)
+	 * buff[2] : write data
+	 **/
+
+	/* strength 6 * 4,  rawdata 6 * 4, buff[0], buff[1] */
+	data = kzalloc(50, GFP_KERNEL);
+	if (!data) {
+		input_err(true, &ts->client->dev,
+			"%s failed to allocate memory. ret: %d\n",
+			__func__, ret);
+		goto err_comm_str;
+	}
+
+	data[0] = SEC_TS_NVM_OFFSET_PRESSURE_INDEX;
+	data[1] = (SEC_TS_NVM_SIZE_PRESSURE_BLOCK * 8) - 1;
+
+	/* remove calicated strength, rawdata in NVM */
+	ret = ts->sec_ts_write(ts, SEC_TS_CMD_NVM, data, 50);
+	if (ret < 0) {
+		input_err(true, &ts->client->dev,
+			  "%s: nvm write failed. ret: %d\n", __func__, ret);
+		goto err_mem_str;
+	}
+
+	sec_ts_delay(20);
+
+	snprintf(buff, sizeof(buff), "%s", "OK");
+
+	kfree(data);
+
+	sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
+	sec->cmd_state = SEC_CMD_STATUS_OK;
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+	return;
+
+err_mem_str:
+	kfree(data);
+err_comm_str:
+	snprintf(buff, sizeof(buff), "NG");
+	sec_cmd_set_cmd_result(sec, buff, strlen(buff));
+
+	sec->cmd_state = SEC_CMD_STATUS_FAIL;
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+}
+
+static void get_pressure_threshold(void *device_data)
+{
+	struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data;
+	char buff[SEC_CMD_STR_LEN] = {0};
+
+	sec_cmd_set_default_result(sec);
+
+	snprintf(buff, sizeof(buff), "300");
+
+	sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
+	sec->cmd_state = SEC_CMD_STATUS_OK;
+}
+
+/* low level is more sensitivity, except level-0(value 0) */
+static void set_pressure_user_level(void *device_data)
+{
+	struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data;
+	struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
+	char buff[SEC_CMD_STR_LEN] = {0};
+	int ret;
+	char addr[3] = { 0 };
+	char data[2] = { 0 };
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, true);
+
+	sec_cmd_set_default_result(sec);
+
+	if (ts->power_status == SEC_TS_STATE_POWER_OFF) {
+		input_err(true, &ts->client->dev, "%s: Touch is stopped!\n",
+			  __func__);
+		snprintf(buff, sizeof(buff), "%s", "TSP turned off");
+		sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
+		sec->cmd_state = SEC_CMD_STATUS_NOT_APPLICABLE;
+
+		sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+		return;
+	}
+
+	if ((sec->cmd_param[0] < 1) || (sec->cmd_param[0] > 5))
+		goto out_set_user_level;
+
+	/*
+	 * byte[0]: m_customlib_ifpacket_addr[7:0]
+	 * byte[1]: m_customlib_ifpacket_addr[15:8]
+	 * byte[n] : user data (max 32 bytes)
+	 */
+	addr[0] = SEC_TS_CMD_CUSTOMLIB_OFFSET_PRESSURE_LEVEL;
+	addr[1] = 0x00;
+	addr[2] = sec->cmd_param[0];
+
+	ret = ts->sec_ts_write(ts, SEC_TS_CMD_CUSTOMLIB_WRITE_PARAM, addr, 3);
+	if (ret < 0)
+		goto out_set_user_level;
+
+	ret = ts->sec_ts_write(ts, SEC_TS_CMD_CUSTOMLIB_NOTIFY_PACKET, NULL, 0);
+	if (ret < 0)
+		goto out_set_user_level;
+
+	ret = ts->sec_ts_write(ts, SEC_TS_CMD_CUSTOMLIB_READ_PARAM, addr, 2);
+	if (ret < 0)
+		goto out_set_user_level;
+
+	ret = ts->sec_ts_read(ts, SEC_TS_CMD_CUSTOMLIB_READ_PARAM, data, 1);
+	if (ret < 0)
+		goto out_set_user_level;
+
+	input_info(true, &ts->client->dev, "%s: set user level: %d\n",
+		   __func__, data[0]);
+
+	ts->pressure_user_level = data[0];
+
+	addr[0] = SEC_TS_CMD_CUSTOMLIB_OFFSET_PRESSURE_THD_HIGH;
+	ret = ts->sec_ts_write(ts, SEC_TS_CMD_CUSTOMLIB_READ_PARAM, addr, 2);
+	if (ret < 0)
+		goto out_set_user_level;
+
+	ret = ts->sec_ts_read(ts, SEC_TS_CMD_CUSTOMLIB_READ_PARAM, data, 1);
+	if (ret < 0)
+		goto out_set_user_level;
+
+	input_info(true, &ts->client->dev, "%s: HIGH THD: %d\n",
+		   __func__, data[0]);
+
+	addr[0] = SEC_TS_CMD_CUSTOMLIB_OFFSET_PRESSURE_THD_LOW;
+
+	ret = ts->sec_ts_write(ts, SEC_TS_CMD_CUSTOMLIB_READ_PARAM, addr, 2);
+	if (ret < 0)
+		goto out_set_user_level;
+
+	ret = ts->sec_ts_read(ts, SEC_TS_CMD_CUSTOMLIB_READ_PARAM, data, 1);
+	if (ret < 0)
+		goto out_set_user_level;
+
+	input_info(true, &ts->client->dev, "%s: LOW THD: %d\n",
+		   __func__, data[0]);
+
+	snprintf(buff, sizeof(buff), "%s", "OK");
+
+	sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
+	sec->cmd_state = SEC_CMD_STATUS_OK;
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+	return;
+
+out_set_user_level:
+	snprintf(buff, sizeof(buff), "%s", "NG");
+	sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
+	sec->cmd_state = SEC_CMD_STATUS_FAIL;
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+}
+
+static void get_pressure_user_level(void *device_data)
+{
+	struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data;
+	struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
+	char buff[SEC_CMD_STR_LEN] = {0};
+	char addr[3] = { 0 };
+	char data[2] = { 0 };
+	int ret;
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, true);
+
+	sec_cmd_set_default_result(sec);
+
+	snprintf(buff, sizeof(buff), "%d", ts->pressure_user_level);
+
+	sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
+
+	addr[0] = SEC_TS_CMD_CUSTOMLIB_OFFSET_PRESSURE_LEVEL;
+	addr[1] = 0x00;
+
+	ret = ts->sec_ts_write(ts, SEC_TS_CMD_CUSTOMLIB_READ_PARAM, addr, 2);
+	if (ret < 0)
+		goto out_get_user_level;
+
+	ret = ts->sec_ts_read(ts, SEC_TS_CMD_CUSTOMLIB_READ_PARAM, data, 1);
+	if (ret < 0)
+		goto out_get_user_level;
+
+	input_err(true, &ts->client->dev, "%s: set user level: %d\n",
+		  __func__, data[0]);
+	ts->pressure_user_level = data[0];
+
+	snprintf(buff, sizeof(buff), "%s", "OK");
+	sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
+	sec->cmd_state = SEC_CMD_STATUS_OK;
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+	return;
+
+out_get_user_level:
+	snprintf(buff, sizeof(buff), "%s", "NG");
+	sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
+	sec->cmd_state = SEC_CMD_STATUS_FAIL;
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+}
+#endif
+
+static void set_lowpower_mode(void *device_data)
+{
+	struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data;
+	struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
+	char buff[SEC_CMD_STR_LEN] = { 0 };
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, true);
+
+	sec_cmd_set_default_result(sec);
+
+	if (sec->cmd_param[0] < 0 || sec->cmd_param[0] > 1) {
+		snprintf(buff, sizeof(buff), "%s", "NG");
+		sec->cmd_state = SEC_CMD_STATUS_FAIL;
+	} else {
+		snprintf(buff, sizeof(buff), "%s", "OK");
+		sec->cmd_state = SEC_CMD_STATUS_OK;
+	}
+
+/* set lowpower mode by spay, edge_swipe function.
+ *	ts->lowpower_mode = sec->cmd_param[0];
+ **/
+	sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
+
+	sec_cmd_set_cmd_exit(sec);
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+}
+
+static void set_wirelesscharger_mode(void *device_data)
+{
+	struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data;
+	struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
+	char buff[SEC_CMD_STR_LEN] = { 0 };
+	int ret;
+	bool mode;
+	u8 w_data[1] = {0x00};
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, true);
+
+	sec_cmd_set_default_result(sec);
+
+	if (sec->cmd_param[0] < 0 || sec->cmd_param[0] > 3)
+		goto OUT;
+
+	if (sec->cmd_param[0] == 0) {
+		ts->charger_mode |= SEC_TS_BIT_CHARGER_MODE_NO;
+		mode = false;
+	} else {
+		ts->charger_mode &= (~SEC_TS_BIT_CHARGER_MODE_NO);
+		mode = true;
+	}
+
+	if (ts->power_status == SEC_TS_STATE_POWER_OFF) {
+		input_err(true, &ts->client->dev,
+			  "%s: fail to enable w-charger status, POWER_STATUS=OFF\n",
+			  __func__);
+		goto NG;
+	}
+
+	if (sec->cmd_param[0] == 1)
+		ts->charger_mode = ts->charger_mode |
+				SEC_TS_BIT_CHARGER_MODE_WIRELESS_CHARGER;
+	else if (sec->cmd_param[0] == 3)
+		ts->charger_mode = ts->charger_mode |
+				SEC_TS_BIT_CHARGER_MODE_WIRELESS_BATTERY_PACK;
+	else if (mode == false)
+		ts->charger_mode = ts->charger_mode &
+			(~SEC_TS_BIT_CHARGER_MODE_WIRELESS_CHARGER) &
+			(~SEC_TS_BIT_CHARGER_MODE_WIRELESS_BATTERY_PACK);
+
+	w_data[0] = ts->charger_mode;
+	ret = ts->sec_ts_write(ts, SET_TS_CMD_SET_CHARGER_MODE, w_data, 1);
+	if (ret < 0) {
+		input_err(true, &ts->client->dev,
+			  "%s: Failed to send command 74\n", __func__);
+		goto NG;
+	}
+
+	input_err(true, &ts->client->dev, "%s: %s, status =%x\n",
+		__func__, (mode) ? "wireless enable" : "wireless disable",
+		ts->charger_mode);
+
+	snprintf(buff, sizeof(buff), "%s", "OK");
+	sec->cmd_state = SEC_CMD_STATUS_OK;
+	sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
+	sec_cmd_set_cmd_exit(sec);
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+	return;
+
+NG:
+	input_err(true, &ts->client->dev, "%s: %s, status =%x\n",
+		__func__, (mode) ? "wireless enable" : "wireless disable",
+		ts->charger_mode);
+
+OUT:
+	snprintf(buff, sizeof(buff), "%s", "NG");
+	sec->cmd_state = SEC_CMD_STATUS_FAIL;
+	sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
+	sec_cmd_set_cmd_exit(sec);
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+}
+
+static void spay_enable(void *device_data)
+{
+	struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data;
+	struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
+	char buff[SEC_CMD_STR_LEN] = { 0 };
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, true);
+
+	sec_cmd_set_default_result(sec);
+
+	if (sec->cmd_param[0] < 0 || sec->cmd_param[0] > 1)
+		goto NG;
+
+	if (sec->cmd_param[0]) {
+		if (ts->use_customlib)
+			ts->lowpower_mode |= SEC_TS_MODE_CUSTOMLIB_SPAY;
+	} else {
+		if (ts->use_customlib)
+			ts->lowpower_mode &= ~SEC_TS_MODE_CUSTOMLIB_SPAY;
+	}
+
+	input_info(true, &ts->client->dev,
+		   "%s: %02X\n", __func__, ts->lowpower_mode);
+
+	#ifdef SEC_TS_SUPPORT_CUSTOMLIB
+	if (ts->use_customlib)
+		sec_ts_set_custom_library(ts);
+	#endif
+
+	snprintf(buff, sizeof(buff), "%s", "OK");
+	sec->cmd_state = SEC_CMD_STATUS_OK;
+	sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
+	sec_cmd_set_cmd_exit(sec);
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+	return;
+
+NG:
+	snprintf(buff, sizeof(buff), "%s", "NG");
+	sec->cmd_state = SEC_CMD_STATUS_FAIL;
+	sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
+	sec_cmd_set_cmd_exit(sec);
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+}
+
+static void set_aod_rect(void *device_data)
+{
+	struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data;
+	struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
+	char buff[SEC_CMD_STR_LEN] = { 0 };
+	u8 data[10] = {0x02, 0};
+	int ret, i;
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, true);
+
+	sec_cmd_set_default_result(sec);
+
+	input_info(true, &ts->client->dev, "%s: w: %d, h: %d, x: %d, y: %d\n",
+			__func__, sec->cmd_param[0], sec->cmd_param[1],
+			sec->cmd_param[2], sec->cmd_param[3]);
+
+	for (i = 0; i < 4; i++) {
+		data[i * 2 + 2] = sec->cmd_param[i] & 0xFF;
+		data[i * 2 + 3] = (sec->cmd_param[i] >> 8) & 0xFF;
+		ts->rect_data[i] = sec->cmd_param[i];
+	}
+
+	if (ts->use_customlib) {
+		disable_irq(ts->client->irq);
+		ret = ts->sec_ts_write(ts, SEC_TS_CMD_CUSTOMLIB_WRITE_PARAM,
+				       &data[0], 10);
+		if (ret < 0) {
+			input_err(true, &ts->client->dev,
+				  "%s: Failed to write offset\n", __func__);
+			goto NG;
+		}
+
+		ret = ts->sec_ts_write(ts, SEC_TS_CMD_CUSTOMLIB_NOTIFY_PACKET,
+				       NULL, 0);
+		if (ret < 0) {
+			input_err(true, &ts->client->dev,
+				  "%s: Failed to send notify\n", __func__);
+			goto NG;
+		}
+		enable_irq(ts->client->irq);
+	}
+
+	snprintf(buff, sizeof(buff), "%s", "OK");
+	sec->cmd_state = SEC_CMD_STATUS_OK;
+	sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
+	sec_cmd_set_cmd_exit(sec);
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+	return;
+NG:
+	enable_irq(ts->client->irq);
+	snprintf(buff, sizeof(buff), "%s", "NG");
+	sec->cmd_state = SEC_CMD_STATUS_FAIL;
+	sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
+	sec_cmd_set_cmd_exit(sec);
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+}
+
+
+static void get_aod_rect(void *device_data)
+{
+	struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data;
+	struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
+	char buff[SEC_CMD_STR_LEN] = { 0 };
+	u8 data[8] = {0x02, 0};
+	u16 rect_data[4] = {0, };
+	int ret, i;
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, true);
+
+	sec_cmd_set_default_result(sec);
+
+	if (ts->use_customlib) {
+		disable_irq(ts->client->irq);
+		ret = ts->sec_ts_read_customlib(ts, data, 8);
+		if (ret < 0) {
+			input_err(true, &ts->client->dev,
+				  "%s: Failed to read rect\n", __func__);
+			goto NG;
+		}
+		enable_irq(ts->client->irq);
+	}
+
+	for (i = 0; i < 4; i++)
+		rect_data[i] = (data[i * 2 + 1] & 0xFF) << 8 |
+					(data[i * 2] & 0xFF);
+
+	input_info(true, &ts->client->dev, "%s: w: %d, h: %d, x: %d, y: %d\n",
+			__func__,
+			rect_data[0], rect_data[1], rect_data[2], rect_data[3]);
+
+	snprintf(buff, sizeof(buff), "%s", "OK");
+	sec->cmd_state = SEC_CMD_STATUS_OK;
+	sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
+	sec_cmd_set_cmd_exit(sec);
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+	return;
+NG:
+	enable_irq(ts->client->irq);
+	snprintf(buff, sizeof(buff), "%s", "NG");
+	sec->cmd_state = SEC_CMD_STATUS_FAIL;
+	sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
+	sec_cmd_set_cmd_exit(sec);
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+}
+
+static void aod_enable(void *device_data)
+{
+	struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data;
+	struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
+	char buff[SEC_CMD_STR_LEN] = { 0 };
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, true);
+
+	sec_cmd_set_default_result(sec);
+
+	if (sec->cmd_param[0] < 0 || sec->cmd_param[0] > 1)
+		goto NG;
+
+	if (sec->cmd_param[0]) {
+		if (ts->use_customlib)
+			ts->lowpower_mode |= SEC_TS_MODE_CUSTOMLIB_AOD;
+	} else {
+		if (ts->use_customlib)
+			ts->lowpower_mode &= ~SEC_TS_MODE_CUSTOMLIB_AOD;
+	}
+
+	input_info(true, &ts->client->dev,
+		   "%s: %02X\n", __func__, ts->lowpower_mode);
+
+	#ifdef SEC_TS_SUPPORT_CUSTOMLIB
+	if (ts->use_customlib)
+		sec_ts_set_custom_library(ts);
+	#endif
+
+	snprintf(buff, sizeof(buff), "%s", "OK");
+	sec->cmd_state = SEC_CMD_STATUS_OK;
+	sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
+	sec_cmd_set_cmd_exit(sec);
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+	return;
+
+NG:
+	snprintf(buff, sizeof(buff), "%s", "NG");
+	sec->cmd_state = SEC_CMD_STATUS_FAIL;
+	sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
+	sec_cmd_set_cmd_exit(sec);
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+}
+
+/*
+ *	flag     1  :  set edge handler
+ *		2  :  set (portrait, normal) edge zone data
+ *		4  :  set (portrait, normal) dead zone data
+ *		8  :  set landscape mode data
+ *		16 :  mode clear
+ *	data
+ *		0x30, FFF (y start), FFF (y end),  FF(direction)
+ *		0x31, FFFF (edge zone)
+ *		0x32, FF (up x), FF (down x), FFFF (y)
+ *		0x33, FF (mode), FFF (edge), FFF (dead zone)
+ *	case
+ *		edge handler set :  0x30....
+ *		booting time :  0x30...  + 0x31...
+ *		normal mode : 0x32...  (+0x31...)
+ *		landscape mode : 0x33...
+ *		landscape -> normal (if same with old data) : 0x33, 0
+ *		landscape -> normal (etc) : 0x32....  + 0x33, 0
+ */
+
+void set_grip_data_to_ic(struct sec_ts_data *ts, u8 flag)
+{
+	u8 data[8] = { 0 };
+
+	input_info(true, &ts->client->dev, "%s: flag: %02X (clr,lan,nor,edg,han)\n",
+		   __func__, flag);
+
+	if (flag & G_SET_EDGE_HANDLER) {
+		if (ts->grip_edgehandler_direction == 0) {
+			data[0] = 0x0;
+			data[1] = 0x0;
+			data[2] = 0x0;
+			data[3] = 0x0;
+		} else {
+			data[0] = (ts->grip_edgehandler_start_y >> 4) & 0xFF;
+			data[1] = (ts->grip_edgehandler_start_y << 4 & 0xF0) |
+				((ts->grip_edgehandler_end_y >> 8) & 0xF);
+			data[2] = ts->grip_edgehandler_end_y & 0xFF;
+			data[3] = ts->grip_edgehandler_direction & 0x3;
+		}
+		ts->sec_ts_write(ts, SEC_TS_CMD_EDGE_HANDLER, data, 4);
+		input_info(true, &ts->client->dev, "%s: 0x%02X %02X,%02X,%02X,%02X\n",
+			__func__, SEC_TS_CMD_EDGE_HANDLER,
+			data[0], data[1], data[2], data[3]);
+	}
+
+	if (flag & G_SET_EDGE_ZONE) {
+		data[0] = (ts->grip_edge_range >> 8) & 0xFF;
+		data[1] = ts->grip_edge_range  & 0xFF;
+		ts->sec_ts_write(ts, SEC_TS_CMD_EDGE_AREA, data, 2);
+		input_info(true, &ts->client->dev, "%s: 0x%02X %02X,%02X\n",
+			__func__, SEC_TS_CMD_EDGE_AREA, data[0], data[1]);
+	}
+
+	if (flag & G_SET_NORMAL_MODE) {
+		data[0] = ts->grip_deadzone_up_x & 0xFF;
+		data[1] = ts->grip_deadzone_dn_x & 0xFF;
+		data[2] = (ts->grip_deadzone_y >> 8) & 0xFF;
+		data[3] = ts->grip_deadzone_y & 0xFF;
+		ts->sec_ts_write(ts, SEC_TS_CMD_DEAD_ZONE, data, 4);
+		input_info(true, &ts->client->dev, "%s: 0x%02X %02X,%02X,%02X,%02X\n",
+			__func__, SEC_TS_CMD_DEAD_ZONE,
+			data[0], data[1], data[2], data[3]);
+	}
+
+	if (flag & G_SET_LANDSCAPE_MODE) {
+		data[0] = ts->grip_landscape_mode & 0x1;
+		data[1] = (ts->grip_landscape_edge >> 4) & 0xFF;
+		data[2] = (ts->grip_landscape_edge << 4 & 0xF0) |
+				((ts->grip_landscape_deadzone >> 8) & 0xF);
+		data[3] = ts->grip_landscape_deadzone & 0xFF;
+		ts->sec_ts_write(ts, SEC_TS_CMD_LANDSCAPE_MODE, data, 4);
+		input_info(true, &ts->client->dev, "%s: 0x%02X %02X,%02X,%02X,%02X\n",
+			__func__, SEC_TS_CMD_LANDSCAPE_MODE,
+			data[0], data[1], data[2], data[3]);
+	}
+
+	if (flag & G_CLR_LANDSCAPE_MODE) {
+		data[0] = ts->grip_landscape_mode;
+		ts->sec_ts_write(ts, SEC_TS_CMD_LANDSCAPE_MODE, data, 1);
+		input_info(true, &ts->client->dev, "%s: 0x%02X %02X\n",
+			__func__, SEC_TS_CMD_LANDSCAPE_MODE, data[0]);
+	}
+}
+
+/*
+ * index  0 :  set edge handler
+ *  1 :  portrait (normal) mode
+ *  2 :  landscape mode
+ *
+ * data
+ *  0, X (direction), X (y start), X (y end)
+ *  direction : 0 (off), 1 (left), 2 (right)
+ *	ex) echo set_grip_data,0,2,600,900 > cmd
+ *
+ *  1, X (edge zone), X (dead zone up x), X (dead zone down x), X (dead zone y)
+ *	ex) echo set_grip_data,1,200,10,50,1500 > cmd
+ *
+ *  2, 1 (landscape mode), X (edge zone), X (dead zone)
+ *	ex) echo set_grip_data,2,1,200,100 > cmd
+ *
+ *2, 0 (portrait mode)
+ *	ex) echo set_grip_data,2,0  > cmd
+ */
+
+static void set_grip_data(void *device_data)
+{
+	struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data;
+	struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
+	char buff[SEC_CMD_STR_LEN] = { 0 };
+	/* u8 mode = G_NONE; */
+	u8 tPara[2] = { 0 };
+	int ret;
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, true);
+
+	sec_cmd_set_default_result(sec);
+
+	memset(buff, 0, sizeof(buff));
+
+	mutex_lock(&ts->device_mutex);
+
+	tPara[0] = sec->cmd_param[0] & 0xFF;
+	tPara[1] = (sec->cmd_param[0] >> 8) & 0xFF;
+
+	ret = ts->sec_ts_write(ts, SEC_TS_CMD_DEADZONE_RANGE, tPara, 2);
+	if (ret < 0)
+		goto err_grip_data;
+/*
+ *	if (sec->cmd_param[0] == 0) {	// edge handler
+ *		if (sec->cmd_param[1] == 0) {	// clear
+ *			ts->grip_edgehandler_direction = 0;
+ *		} else if (sec->cmd_param[1] < 3) {
+ *			ts->grip_edgehandler_direction = sec->cmd_param[1];
+ *			ts->grip_edgehandler_start_y = sec->cmd_param[2];
+ *			ts->grip_edgehandler_end_y = sec->cmd_param[3];
+ *		} else {
+ *			input_err(true, &ts->client->dev,
+ *				"%s: cmd1 is abnormal, %d (%d)\n",
+ *				__func__, sec->cmd_param[1], __LINE__);
+ *			goto err_grip_data;
+ *		}
+ *
+ *		mode = mode | G_SET_EDGE_HANDLER;
+ *		set_grip_data_to_ic(ts, mode);
+ *
+ *	} else if (sec->cmd_param[0] == 1) {	// normal mode
+ *		if (ts->grip_edge_range != sec->cmd_param[1])
+ *			mode = mode | G_SET_EDGE_ZONE;
+ *
+ *		ts->grip_edge_range = sec->cmd_param[1];
+ *		ts->grip_deadzone_up_x = sec->cmd_param[2];
+ *		ts->grip_deadzone_dn_x = sec->cmd_param[3];
+ *		ts->grip_deadzone_y = sec->cmd_param[4];
+ *		mode = mode | G_SET_NORMAL_MODE;
+ *
+ *		if (ts->grip_landscape_mode == 1) {
+ *			ts->grip_landscape_mode = 0;
+ *			mode = mode | G_CLR_LANDSCAPE_MODE;
+ *		}
+ *		set_grip_data_to_ic(ts, mode);
+ *	} else if (sec->cmd_param[0] == 2) {	// landscape mode
+ *		if (sec->cmd_param[1] == 0) {	// normal mode
+ *			ts->grip_landscape_mode = 0;
+ *			mode = mode | G_CLR_LANDSCAPE_MODE;
+ *		} else if (sec->cmd_param[1] == 1) {
+ *			ts->grip_landscape_mode = 1;
+ *			ts->grip_landscape_edge = sec->cmd_param[2];
+ *			ts->grip_landscape_deadzone	= sec->cmd_param[3];
+ *			mode = mode | G_SET_LANDSCAPE_MODE;
+ *		} else {
+ *			input_err(true, &ts->client->dev,
+ *				"%s: cmd1 is abnormal, %d (%d)\n",
+ *				__func__, sec->cmd_param[1], __LINE__);
+ *			goto err_grip_data;
+ *		}
+ *		set_grip_data_to_ic(ts, mode);
+ *	} else {
+ *		input_err(true, &ts->client->dev,
+ *			"%s: cmd0 is abnormal, %d",
+ *			__func__, sec->cmd_param[0]);
+ *		goto err_grip_data;
+ *	}
+ **/
+
+	mutex_unlock(&ts->device_mutex);
+
+	snprintf(buff, sizeof(buff), "%s", "OK");
+	sec->cmd_state = SEC_CMD_STATUS_OK;
+	sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
+	sec_cmd_set_cmd_exit(sec);
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+	return;
+
+err_grip_data:
+	mutex_unlock(&ts->device_mutex);
+
+	snprintf(buff, sizeof(buff), "%s", "NG");
+	sec->cmd_state = SEC_CMD_STATUS_FAIL;
+	sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
+	sec_cmd_set_cmd_exit(sec);
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+}
+
+/*
+ * Set/Get Dex Mode 0xE7
+ *  0: Disable dex mode
+ *  1: Full screen mode
+ *  2: Iris mode
+ */
+static void dex_enable(void *device_data)
+{
+	struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data;
+	struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
+	char buff[SEC_CMD_STR_LEN] = { 0 };
+	int ret;
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, true);
+
+	sec_cmd_set_default_result(sec);
+
+	if (!ts->plat_data->support_dex) {
+		input_err(true, &ts->client->dev, "%s: not support DeX mode\n",
+			  __func__);
+		goto NG;
+	}
+
+	if ((sec->cmd_param[0] < 0 || sec->cmd_param[0] > 1) &&
+		(sec->cmd_param[1] < 0 || sec->cmd_param[1] > 1)) {
+		input_err(true, &ts->client->dev, "%s: not support param\n",
+			  __func__);
+		goto NG;
+	}
+
+	ts->dex_mode = sec->cmd_param[0];
+	if (ts->dex_mode) {
+		input_err(true, &ts->client->dev, "%s: set DeX touch_pad mode%s\n",
+			__func__, sec->cmd_param[1] ? " & Iris mode" : "");
+		ts->input_dev = ts->input_dev_pad;
+		if (sec->cmd_param[1]) {
+			/* Iris mode */
+			ts->dex_mode = 0x02;
+			ts->dex_name = "[DeXI]";
+		} else {
+			ts->dex_name = "[DeX]";
+		}
+	} else {
+		input_err(true, &ts->client->dev, "%s: set touch mode\n",
+			  __func__);
+		ts->input_dev = ts->input_dev_touch;
+		ts->dex_name = "";
+	}
+
+	if (ts->power_status == SEC_TS_STATE_POWER_OFF) {
+		input_err(true, &ts->client->dev, "%s: Touch is stopped!\n",
+			  __func__);
+		goto NG;
+	}
+
+	ret = ts->sec_ts_write(ts, SEC_TS_CMD_SET_DEX_MODE, &ts->dex_mode, 1);
+	if (ret < 0) {
+		input_err(true, &ts->client->dev,
+				"%s: failed to set dex %smode\n", __func__,
+				sec->cmd_param[1] ? "iris " : "");
+		goto NG;
+	}
+
+	snprintf(buff, sizeof(buff), "%s", "OK");
+	sec->cmd_state = SEC_CMD_STATUS_OK;
+	sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
+	sec_cmd_set_cmd_exit(sec);
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+	return;
+
+NG:
+	snprintf(buff, sizeof(buff), "%s", "NG");
+	sec->cmd_state = SEC_CMD_STATUS_FAIL;
+	sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
+	sec_cmd_set_cmd_exit(sec);
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+}
+
+static void brush_enable(void *device_data)
+{
+	struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data;
+	struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
+	char buff[SEC_CMD_STR_LEN] = { 0 };
+	int ret;
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, true);
+
+	sec_cmd_set_default_result(sec);
+
+	if (sec->cmd_param[0] < 0 || sec->cmd_param[0] > 1) {
+		snprintf(buff, sizeof(buff), "%s", "NG");
+		sec->cmd_state = SEC_CMD_STATUS_FAIL;
+		goto out;
+	}
+
+	ts->brush_mode = sec->cmd_param[0];
+
+	if (ts->power_status == SEC_TS_STATE_POWER_OFF) {
+		input_err(true, &ts->client->dev,
+			"%s: Touch is stopped!\n", __func__);
+		snprintf(buff, sizeof(buff), "%s", "TSP turned off");
+		sec->cmd_state = SEC_CMD_STATUS_NOT_APPLICABLE;
+		goto out;
+	}
+
+	input_info(true, &ts->client->dev,
+		"%s: set brush mode %s\n", __func__,
+		ts->brush_mode ? "enable" : "disable");
+
+	/* - 0: Disable Artcanvas min phi mode
+	 * - 1: Enable Artcanvas min phi mode
+	 **/
+	ret = ts->sec_ts_write(ts, SEC_TS_CMD_SET_BRUSH_MODE,
+				&ts->brush_mode, 1);
+	if (ret < 0) {
+		input_err(true, &ts->client->dev,
+				"%s: failed to set brush mode\n", __func__);
+		snprintf(buff, sizeof(buff), "%s", "NG");
+		sec->cmd_state = SEC_CMD_STATUS_FAIL;
+		goto out;
+	}
+
+	snprintf(buff, sizeof(buff), "%s", "OK");
+	sec->cmd_state = SEC_CMD_STATUS_OK;
+out:
+	sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
+	sec_cmd_set_cmd_exit(sec);
+
+	input_info(true, &ts->client->dev, "%s: %s\n", __func__, buff);
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+}
+
+static void force_touch_active(void *device_data)
+{
+	struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data;
+	struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
+	int active, ret;
+	u16 bus_ref = SEC_TS_BUS_REF_FORCE_ACTIVE;
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, true);
+
+	sec_cmd_set_default_result(sec);
+
+	if (sec->cmd_param[0] < 0 || sec->cmd_param[0] > 2) {
+		sec_cmd_set_cmd_result(sec, "NG", 2);
+		sec_cmd_set_cmd_exit(sec);
+		sec->cmd_state = SEC_CMD_STATUS_FAIL;
+
+		sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+		return;
+	}
+
+	/* Specific case for bugreport. */
+	if (sec->cmd_param[0] == 2) {
+		bus_ref = SEC_TS_BUS_REF_BUGREPORT;
+		active = (sec->cmd_param[1]) ? true : false;
+		if (active) {
+			sec_ts_hc_dump(ts);
+			sec_ts_debug_dump(ts);
+			ts->bugreport_ktime_start = ktime_get();
+		} else {
+			ts->bugreport_ktime_start = 0;
+		}
+	} else {
+		active = sec->cmd_param[0];
+	}
+	input_info(true, &ts->client->dev,
+		   "%s: %s %#x\n", __func__, active ? "enable" : "disable",
+		   bus_ref);
+
+	if (active)
+		pm_stay_awake(&ts->client->dev);
+	else
+		pm_relax(&ts->client->dev);
+
+	ret = sec_ts_set_bus_ref(ts, bus_ref, active);
+	if (ret == 0) {
+		sec_cmd_set_cmd_result(sec, "OK", 2);
+		sec->cmd_state = SEC_CMD_STATUS_OK;
+	} else {
+		input_info(true, &ts->client->dev,
+			"%s: failed! ret %d\n", __func__, ret);
+		sec_cmd_set_cmd_result(sec, "NG", 2);
+		sec->cmd_state = SEC_CMD_STATUS_FAIL;
+	}
+	sec_cmd_set_cmd_exit(sec);
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+}
+
+static void set_touchable_area(void *device_data)
+{
+	struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data;
+	struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
+	char buff[SEC_CMD_STR_LEN] = { 0 };
+	int ret;
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, true);
+
+	sec_cmd_set_default_result(sec);
+
+	if (sec->cmd_param[0] < 0 || sec->cmd_param[0] > 1) {
+		snprintf(buff, sizeof(buff), "%s", "NG");
+		sec->cmd_state = SEC_CMD_STATUS_FAIL;
+		goto out;
+	}
+
+	ts->touchable_area = sec->cmd_param[0];
+
+	if (ts->power_status == SEC_TS_STATE_POWER_OFF) {
+		input_err(true, &ts->client->dev,
+			"%s: Touch is stopped!\n", __func__);
+		snprintf(buff, sizeof(buff), "%s", "TSP turned off");
+		sec->cmd_state = SEC_CMD_STATUS_NOT_APPLICABLE;
+		goto out;
+	}
+
+	input_info(true, &ts->client->dev,
+		"%s: set 16:9 mode %s\n", __func__,
+		ts->touchable_area ? "enable" : "disable");
+
+	/*  - 0: Disable 16:9 mode
+	 *  - 1: Enable 16:9 mode
+	 **/
+	ret = ts->sec_ts_write(ts, SEC_TS_CMD_SET_TOUCHABLE_AREA,
+				&ts->touchable_area, 1);
+	if (ret < 0) {
+		input_err(true, &ts->client->dev,
+				"%s: failed to set 16:9 mode\n", __func__);
+		snprintf(buff, sizeof(buff), "%s", "NG");
+		sec->cmd_state = SEC_CMD_STATUS_FAIL;
+		goto out;
+	}
+
+	snprintf(buff, sizeof(buff), "%s", "OK");
+	sec->cmd_state = SEC_CMD_STATUS_OK;
+out:
+	sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
+	sec_cmd_set_cmd_exit(sec);
+
+	input_info(true, &ts->client->dev, "%s: %s\n", __func__, buff);
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+}
+
+static void set_log_level(void *device_data)
+{
+	struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data;
+	struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
+	char buff[SEC_CMD_STR_LEN] = { 0 };
+	char tBuff[2] = { 0 };
+	u8 w_data[1] = {0x00};
+	int ret;
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, true);
+
+	sec_cmd_set_default_result(sec);
+
+	if (ts->power_status == SEC_TS_STATE_POWER_OFF) {
+		input_err(true, &ts->client->dev,
+				"%s: Touch is stopped!\n", __func__);
+		snprintf(buff, sizeof(buff), "%s", "TSP turned off");
+		sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
+		sec->cmd_state = SEC_CMD_STATUS_FAIL;
+
+		sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+		return;
+	}
+
+	if ((sec->cmd_param[0] < 0 || sec->cmd_param[0] > 1) ||
+		(sec->cmd_param[1] < 0 || sec->cmd_param[1] > 1) ||
+		(sec->cmd_param[2] < 0 || sec->cmd_param[2] > 1) ||
+		(sec->cmd_param[3] < 0 || sec->cmd_param[3] > 1) ||
+		(sec->cmd_param[4] < 0 || sec->cmd_param[4] > 1) ||
+		(sec->cmd_param[5] < 0 || sec->cmd_param[5] > 1) ||
+		(sec->cmd_param[6] < 0 || sec->cmd_param[6] > 1) ||
+		(sec->cmd_param[7] < 0 || sec->cmd_param[7] > 1)) {
+		input_err(true, &ts->client->dev,
+				"%s: para out of range\n", __func__);
+		snprintf(buff, sizeof(buff), "%s", "Para out of range");
+		sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
+		sec->cmd_state = SEC_CMD_STATUS_FAIL;
+
+		sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+		return;
+	}
+
+	ret = ts->sec_ts_read(ts, SEC_TS_CMD_STATUS_EVENT_TYPE, tBuff, 2);
+	if (ret < 0) {
+		input_err(true, &ts->client->dev,
+			"%s: Read Event type enable status fail\n", __func__);
+		snprintf(buff, sizeof(buff), "%s", "Read Stat Fail");
+		goto err;
+	}
+
+	input_info(true, &ts->client->dev, "%s: STATUS_EVENT enable = 0x%02X, 0x%02X\n",
+		__func__, tBuff[0], tBuff[1]);
+
+	tBuff[0] = BIT_STATUS_EVENT_VENDOR_INFO(sec->cmd_param[6]);
+	tBuff[1] = BIT_STATUS_EVENT_ERR(sec->cmd_param[0]) |
+			BIT_STATUS_EVENT_INFO(sec->cmd_param[1]) |
+			BIT_STATUS_EVENT_USER_INPUT(sec->cmd_param[2]);
+
+	ret = ts->sec_ts_write(ts, SEC_TS_CMD_STATUS_EVENT_TYPE, tBuff, 2);
+	if (ret < 0) {
+		input_err(true, &ts->client->dev,
+			"%s: Write Event type enable status fail\n", __func__);
+		snprintf(buff, sizeof(buff), "%s", "Write Stat Fail");
+		goto err;
+	}
+
+	if (sec->cmd_param[0] == 1 && sec->cmd_param[1] == 1 &&
+		sec->cmd_param[2] == 1  && sec->cmd_param[3] == 1 &&
+		sec->cmd_param[4] == 1 &&  sec->cmd_param[5] == 1 &&
+		sec->cmd_param[6] == 1 && sec->cmd_param[7] == 1) {
+		w_data[0] = 0x1;
+		ret = ts->sec_ts_write(ts, SEC_TS_CMD_SET_VENDOR_EVENT_LEVEL,
+				       w_data, 1);
+		if (ret < 0) {
+			input_err(true, &ts->client->dev,
+				  "%s: Write Vendor Event Level fail\n",
+				  __func__);
+			snprintf(buff, sizeof(buff), "%s", "Write Stat Fail");
+			goto err;
+		}
+	} else {
+		w_data[0] = 0x0;
+		ret = ts->sec_ts_write(ts, SEC_TS_CMD_SET_VENDOR_EVENT_LEVEL,
+				       w_data, 0);
+		if (ret < 0) {
+			input_err(true, &ts->client->dev,
+				"%s: Write Vendor Event Level fail\n",
+				__func__);
+			snprintf(buff, sizeof(buff), "%s", "Write Stat Fail");
+			goto err;
+		}
+	}
+
+	input_info(true, &ts->client->dev,
+		"%s: ERROR : %d, INFO : %d, USER_INPUT : %d, INFO_CUSTOMLIB : %d, VENDOR_INFO : %d, VENDOR_EVENT_LEVEL : %d\n",
+		__func__, sec->cmd_param[0], sec->cmd_param[1],
+		sec->cmd_param[2], sec->cmd_param[5],
+		sec->cmd_param[6], w_data[0]);
+
+	snprintf(buff, sizeof(buff), "%s", "OK");
+	sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
+	sec->cmd_state = SEC_CMD_STATUS_OK;
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+	return;
+err:
+	sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
+	sec->cmd_state = SEC_CMD_STATUS_NOT_APPLICABLE;
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+}
+
+static void debug(void *device_data)
+{
+	struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data;
+	struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
+	char buff[SEC_CMD_STR_LEN] = { 0 };
+
+	sec_cmd_set_default_result(sec);
+
+	ts->debug = sec->cmd_param[0];
+
+	snprintf(buff, sizeof(buff), "%s", "OK");
+	sec->cmd_state = SEC_CMD_STATUS_OK;
+	sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
+}
+
+static void set_print_format(void *device_data)
+{
+	struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data;
+	struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
+	char buff[SEC_CMD_STR_LEN] = { 0 };
+
+	sec_cmd_set_default_result(sec);
+
+	ts->print_format = !!sec->cmd_param[0];
+
+	snprintf(buff, sizeof(buff), "%s", "OK");
+	sec->cmd_state = SEC_CMD_STATUS_OK;
+	sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
+}
+
+u8 sec_ts_run_cal_check(struct sec_ts_data *ts)
+{
+	int rc = 0;
+	u8 mis_cal_data = 0xF0;
+
+	if (ts->plat_data->mis_cal_check) {
+		rc = sec_ts_fix_tmode(ts, TOUCH_SYSTEM_MODE_TOUCH,
+				      TOUCH_MODE_STATE_TOUCH);
+		if (rc < 0)
+			input_err(true, &ts->client->dev,
+				  "%s: failed#1 ret: %d\n", __func__, rc);
+
+		rc = ts->sec_ts_write(ts, SEC_TS_CMD_MIS_CAL_CHECK,
+				      NULL, 0);
+		if (rc < 0)
+			input_err(true, &ts->client->dev,
+				  "%s: failed#2 ret: %d\n", __func__, rc);
+		sec_ts_delay(200);
+
+		rc = ts->sec_ts_read(ts, SEC_TS_CMD_MIS_CAL_READ,
+				     &mis_cal_data, 1);
+		if (rc < 0) {
+			input_err(true, &ts->client->dev,
+				  "%s: failed#3 ret: %d\n", __func__, rc);
+			mis_cal_data = 0xF3;
+		} else {
+			input_info(true, &ts->client->dev,
+				   "%s: mis cal data : %d\n",
+				   __func__, mis_cal_data);
+		}
+
+		rc = sec_ts_release_tmode(ts);
+		if (rc < 0)
+			input_err(true, &ts->client->dev,
+				  "%s: failed#4 ret: %d\n", __func__, rc);
+	} else {
+		input_info(true, &ts->client->dev,
+			  "%s: not support!\n", __func__);
+		mis_cal_data = 0xF1;
+	}
+
+	return mis_cal_data;
+}
+
+static void run_cal_check(void *device_data)
+{
+	struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data;
+	struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
+	char buff[SEC_CMD_STR_LEN] = { 0 };
+	u8 ret;
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, true);
+	sec_cmd_set_default_result(sec);
+
+	ret = sec_ts_run_cal_check(ts);
+	if (ret)
+		scnprintf(buff, sizeof(buff), "FAIL(%#x)\n", ret);
+	else
+		scnprintf(buff, sizeof(buff), "OK\n");
+
+	sec->cmd_state = SEC_CMD_STATUS_OK;
+	sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+}
+
+static void not_support_cmd(void *device_data)
+{
+	struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data;
+	char buff[SEC_CMD_STR_LEN] = { 0 };
+
+	sec_cmd_set_default_result(sec);
+	snprintf(buff, sizeof(buff), "%s", "NA");
+
+	sec_cmd_set_cmd_result(sec, buff, strlen(buff));
+	sec->cmd_state = SEC_CMD_STATUS_NOT_APPLICABLE;
+	sec_cmd_set_cmd_exit(sec);
+}
+
+static void set_touch_mode(void *device_data)
+{
+	struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data;
+	struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
+	char buff[SEC_CMD_STR_LEN] = { 0 };
+	int ret = 0;
+	u8 para[4] = { 0 };
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, true);
+	sec_cmd_set_default_result(sec);
+
+	if (ts->power_status == SEC_TS_STATE_POWER_OFF) {
+		input_err(true, &ts->client->dev, "%s: POWER off!\n", __func__);
+		goto err_out;
+	}
+
+	switch (sec->cmd_param[0]) {
+	case 1:
+		input_info(true, &ts->client->dev,
+			"%s: param = %d, set Normal ACTIVE mode\n",
+			__func__, sec->cmd_param[0]);
+		sec_ts_fix_tmode(ts,
+			TOUCH_SYSTEM_MODE_TOUCH, TOUCH_MODE_STATE_TOUCH);
+		break;
+	case 2:
+		input_info(true, &ts->client->dev,
+			"%s: param = %d, set Normal IDLE mode\n",
+			__func__, sec->cmd_param[0]);
+		sec_ts_fix_tmode(ts,
+			TOUCH_SYSTEM_MODE_TOUCH, TOUCH_MODE_STATE_IDLE);
+		break;
+	case 3:
+		input_info(true, &ts->client->dev,
+			"%s: param = %d, set Lowpower ACTIVE mode\n",
+			__func__, sec->cmd_param[0]);
+		sec_ts_fix_tmode(ts,
+			TOUCH_SYSTEM_MODE_LOWPOWER, TOUCH_MODE_STATE_TOUCH);
+		break;
+	case 4:
+		input_info(true, &ts->client->dev,
+			"%s: param = %d, set Lowpower IDLE mode\n",
+			__func__, sec->cmd_param[0]);
+		sec_ts_fix_tmode(ts,
+			TOUCH_SYSTEM_MODE_LOWPOWER, TOUCH_MODE_STATE_IDLE);
+		break;
+	case 5:
+		input_info(true, &ts->client->dev,
+			"%s: param = %d, Sense On\n",
+			__func__, sec->cmd_param[0]);
+		ret = ts->sec_ts_write(ts,
+			SEC_TS_CMD_SENSE_ON, NULL, 0);
+		if (ret < 0)
+			input_err(true, &ts->client->dev,
+				"%s: fail to write Sense_on\n", __func__);
+		sec_ts_delay(300);
+		break;
+	case 6:
+		input_info(true, &ts->client->dev,
+			"%s: param = %d, Sense Off\n",
+			__func__, sec->cmd_param[0]);
+		sec_ts_fix_tmode(ts, TOUCH_SYSTEM_MODE_SLEEP,
+			TOUCH_MODE_STATE_STOP);
+		break;
+	case 7:
+		input_info(true, &ts->client->dev,
+			"%s: param = %d %d, do touch system reset\n",
+			__func__, sec->cmd_param[0], sec->cmd_param[1]);
+		switch (sec->cmd_param[1]) {
+		case RESET_MODE_SW:
+			sec_ts_system_reset(ts, RESET_MODE_SW, true, true);
+			break;
+		case RESET_MODE_HW:
+			sec_ts_system_reset(ts, RESET_MODE_HW, true, true);
+			break;
+		default:
+			sec_ts_system_reset(ts, RESET_MODE_AUTO, true, true);
+		}
+		break;
+	case 8:
+		input_info(true, &ts->client->dev,
+			"%s: Toggle Sense On/Off\n",
+			__func__, sec->cmd_param[0]);
+		ret = ts->sec_ts_read(ts, SEC_TS_READ_TS_STATUS, para, 4);
+		if (ret < 0) {
+			input_err(true, &ts->client->dev,
+				"%s: failed to read status(%d)\n", __func__,
+				ret);
+			goto err_out;
+		}
+
+		if (para[1] == 6) {// have to sense on
+			input_info(true, &ts->client->dev,
+				"%s: param = %d, Sense On\n",
+				__func__, sec->cmd_param[0]);
+			ret = ts->sec_ts_write(ts,
+				SEC_TS_CMD_SENSE_ON, NULL, 0);
+			if (ret < 0)
+				input_err(true, &ts->client->dev,
+					"%s: fail to write Sense_on\n",
+					__func__);
+
+			sec_ts_delay(300);
+
+			input_dbg(false, &ts->client->dev,
+				"%s: SENSE ON\n", __func__);
+		} else {// have to sense off
+			input_info(true, &ts->client->dev,
+				"%s: param = %d, Sense Off\n",
+				__func__, sec->cmd_param[0]);
+			sec_ts_fix_tmode(ts, 0x6, 0x1);
+		}
+
+		break;
+	default:
+		input_info(true, &ts->client->dev,
+			"%s: param error! param = %d\n",
+			__func__, sec->cmd_param[0]);
+		goto err_out;
+	}
+
+	snprintf(buff, sizeof(buff), "%s", "OK");
+	sec->cmd_state = SEC_CMD_STATUS_OK;
+	sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+
+	return;
+
+err_out:
+	snprintf(buff, sizeof(buff), "%s", "NG");
+	sec->cmd_state = SEC_CMD_STATUS_FAIL;
+	sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+}
+
+int sec_ts_fn_init(struct sec_ts_data *ts)
+{
+	int retval;
+
+	retval = sec_cmd_init(&ts->sec, sec_cmds,
+			ARRAY_SIZE(sec_cmds), SEC_CLASS_DEVT_TSP);
+	if (retval < 0) {
+		input_err(true, &ts->client->dev,
+			"%s: Failed to sec_cmd_init\n", __func__);
+		goto exit;
+	}
+
+	retval = sysfs_create_group(&ts->sec.fac_dev->kobj,
+			&cmd_attr_group);
+	if (retval < 0) {
+		input_err(true, &ts->client->dev,
+			"%s: Failed to create sysfs attributes\n",
+			__func__);
+		goto exit;
+	}
+
+	retval = sysfs_create_link(&ts->sec.fac_dev->kobj,
+				&ts->input_dev->dev.kobj, "input");
+	if (retval < 0) {
+		input_err(true, &ts->client->dev,
+			"%s: Failed to create input symbolic link\n",
+			__func__);
+		goto exit;
+	}
+
+	ts->reinit_done = true;
+
+	return 0;
+
+exit:
+	return retval;
+}
+
+void sec_ts_fn_remove(struct sec_ts_data *ts)
+{
+	input_err(true, &ts->client->dev, "%s\n", __func__);
+
+	sysfs_remove_link(&ts->sec.fac_dev->kobj, "input");
+
+	sysfs_remove_group(&ts->sec.fac_dev->kobj,
+			   &cmd_attr_group);
+
+	sec_cmd_exit(&ts->sec, SEC_CLASS_DEVT_TSP);
+
+}
+
+int sec_ts_run_rawdata_type(struct sec_ts_data *ts, struct sec_cmd_data *sec)
+{
+	short min[REGION_TYPE_COUNT], max[REGION_TYPE_COUNT];
+	enum spec_check_type spec_check = SPEC_NO_CHECK;
+	int i, ii, jj;
+	int ret = -1;
+	u8 data_type = 0;
+	u8 touch_type = sec->cmd_param[1];
+	u8 read_type[9] = {TYPE_RAW_DATA, TYPE_AMBIENT_DATA,
+		TYPE_DECODED_DATA, TYPE_REMV_AMB_DATA,
+		TYPE_SIGNAL_DATA, TYPE_OFFSET_DATA_SEC, TYPE_OFFSET_DATA_SDC,
+		TYPE_NOI_P2P_MIN, TYPE_NOI_P2P_MAX};
+	const unsigned int buff_size = ts->tx_count * ts->rx_count *
+					CMD_RESULT_WORD_LEN;
+	unsigned int buff_len = 0;
+	char *buff;
+	char para = TO_TOUCH_MODE;
+
+#ifdef USE_PRESSURE_SENSOR
+	short pressure[3] = { 0 };
+	u8 cal_data[18] = { 0 };
+#endif
+
+	buff = kzalloc(buff_size, GFP_KERNEL);
+	if (!buff)
+		goto error_alloc_mem;
+
+	for (i = 0; i < 9; i++) {
+		if (read_type[i] == sec->cmd_param[0])
+			break;
+	}
+	if (i == 9) {
+		input_err(true, &ts->client->dev, "%s: invalid data type\n",
+				__func__);
+		goto out;
+	}
+
+	ts->tsp_dump_lock = 1;
+	input_info(true, &ts->client->dev,
+			"%s: start (wet: %d)##\n",
+			__func__, ts->wet_mode);
+
+
+	if (sec->cmd_param[0] == TYPE_OFFSET_DATA_SDC)
+		data_type = TYPE_OFFSET_DATA_SDC_NOT_SAVE;
+	else
+		data_type = (u8)sec->cmd_param[0];
+
+	if (data_type == TYPE_NOI_P2P_MIN
+		|| data_type == TYPE_NOI_P2P_MAX) {
+		disable_irq(ts->client->irq);
+
+		ret = execute_p2ptest(ts);
+		if (ret < 0) {
+			input_err(true, &ts->client->dev, "%s: P2P test failed\n",
+				__func__);
+		}
+
+		ret = ts->sec_ts_write(ts, SEC_TS_CMD_SET_POWER_MODE, &para, 1);
+		if (ret < 0) {
+			input_err(true, &ts->client->dev,
+				"%s: Set powermode failed\n", __func__);
+			enable_irq(ts->client->irq);
+			goto out;
+		}
+
+		enable_irq(ts->client->irq);
+	} else {
+		ret = sec_ts_fix_tmode(ts, TOUCH_SYSTEM_MODE_TOUCH,
+				TOUCH_MODE_STATE_TOUCH);
+		if (ret < 0) {
+			input_err(true, &ts->client->dev, "%s: failed to fix tmode\n",
+					__func__);
+			goto out;
+		}
+	}
+
+	if (touch_type == 0) {
+		ret = sec_ts_read_frame(ts, data_type, min, max,
+					&spec_check);
+
+		if (ret < 0)
+			input_info(true, &ts->client->dev,
+					"%s: mutual %d : error ## ret: %d\n",
+					__func__, sec->cmd_param[0], ret);
+		else
+#ifdef USE_SPEC_CHECK
+			input_info(true, &ts->client->dev,
+					"%s: mutual %d : Max/Min %d,%d ##\n",
+					__func__, sec->cmd_param[0],
+					max[0], min[0]);
+#else
+			input_info(true, &ts->client->dev,
+					"%s: mutual %d ##\n",
+					__func__, sec->cmd_param[0]);
+#endif
+
+		sec_ts_delay(20);
+
+		buff_len += scnprintf(buff + buff_len,
+					buff_size - buff_len, "\n");
+		if (!ts->print_format) {
+			for (ii = 0; ii < (ts->rx_count * ts->tx_count); ii++) {
+				buff_len += scnprintf(buff + buff_len,
+					buff_size - buff_len,
+					"%3d,", ts->pFrame[ii]);
+				if (ii % ts->tx_count == (ts->tx_count - 1))
+					buff_len += scnprintf(buff + buff_len,
+						buff_size - buff_len,
+						"\n");
+			}
+		} else {
+			for (ii = 0; ii < ts->tx_count; ii++) {
+				for (jj = 0; jj < ts->rx_count; jj++) {
+					buff_len += scnprintf(buff + buff_len,
+						buff_size - buff_len,
+						"%3d,",
+						ts->pFrame[(jj * ts->tx_count)
+								+ ii]);
+				}
+				buff_len += scnprintf(buff + buff_len,
+						buff_size - buff_len,
+						"\n");
+			}
+		}
+	} else if (touch_type > 0) {
+		ret = sec_ts_read_channel(ts, data_type, min,
+					max, &spec_check);
+		if (ret < 0)
+			input_info(true, &ts->client->dev,
+					"%s: self %d : error ## ret: %d\n",
+					__func__, sec->cmd_param[0], ret);
+		else
+#ifdef USE_SPEC_CHECK
+			input_info(true, &ts->client->dev,
+					"%s: self %d : Max/Min %d,%d ##\n",
+					__func__, sec->cmd_param[0], max[0],
+					min[0]);
+#else
+			input_info(true, &ts->client->dev,
+					"%s: self %d ##\n",
+					__func__, sec->cmd_param[0]);
+#endif
+
+		sec_ts_delay(20);
+
+		buff_len += scnprintf(buff + buff_len,
+				buff_size - buff_len, "\n      ");
+		if (!ts->print_format) {
+			for (ii = 0; ii < (ts->rx_count + ts->tx_count); ii++) {
+				buff_len += scnprintf(buff + buff_len,
+					buff_size - buff_len,
+					"%3d,", ts->pFrame[ii]);
+				if (ii >= ts->tx_count - 1)
+					buff_len += scnprintf(buff + buff_len,
+							buff_size - buff_len,
+							"\n");
+			}
+		} else {
+			for (ii = ts->tx_count;
+			     ii < (ts->rx_count + ts->tx_count); ii++) {
+				buff_len += scnprintf(buff + buff_len,
+						buff_size - buff_len,
+						"%3d,", ts->pFrame[ii]);
+			}
+			buff_len += scnprintf(buff + buff_len,
+					      buff_size - buff_len, "\n");
+			for (ii = 0; ii < ts->tx_count; ii++) {
+				buff_len += scnprintf(buff + buff_len,
+						buff_size - buff_len,
+						"%3d,\n", ts->pFrame[ii]);
+			}
+		}
+	}
+
+#ifdef USE_PRESSURE_SENSOR
+	ret = sec_ts_fix_tmode(ts, TOUCH_SYSTEM_MODE_TOUCH,
+			       TOUCH_MODE_STATE_TOUCH);
+	if (ret < 0) {
+		input_err(true, &ts->client->dev, "%s: failed to fix tmode\n",
+				__func__);
+		goto out;
+	}
+
+	/* run pressure offset data read */
+	read_pressure_data(ts, TYPE_OFFSET_DATA_SEC, pressure);
+	sec_ts_delay(20);
+
+	/* run pressure rawdata read */
+	read_pressure_data(ts, TYPE_RAW_DATA, pressure);
+	sec_ts_delay(20);
+
+	/* run pressure raw delta read  */
+	read_pressure_data(ts, TYPE_REMV_AMB_DATA, pressure);
+	sec_ts_delay(20);
+
+	/* run pressure sigdata read */
+	read_pressure_data(ts, TYPE_SIGNAL_DATA, pressure);
+	sec_ts_delay(20);
+
+	ret = ts->sec_ts_read(ts, SEC_TS_CMD_SET_GET_PRESSURE, cal_data,
+				  18);
+	ts->pressure_left = ((cal_data[16] << 8) | cal_data[17]);
+	ts->pressure_center = ((cal_data[8] << 8) | cal_data[9]);
+	ts->pressure_right = ((cal_data[0] << 8) | cal_data[1]);
+	input_info(true, &ts->client->dev, "%s: pressure cal data - Left: %d, Center: %d, Right: %d\n",
+			__func__, ts->pressure_left, ts->pressure_center,
+			ts->pressure_right);
+#endif
+	sec_ts_release_tmode(ts);
+
+	ret = sec_ts_fix_tmode(ts, TOUCH_SYSTEM_MODE_TOUCH,
+			       TOUCH_MODE_STATE_TOUCH);
+	if (ret < 0) {
+		input_err(true, &ts->client->dev, "%s: failed to fix tmode.\n",
+			  __func__);
+		goto out;
+	}
+
+#ifdef USE_STIM_PAD
+	sec_ts_read_gain_table(ts);
+#endif
+
+	sec_ts_release_tmode(ts);
+out:
+	input_info(true, &ts->client->dev, "%s: ito: %02X %02X %02X %02X\n",
+			__func__, ts->ito_test[0], ts->ito_test[1]
+			, ts->ito_test[2], ts->ito_test[3]);
+
+	input_info(true, &ts->client->dev, "%s: done (wet: %d)##\n",
+			__func__, ts->wet_mode);
+	ts->tsp_dump_lock = 0;
+
+	sec_ts_locked_release_all_finger(ts);
+
+	sec_cmd_set_cmd_result(sec, buff, buff_len);
+	kfree(buff);
+
+	return ret;
+
+error_alloc_mem:
+	sec_cmd_set_cmd_result(sec, "FAIL", 4);
+	return ret;
+}
+
+static void run_rawdata_read_type(void *device_data)
+{
+	struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data;
+	struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
+	char buff[16] = { 0 };
+	int ret = -1;
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, true);
+
+	sec_cmd_set_default_result(sec);
+
+	if (ts->tsp_dump_lock == 1) {
+		input_err(true, &ts->client->dev, "%s: already checking now\n",
+			  __func__);
+		scnprintf(buff, sizeof(buff), "NG");
+		sec->cmd_state = SEC_CMD_STATUS_FAIL;
+		goto out;
+	}
+	if (ts->power_status == SEC_TS_STATE_POWER_OFF) {
+		input_err(true, &ts->client->dev, "%s: IC is power off\n",
+			  __func__);
+		scnprintf(buff, sizeof(buff), "NG");
+		sec->cmd_state = SEC_CMD_STATUS_FAIL;
+		goto out;
+	}
+
+	ret = sec_ts_run_rawdata_type(ts, sec);
+	if (ret < 0) {
+		scnprintf(buff, sizeof(buff), "NA");
+		sec->cmd_state = SEC_CMD_STATUS_FAIL;
+	} else {
+		scnprintf(buff, sizeof(buff), "OK");
+		sec->cmd_state = SEC_CMD_STATUS_OK;
+	}
+out:
+	sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
+	input_info(true, &ts->client->dev, "%s: %s\n", __func__, buff);
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+}
+
+/*
+ * sec_ts_run_rawdata_all : read all raw data
+ *
+ * when you want to read full raw data (full_read : true)
+ * "mutual/self 3, 5, 29, 1, 19" data will be saved in log
+ *
+ * otherwise, (full_read : false, especially on boot time)
+ * only "mutual 3, 5, 29" data will be saved in log
+ */
+void sec_ts_run_rawdata_all(struct sec_ts_data *ts, bool full_read)
+{
+	short min[REGION_TYPE_COUNT], max[REGION_TYPE_COUNT];
+	enum spec_check_type spec_check = SPEC_NO_CHECK;
+	int ret, i, read_num;
+	u8 test_type[5] = {TYPE_AMBIENT_DATA, TYPE_DECODED_DATA,
+		TYPE_SIGNAL_DATA, TYPE_OFFSET_DATA_SEC, TYPE_OFFSET_DATA_SDC};
+#ifdef USE_PRESSURE_SENSOR
+	short pressure[3] = { 0 };
+	u8 cal_data[18] = { 0 };
+#endif
+
+	ts->tsp_dump_lock = 1;
+	input_info(true, &ts->client->dev,
+			"%s: start (wet: %d)##\n",
+			__func__, ts->wet_mode);
+
+	ret = sec_ts_fix_tmode(ts, TOUCH_SYSTEM_MODE_TOUCH,
+			       TOUCH_MODE_STATE_TOUCH);
+	if (ret < 0) {
+		input_err(true, &ts->client->dev, "%s: failed to fix tmode\n",
+				__func__);
+		goto out;
+	}
+
+	if (full_read) {
+		read_num = 5;
+	} else {
+		read_num = 3;
+		test_type[read_num - 1] = TYPE_OFFSET_DATA_SDC;
+	}
+
+	for (i = 0; i < read_num; i++) {
+		ret = sec_ts_read_frame(ts, test_type[i], min, max,
+					&spec_check);
+		if (ret < 0)
+			input_info(true, &ts->client->dev,
+					"%s: mutual %d : error ## ret: %d\n",
+					__func__, test_type[i], ret);
+		else
+#ifdef USE_SPEC_CHECK
+			input_info(true, &ts->client->dev,
+					"%s: mutual %d : Max/Min %d,%d ##\n",
+					__func__, test_type[i], max[0], min[0]);
+#else
+			input_info(true, &ts->client->dev,
+					"%s: mutual %d ##\n",
+					__func__, test_type[i]);
+#endif
+		sec_ts_delay(20);
+
+		if (full_read) {
+			ret = sec_ts_read_channel(ts, test_type[i], min,
+						  max, &spec_check);
+			if (ret < 0)
+				input_info(true, &ts->client->dev,
+						"%s: self %d : error ## ret: %d\n",
+						__func__, test_type[i], ret);
+			else
+#ifdef USE_SPEC_CHECK
+				input_info(true, &ts->client->dev,
+						"%s: self %d : Max/Min %d,%d ##\n",
+						__func__, test_type[i], max[0],
+						min[0]);
+#else
+				input_info(true, &ts->client->dev,
+						"%s: self %d ##\n",
+						__func__, test_type[i]);
+#endif
+			sec_ts_delay(20);
+		}
+	}
+
+#ifdef USE_PRESSURE_SENSOR
+	ret = sec_ts_fix_tmode(ts, TOUCH_SYSTEM_MODE_TOUCH,
+			       TOUCH_MODE_STATE_TOUCH);
+	if (ret < 0) {
+		input_err(true, &ts->client->dev, "%s: failed to fix tmode\n",
+				__func__);
+		goto out;
+	}
+
+	/* run pressure offset data read */
+	read_pressure_data(ts, TYPE_OFFSET_DATA_SEC, pressure);
+	sec_ts_delay(20);
+
+	/* run pressure rawdata read */
+	read_pressure_data(ts, TYPE_RAW_DATA, pressure);
+	sec_ts_delay(20);
+
+	/* run pressure raw delta read  */
+	read_pressure_data(ts, TYPE_REMV_AMB_DATA, pressure);
+	sec_ts_delay(20);
+
+	/* run pressure sigdata read */
+	read_pressure_data(ts, TYPE_SIGNAL_DATA, pressure);
+	sec_ts_delay(20);
+
+	ret = ts->sec_ts_read(ts, SEC_TS_CMD_SET_GET_PRESSURE, cal_data,
+				  18);
+	ts->pressure_left = ((cal_data[16] << 8) | cal_data[17]);
+	ts->pressure_center = ((cal_data[8] << 8) | cal_data[9]);
+	ts->pressure_right = ((cal_data[0] << 8) | cal_data[1]);
+	input_info(true, &ts->client->dev, "%s: pressure cal data - Left: %d, Center: %d, Right: %d\n",
+			__func__, ts->pressure_left, ts->pressure_center,
+			ts->pressure_right);
+#endif
+	sec_ts_release_tmode(ts);
+
+	ret = sec_ts_fix_tmode(ts, TOUCH_SYSTEM_MODE_TOUCH,
+			       TOUCH_MODE_STATE_TOUCH);
+	if (ret < 0) {
+		input_err(true, &ts->client->dev, "%s: failed to fix tmode.\n",
+			  __func__);
+		goto out;
+	}
+
+#ifdef USE_STIM_PAD
+	sec_ts_read_gain_table(ts);
+#endif
+
+	sec_ts_release_tmode(ts);
+out:
+	input_info(true, &ts->client->dev, "%s: ito: %02X %02X %02X %02X\n",
+			__func__, ts->ito_test[0], ts->ito_test[1]
+			, ts->ito_test[2], ts->ito_test[3]);
+
+	input_info(true, &ts->client->dev, "%s: done (wet: %d)##\n",
+			__func__, ts->wet_mode);
+	ts->tsp_dump_lock = 0;
+
+	sec_ts_locked_release_all_finger(ts);
+}
+
+static void run_rawdata_read_all(void *device_data)
+{
+	struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data;
+	struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
+	char buff[16] = { 0 };
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, true);
+
+	sec_cmd_set_default_result(sec);
+
+	if (ts->tsp_dump_lock == 1) {
+		input_err(true, &ts->client->dev, "%s: already checking now\n",
+			  __func__);
+		snprintf(buff, sizeof(buff), "NG");
+		sec->cmd_state = SEC_CMD_STATUS_FAIL;
+		goto out;
+	}
+	if (ts->power_status == SEC_TS_STATE_POWER_OFF) {
+		input_err(true, &ts->client->dev, "%s: IC is power off\n",
+			  __func__);
+		snprintf(buff, sizeof(buff), "NG");
+		sec->cmd_state = SEC_CMD_STATUS_FAIL;
+		goto out;
+	}
+
+	sec_ts_run_rawdata_all(ts, true);
+
+	snprintf(buff, sizeof(buff), "OK");
+	sec->cmd_state = SEC_CMD_STATUS_OK;
+out:
+	sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
+	input_info(true, &ts->client->dev, "%s: %s\n", __func__, buff);
+
+	sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
+}
diff --git a/sec_ts_fw.c b/sec_ts_fw.c
new file mode 100644
index 0000000..7810438
--- /dev/null
+++ b/sec_ts_fw.c
@@ -0,0 +1,1464 @@
+/* drivers/input/touchscreen/sec_ts_fw.c
+ *
+ * Copyright (C) 2015 Samsung Electronics Co., Ltd.
+ * http://www.samsungsemi.com/
+ *
+ * Core file for Samsung TSC driver
+ *
+ * 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 "sec_ts.h"
+
+#define SEC_TS_ENABLE_FW_VERIFY		1
+#define SEC_TS_FW_BLK_SIZE		256
+
+enum {
+	BUILT_IN = 0,
+	UMS, /* deprecated */
+	BL,
+	FFU,
+};
+
+typedef struct {
+	u32 signature;			/* signature */
+	u32 version;			/* version */
+	u32 totalsize;			/* total size */
+	u32 checksum;			/* checksum */
+	u32 img_ver;			/* image file version */
+	u32 img_date;			/* image file date */
+	u32 img_description;		/* image file description */
+	u32 fw_ver;			/* firmware version */
+	u32 fw_date;			/* firmware date */
+	u32 fw_description;		/* firmware description */
+	u32 para_ver;			/* parameter version */
+	u32 para_date;			/* parameter date */
+	u32 para_description;		/* parameter description */
+	u32 num_chunk;			/* number of chunk */
+	u32 reserved1;
+	u32 reserved2;
+} fw_header;
+
+typedef struct {
+	u32 signature;
+	u32 addr;
+	u32 size;
+	u32 reserved;
+} fw_chunk;
+
+static int sec_ts_enter_fw_mode(struct sec_ts_data *ts)
+{
+	int ret;
+	u8 fw_update_mode_passwd[] = {0x55, 0xAC};
+	u8 fw_status;
+	u8 id[3];
+
+	ret = ts->sec_ts_write(ts, SEC_TS_CMD_ENTER_FW_MODE,
+			fw_update_mode_passwd, sizeof(fw_update_mode_passwd));
+	sec_ts_delay(20);
+	if (ret < 0) {
+		input_err(true, &ts->client->dev,
+			  "%s: write fail, enter_fw_mode\n", __func__);
+		return 0;
+	}
+
+	input_info(true, &ts->client->dev, "%s: write ok, enter_fw_mode - 0x%x 0x%x 0x%x\n",
+		__func__, SEC_TS_CMD_ENTER_FW_MODE, fw_update_mode_passwd[0],
+		fw_update_mode_passwd[1]);
+
+	ret = ts->sec_ts_read(ts, SEC_TS_READ_BOOT_STATUS, &fw_status, 1);
+	if (ret < 0) {
+		input_err(true, &ts->client->dev,
+			  "%s: read fail, read_boot_status\n", __func__);
+		return 0;
+	}
+	if (fw_status != SEC_TS_STATUS_BOOT_MODE) {
+		input_err(true, &ts->client->dev, "%s: enter fail! read_boot_status = 0x%x\n",
+			  __func__, fw_status);
+		return 0;
+	}
+
+	input_info(true, &ts->client->dev, "%s: Success! read_boot_status = 0x%x\n",
+		   __func__, fw_status);
+
+	sec_ts_delay(10);
+
+	ret = ts->sec_ts_read(ts, SEC_TS_READ_ID, id, 3);
+	if (ret < 0) {
+		input_err(true, &ts->client->dev,
+			  "%s: read id fail\n", __func__);
+		return 0;
+	}
+
+	ts->boot_ver[0] = id[0];
+	ts->boot_ver[1] = id[1];
+	ts->boot_ver[2] = id[2];
+
+	ts->flash_page_size = SEC_TS_FW_BLK_SIZE_DEFAULT;
+
+	input_info(true, &ts->client->dev, "%s: read_boot_id = %02X%02X%02X\n",
+		   __func__, id[0], id[1], id[2]);
+
+	return 1;
+}
+
+int sec_ts_wait_for_reset_done(struct sec_ts_data *ts)
+{
+	int ret = 0;
+
+	if (completion_done(&ts->bus_resumed) &&
+	    ts->probe_done == true) {
+		if (!completion_done(&ts->boot_completed) &&
+		    wait_for_completion_timeout(&ts->boot_completed,
+						msecs_to_jiffies(200) == 0))
+			ret = -ETIME;
+	} else {
+		ret = sec_ts_wait_for_ready_with_count(ts,
+						SEC_TS_ACK_BOOT_COMPLETE, 10);
+	}
+
+	return ret;
+}
+
+int sec_ts_hw_reset(struct sec_ts_data *ts, bool wait_for_done)
+{
+	int ret = 0;
+	int reset_gpio = ts->plat_data->reset_gpio;
+
+	input_info(true, &ts->client->dev, "%s: wait_for_done %d.\n",
+		   __func__, wait_for_done);
+	if (wait_for_done)
+		reinit_completion(&ts->boot_completed);
+
+	if (!gpio_is_valid(reset_gpio)) {
+		input_err(true, &ts->client->dev, "%s: invalid gpio %d.\n",
+			__func__, reset_gpio);
+		return -EINVAL;
+	}
+
+	gpio_set_value(reset_gpio, 0);
+	sec_ts_delay(10);
+	gpio_set_value(reset_gpio, 1);
+
+	/* Wait 70 ms at least from bootloader to applicateion mode. */
+	sec_ts_delay(70);
+
+	if (wait_for_done) {
+		ret = sec_ts_wait_for_reset_done(ts);
+		if (!ret)
+			input_info(true, &ts->client->dev,
+				"%s: done.\n", __func__);
+		else
+			input_err(true, &ts->client->dev,
+				  "%s: hw_reset time out!\n", __func__);
+		complete_all(&ts->boot_completed);
+	}
+
+	return ret;
+}
+
+int sec_ts_sw_reset(struct sec_ts_data *ts, bool wait_for_done)
+{
+	int ret = 0;
+
+	input_info(true, &ts->client->dev, "%s: wait_for_done %d.\n",
+		   __func__, wait_for_done);
+	if (wait_for_done)
+		reinit_completion(&ts->boot_completed);
+
+	ret = ts->sec_ts_write(ts, SEC_TS_CMD_SW_RESET, NULL, 0);
+	if (ret < 0) {
+		input_err(true, &ts->client->dev,
+			  "%s: failed to write sw_reset.\n", __func__);
+		return -EIO;
+	}
+
+	/* Wait 70 ms at least from bootloader to applicateion mode. */
+	sec_ts_delay(70);
+
+	if (wait_for_done) {
+		ret = sec_ts_wait_for_reset_done(ts);
+		if (!ret)
+			input_info(true, &ts->client->dev,
+				"%s: done.\n", __func__);
+		else
+			input_err(true, &ts->client->dev,
+				"%s: sw_reset time out!\n", __func__);
+
+		complete_all(&ts->boot_completed);
+	}
+
+	return ret;
+}
+
+int sec_ts_system_reset(struct sec_ts_data *ts,
+			enum RESET_MODE mode,
+			bool wait_for_done,
+			bool sense_on)
+{
+	int ret = 0;
+
+	input_info(true, &ts->client->dev,
+		"%s: mode %d, wait_for_done %d, sense_on %d.\n",
+		__func__, mode, wait_for_done, sense_on);
+
+	if (mode & RESET_MODE_SW) {
+		ret = sec_ts_sw_reset(ts, wait_for_done);
+		if (ret)
+			input_err(true, &ts->client->dev,
+				  "%s: sw reset failed.");
+		else
+			goto sw_reset_done;
+	}
+
+	if (mode & RESET_MODE_HW) {
+		if (ret)
+			input_err(true, &ts->client->dev,
+				 "%s: sw_reset failed or time out, try hw_reset to recover!\n",
+				 __func__);
+		ret = sec_ts_hw_reset(ts, wait_for_done);
+		if (ret)
+			input_err(true, &ts->client->dev,
+				  "%s: hw reset failed.");
+	}
+
+sw_reset_done:
+	/* Sense on. */
+	if (sense_on) {
+		ret = ts->sec_ts_write(ts, SEC_TS_CMD_SENSE_ON, NULL, 0);
+		if (ret < 0) {
+			input_err(true, &ts->client->dev,
+				  "%s: failed to write sense_on.\n",
+				  __func__);
+		}
+	}
+
+	/* Initialize wet status. */
+	ts->wet_mode = 0;
+	ts->wet_count = 0;
+
+	return ret;
+}
+
+static void sec_ts_save_version_of_bin(struct sec_ts_data *ts,
+				       const fw_header *fw_hd)
+{
+	ts->plat_data->img_version_of_bin[3] =
+			((fw_hd->img_ver >> 24) & 0xff);
+	ts->plat_data->img_version_of_bin[2] =
+			((fw_hd->img_ver >> 16) & 0xff);
+	ts->plat_data->img_version_of_bin[1] =
+			((fw_hd->img_ver >> 8) & 0xff);
+	ts->plat_data->img_version_of_bin[0] =
+			((fw_hd->img_ver >> 0) & 0xff);
+
+	ts->plat_data->core_version_of_bin[3] =
+			((fw_hd->fw_ver >> 24) & 0xff);
+	ts->plat_data->core_version_of_bin[2] =
+			((fw_hd->fw_ver >> 16) & 0xff);
+	ts->plat_data->core_version_of_bin[1] =
+			((fw_hd->fw_ver >> 8) & 0xff);
+	ts->plat_data->core_version_of_bin[0] =
+			((fw_hd->fw_ver >> 0) & 0xff);
+
+	ts->plat_data->config_version_of_bin[3] =
+			((fw_hd->para_ver >> 24) & 0xff);
+	ts->plat_data->config_version_of_bin[2] =
+			((fw_hd->para_ver >> 16) & 0xff);
+	ts->plat_data->config_version_of_bin[1] =
+			((fw_hd->para_ver >> 8) & 0xff);
+	ts->plat_data->config_version_of_bin[0] =
+			((fw_hd->para_ver >> 0) & 0xff);
+
+	input_info(true, &ts->client->dev, "%s: img_ver of bin: %x.%x.%x.%x\n",
+			__func__,
+			ts->plat_data->img_version_of_bin[0],
+			ts->plat_data->img_version_of_bin[1],
+			ts->plat_data->img_version_of_bin[2],
+			ts->plat_data->img_version_of_bin[3]);
+
+	input_info(true, &ts->client->dev, "%s: core_ver of bin: %x.%x.%x.%x\n",
+			__func__,
+			ts->plat_data->core_version_of_bin[0],
+			ts->plat_data->core_version_of_bin[1],
+			ts->plat_data->core_version_of_bin[2],
+			ts->plat_data->core_version_of_bin[3]);
+
+	input_info(true, &ts->client->dev, "%s: config_ver of bin: %x.%x.%x.%x\n",
+			__func__,
+			ts->plat_data->config_version_of_bin[0],
+			ts->plat_data->config_version_of_bin[1],
+			ts->plat_data->config_version_of_bin[2],
+			ts->plat_data->config_version_of_bin[3]);
+}
+
+static int sec_ts_save_version_of_ic(struct sec_ts_data *ts)
+{
+	u8 img_ver[4] = {0,};
+	u8 core_ver[4] = {0,};
+	u8 config_ver[4] = {0,};
+	int ret;
+
+	/* Image ver */
+	ret = ts->sec_ts_read(ts, SEC_TS_READ_IMG_VERSION, img_ver, 4);
+	if (ret < 0) {
+		input_err(true, &ts->client->dev,
+			"%s: Image version read error\n", __func__);
+		return -EIO;
+	}
+	input_info(true, &ts->client->dev,
+		"%s: IC Image version info: %x.%x.%x.%x\n",
+		__func__, img_ver[0], img_ver[1], img_ver[2], img_ver[3]);
+
+	ts->plat_data->img_version_of_ic[0] = img_ver[0];
+	ts->plat_data->img_version_of_ic[1] = img_ver[1];
+	ts->plat_data->img_version_of_ic[2] = img_ver[2];
+	ts->plat_data->img_version_of_ic[3] = img_ver[3];
+
+	/* Core ver */
+	ret = ts->sec_ts_read(ts, SEC_TS_READ_FW_VERSION, core_ver, 4);
+	if (ret < 0) {
+		input_err(true, &ts->client->dev,
+			"%s: core version read error\n", __func__);
+		return -EIO;
+	}
+	input_info(true, &ts->client->dev,
+		"%s: IC Core version info: %x.%x.%x.%x,\n",
+		__func__, core_ver[0], core_ver[1], core_ver[2], core_ver[3]);
+
+	ts->plat_data->core_version_of_ic[0] = core_ver[0];
+	ts->plat_data->core_version_of_ic[1] = core_ver[1];
+	ts->plat_data->core_version_of_ic[2] = core_ver[2];
+	ts->plat_data->core_version_of_ic[3] = core_ver[3];
+
+	/* Config ver */
+	ret = ts->sec_ts_read(ts, SEC_TS_READ_PARA_VERSION, config_ver, 4);
+	if (ret < 0) {
+		input_err(true, &ts->client->dev,
+				"%s: config version read error\n", __func__);
+		return -EIO;
+	}
+	input_info(true, &ts->client->dev,
+			"%s: IC config version info: %x.%x.%x.%x\n",
+			__func__, config_ver[0], config_ver[1],
+			config_ver[2], config_ver[3]);
+
+	ts->plat_data->config_version_of_ic[0] = config_ver[0];
+	ts->plat_data->config_version_of_ic[1] = config_ver[1];
+	ts->plat_data->config_version_of_ic[2] = config_ver[2];
+	ts->plat_data->config_version_of_ic[3] = config_ver[3];
+
+	return 1;
+}
+
+static int sec_ts_check_firmware_version(struct sec_ts_data *ts,
+					 const u8 *fw_info)
+{
+	fw_header *fw_hd;
+	u8 buff[1];
+	int i;
+	int ret;
+	/*
+	 * sec_ts_check_firmware_version
+	 * return value = 1 : firmware download needed,
+	 * return value = 0 : skip firmware download
+	 */
+
+	fw_hd = (fw_header *)fw_info;
+
+	sec_ts_save_version_of_bin(ts, fw_hd);
+
+	/* firmware download if READ_BOOT_STATUS = 0x10 */
+	ret = ts->sec_ts_read(ts, SEC_TS_READ_BOOT_STATUS, buff, 1);
+	if (ret < 0) {
+		input_err(true, &ts->client->dev,
+				"%s: fail to read BootStatus\n", __func__);
+		return -EIO;
+	}
+
+	if (buff[0] == SEC_TS_STATUS_BOOT_MODE) {
+		input_err(true, &ts->client->dev,
+				"%s: ReadBootStatus = 0x%x, Firmware download Start!\n",
+				__func__, buff[0]);
+		return 1;
+	}
+
+	ret = sec_ts_save_version_of_ic(ts);
+	if (ret < 0) {
+		input_err(true, &ts->client->dev,
+				"%s: fail to read ic version\n", __func__);
+		return -EIO;
+	}
+
+	/* check f/w version
+	 * ver[0] : IC version
+	 * ver[1] : Project version
+	 */
+	for (i = 0; i < 2; i++) {
+		if (ts->plat_data->img_version_of_ic[i] !=
+			ts->plat_data->img_version_of_bin[i]) {
+			input_err(true, &ts->client->dev,
+				"%s: do not matched version info\n", __func__);
+			return 0;
+		}
+	}
+
+	for (i = 2; i < 4; i++) {
+		if (ts->plat_data->img_version_of_ic[i] !=
+		    ts->plat_data->img_version_of_bin[i])
+			return 1;
+	}
+
+	return 0;
+}
+
+static u8 sec_ts_checksum(u8 *data, int offset, int size)
+{
+	int i;
+	u8 checksum = 0;
+
+	for (i = 0; i < size; i++)
+		checksum += data[i + offset];
+
+	return checksum;
+}
+
+static int sec_ts_flashpageerase(struct sec_ts_data *ts, u32 page_idx,
+				 u32 page_num)
+{
+	int ret;
+	u8 tCmd[6];
+
+	tCmd[0] = SEC_TS_CMD_FLASH_ERASE;
+	tCmd[1] = (u8)((page_idx >> 8) & 0xFF);
+	tCmd[2] = (u8)((page_idx >> 0) & 0xFF);
+	tCmd[3] = (u8)((page_num >> 8) & 0xFF);
+	tCmd[4] = (u8)((page_num >> 0) & 0xFF);
+	tCmd[5] = sec_ts_checksum(tCmd, 1, 4);
+
+	ret = ts->sec_ts_write_burst(ts, tCmd, 6);
+
+	return ret;
+}
+
+static int sec_ts_flashpagewrite(struct sec_ts_data *ts, u32 page_idx,
+				 u8 *page_data)
+{
+	int ret;
+	u8 tCmd[1 + 2 + SEC_TS_FW_BLK_SIZE_MAX + 1];
+	int flash_page_size = (int)ts->flash_page_size;
+
+	tCmd[0] = 0xD9;
+	tCmd[1] = (u8)((page_idx >> 8) & 0xFF);
+	tCmd[2] = (u8)((page_idx >> 0) & 0xFF);
+
+	memcpy(&tCmd[3], page_data, flash_page_size);
+	tCmd[1 + 2 + flash_page_size] = sec_ts_checksum(tCmd, 1,
+							2 + flash_page_size);
+
+	ret = ts->sec_ts_write_burst(ts, tCmd, 1 + 2 + flash_page_size + 1);
+	return ret;
+}
+
+static bool sec_ts_limited_flashpagewrite(struct sec_ts_data *ts,
+						u32 page_idx, u8 *page_data)
+{
+	int ret = 0;
+	u8 *tCmd;
+	u8 copy_data[3 + SEC_TS_FW_BLK_SIZE_MAX];
+	int copy_left = (int)ts->flash_page_size + 3;
+	int copy_size = 0;
+	int copy_max = ts->io_burstmax - 1;
+	int flash_page_size = (int)ts->flash_page_size;
+
+	copy_data[0] = (u8)((page_idx >> 8) & 0xFF);	/* addH */
+	copy_data[1] = (u8)((page_idx >> 0) & 0xFF);	/* addL */
+
+	memcpy(&copy_data[2], page_data, flash_page_size);	/* DATA */
+	copy_data[2 + flash_page_size] =
+		sec_ts_checksum(copy_data, 0, 2 + flash_page_size);	/* CS */
+
+	while (copy_left > 0) {
+		int copy_cur = (copy_left > copy_max) ? copy_max : copy_left;
+
+		tCmd = kzalloc(copy_cur + 1, GFP_KERNEL);
+		if (!tCmd)
+			goto err_write;
+
+		if (copy_size == 0)
+			tCmd[0] = SEC_TS_CMD_FLASH_WRITE;
+		else
+			tCmd[0] = SEC_TS_CMD_FLASH_PADDING;
+
+		memcpy(&tCmd[1], &copy_data[copy_size], copy_cur);
+
+		ret = ts->sec_ts_write_burst_heap(ts, tCmd, 1 + copy_cur);
+		if (ret < 0)
+			input_err(true, &ts->client->dev,
+					"%s: failed, ret: %d\n", __func__, ret);
+
+		copy_size += copy_cur;
+		copy_left -= copy_cur;
+		kfree(tCmd);
+	}
+	return ret;
+
+err_write:
+	input_err(true, &ts->client->dev,
+				"%s: failed to alloc.\n", __func__);
+	return -ENOMEM;
+
+}
+
+static int sec_ts_flashwrite(struct sec_ts_data *ts, u32 mem_addr,
+				u8 *mem_data, u32 mem_size, int retry)
+{
+	int ret;
+	u32 page_idx;
+	u32 size_copy;
+	u32 flash_page_size;
+	u32 page_idx_start;
+	u32 page_idx_end;
+	u32 page_num;
+	u8 page_buf[SEC_TS_FW_BLK_SIZE_MAX];
+
+	if (mem_size == 0)
+		return 0;
+
+	flash_page_size = ts->flash_page_size;
+	page_idx_start = mem_addr / flash_page_size;
+	page_idx_end = (mem_addr + mem_size - 1) / flash_page_size;
+	page_num = page_idx_end - page_idx_start + 1;
+
+	ret = sec_ts_flashpageerase(ts, page_idx_start, page_num);
+	if (ret < 0) {
+		input_err(true, &ts->client->dev,
+				"%s: fw erase failed, mem_addr= %08X, pagenum = %d\n",
+				__func__, mem_addr, page_num);
+		return -EIO;
+	}
+
+	sec_ts_delay(page_num + 10);
+
+	size_copy = mem_size % flash_page_size;
+	if (size_copy == 0)
+		size_copy = flash_page_size;
+
+	memset(page_buf, 0, flash_page_size);
+
+	for (page_idx = page_num - 1;; page_idx--) {
+		memcpy(page_buf, mem_data + (page_idx * flash_page_size),
+			size_copy);
+		if (ts->boot_ver[0] == 0xB2) {
+			ret = sec_ts_flashpagewrite(ts,
+					(page_idx + page_idx_start), page_buf);
+			if (ret < 0) {
+				input_err(true, &ts->client->dev,
+					"%s: fw write failed, page_idx = %u\n",
+					__func__, page_idx);
+				goto err;
+			}
+
+			if (retry) {
+				sec_ts_delay(50);
+				ret = sec_ts_flashpagewrite(ts,
+					(page_idx + page_idx_start), page_buf);
+				if (ret < 0) {
+					input_err(true, &ts->client->dev,
+						"%s: fw write failed, page_idx = %u\n",
+						__func__, page_idx);
+					goto err;
+				}
+			}
+		} else {
+			ret = sec_ts_limited_flashpagewrite(ts,
+					(page_idx + page_idx_start), page_buf);
+			if (ret < 0) {
+				input_err(true, &ts->client->dev,
+					"%s: fw write failed, page_idx = %u\n",
+					__func__, page_idx);
+				goto err;
+			}
+
+			if (retry) {
+				sec_ts_delay(50);
+				ret = sec_ts_limited_flashpagewrite(ts,
+					(page_idx + page_idx_start), page_buf);
+				if (ret < 0) {
+					input_err(true, &ts->client->dev,
+						"%s: fw write failed, page_idx = %u\n",
+						__func__, page_idx);
+					goto err;
+				}
+			}
+
+		}
+
+		size_copy = flash_page_size;
+		sec_ts_delay(5);
+
+		/* end condition (page_idx >= 0) page_idx type unsigned int
+		 **/
+		if (page_idx == 0)
+			break;
+	}
+
+	return mem_size;
+err:
+	return -EIO;
+}
+
+#if SEC_TS_ENABLE_FW_VERIFY
+static int sec_ts_memoryblockread(struct sec_ts_data *ts, u32 mem_addr,
+				int mem_size, u8 *buf)
+{
+	int ret;
+	u8 cmd[5];
+	u8 *data;
+
+	if (mem_size >= 64 * 1024) {
+		input_err(true, &ts->client->dev,
+				"%s: mem size over 64K\n", __func__);
+		return -EIO;
+	}
+
+	cmd[0] = (u8)SEC_TS_CMD_FLASH_READ_ADDR;
+	cmd[1] = (u8)((mem_addr >> 24) & 0xff);
+	cmd[2] = (u8)((mem_addr >> 16) & 0xff);
+	cmd[3] = (u8)((mem_addr >> 8) & 0xff);
+	cmd[4] = (u8)((mem_addr >> 0) & 0xff);
+
+	ret = ts->sec_ts_write_burst(ts, cmd, 5);
+	if (ret < 0) {
+		input_err(true, &ts->client->dev,
+			"%s: send command failed, %02X\n", __func__, cmd[0]);
+		return -EIO;
+	}
+
+	udelay(10);
+	cmd[0] = (u8)SEC_TS_CMD_FLASH_READ_SIZE;
+	cmd[1] = (u8)((mem_size >> 8) & 0xff);
+	cmd[2] = (u8)((mem_size >> 0) & 0xff);
+
+	ret = ts->sec_ts_write_burst(ts, cmd, 3);
+	if (ret < 0) {
+		input_err(true, &ts->client->dev,
+				"%s: send command failed, %02X\n",
+				__func__, cmd[0]);
+		return -EIO;
+	}
+
+	udelay(10);
+	cmd[0] = (u8)SEC_TS_CMD_FLASH_READ_DATA;
+
+	data = buf;
+
+
+	ret = ts->sec_ts_read_heap(ts, cmd[0], data, mem_size);
+	if (ret < 0) {
+		input_err(true, &ts->client->dev, "%s: memory read failed\n",
+				__func__);
+		return -EIO;
+	}
+/*
+ *	ret = ts->sec_ts_write(ts, cmd[0], NULL, 0);
+ *	ret = ts->sec_ts_read_bulk_heap(ts, data, mem_size);
+ **/
+	return 0;
+}
+
+static int sec_ts_memoryread(struct sec_ts_data *ts, u32 mem_addr,
+				u8 *mem_data, u32 mem_size)
+{
+	int ret;
+	int retry = 3;
+	int read_size = 0;
+	int unit_size;
+	int max_size = 1024;
+	int read_left = (int)mem_size;
+	u8 *tmp_data;
+
+	tmp_data = kmalloc(max_size, GFP_KERNEL);
+	if (!tmp_data) {
+		input_err(true, &ts->client->dev,
+			"%s: failed to kmalloc\n", __func__);
+		return -ENOMEM;
+	}
+
+	while (read_left > 0) {
+		unit_size = (read_left > max_size) ? max_size : read_left;
+		retry = 3;
+		do {
+			ret = sec_ts_memoryblockread(ts, mem_addr, unit_size,
+							tmp_data);
+			if (retry-- == 0) {
+				input_err(true, &ts->client->dev,
+						"%s: fw read fail mem_addr=%08X,unit_size=%d\n",
+						__func__, mem_addr, unit_size);
+				kfree(tmp_data);
+				return -1;
+			}
+
+			memcpy(mem_data + read_size, tmp_data, unit_size);
+		} while (ret < 0);
+
+		mem_addr += unit_size;
+		read_size += unit_size;
+		read_left -= unit_size;
+	}
+
+	kfree(tmp_data);
+
+	return read_size;
+}
+#endif
+
+static int sec_ts_chunk_update(struct sec_ts_data *ts, u32 addr,
+				u32 size, u8 *data, int retry)
+{
+	u32 fw_size;
+	u32 write_size;
+	u8 *mem_rb;
+	int ret = 0;
+
+	fw_size = size;
+
+	write_size = sec_ts_flashwrite(ts, addr, data, fw_size, retry);
+	if (write_size != fw_size) {
+		input_err(true, &ts->client->dev,
+				"%s: fw write failed, write_size %d != fw_size %d\n",
+				__func__, write_size, fw_size);
+		ret = -1;
+		goto err_write_fail;
+	}
+
+	mem_rb = vzalloc(fw_size);
+	if (!mem_rb) {
+		input_err(true, &ts->client->dev,
+				"%s: vzalloc failed\n", __func__);
+		ret = -1;
+		goto err_write_fail;
+	}
+
+#if SEC_TS_ENABLE_FW_VERIFY
+	if (sec_ts_memoryread(ts, addr, mem_rb, fw_size) >= 0) {
+		u32 ii;
+
+		for (ii = 0; ii < fw_size; ii++) {
+			if (data[ii] != mem_rb[ii]) {
+				input_info(true, &ts->client->dev,
+					"%s: data = %X, mem_rb = %X, ii = %d\n",
+					__func__, data[ii], mem_rb[ii], ii);
+				break;
+			}
+		}
+
+		if (fw_size != ii) {
+			input_err(true, &ts->client->dev,
+					"%s: fw verify fail, fw_size %d != ii %d\n",
+					__func__, fw_size, ii);
+			ret = -1;
+			goto out;
+		}
+	} else {
+		ret = -1;
+		goto out;
+	}
+
+	input_info(true, &ts->client->dev, "%s: verify done(%d)\n",
+			__func__, ret);
+
+out:
+#endif
+	vfree(mem_rb);
+err_write_fail:
+	sec_ts_delay(10);
+
+	return ret;
+}
+
+static int sec_ts_firmware_update(struct sec_ts_data *ts, const u8 *data,
+			size_t size, int bl_update, int restore_cal, int retry)
+{
+	int i;
+	int ret;
+	fw_header *fw_hd;
+	fw_chunk *fw_ch;
+	u8 fw_status = 0;
+	u8 *fd = (u8 *)data;
+	u8 tBuff[3];
+#ifdef PAT_CONTROL
+	char buff[SEC_CMD_STR_LEN] = {0};
+	u8 img_ver[4];
+	bool magic_cal = false;
+#endif
+
+	/* Check whether CRC is appended or not.
+	 * Enter Firmware Update Mode
+	 */
+	if (!sec_ts_enter_fw_mode(ts)) {
+		input_err(true, &ts->client->dev,
+				"%s: firmware mode failed\n", __func__);
+		return -1;
+	}
+
+	if (bl_update && (ts->boot_ver[0] == 0xB4)) {
+		input_info(true, &ts->client->dev,
+				"%s: bootloader is up to date\n", __func__);
+		return 0;
+	}
+
+	input_info(true, &ts->client->dev,
+			"%s: firmware update retry: %d\n", __func__, retry);
+
+	fw_hd = (fw_header *)fd;
+	fd += sizeof(fw_header);
+
+	if (fw_hd->signature != SEC_TS_FW_HEADER_SIGN) {
+		input_err(true, &ts->client->dev,
+				"%s: firmware header error = %08X\n",
+				__func__, fw_hd->signature);
+		return -1;
+	}
+
+	input_info(true, &ts->client->dev, "%s: num_chunk: %d\n",
+			__func__, fw_hd->num_chunk);
+
+	for (i = 0; i < fw_hd->num_chunk; i++) {
+		fw_ch = (fw_chunk *)fd;
+
+		input_info(true, &ts->client->dev,
+				"%s: [%d] 0x%08X, 0x%08X, 0x%08X, 0x%08X\n",
+				__func__, i, fw_ch->signature, fw_ch->addr,
+				fw_ch->size, fw_ch->reserved);
+
+		if (fw_ch->signature != SEC_TS_FW_CHUNK_SIGN) {
+			input_err(true, &ts->client->dev,
+					"%s: firmware chunk error = %08X\n",
+					__func__, fw_ch->signature);
+			return -1;
+		}
+		fd += sizeof(fw_chunk);
+		ret = sec_ts_chunk_update(ts, fw_ch->addr, fw_ch->size, fd,
+						retry);
+		if (ret < 0) {
+			input_err(true, &ts->client->dev,
+					"%s: firmware chunk write failed, addr=%08X, size = %d\n",
+					__func__, fw_ch->addr, fw_ch->size);
+			return -1;
+		}
+		fd += fw_ch->size;
+	}
+
+	sec_ts_system_reset(ts, RESET_MODE_SW, true, true);
+
+#ifdef PAT_CONTROL
+	if (restore_cal) {
+		if (ts->plat_data->pat_function == PAT_CONTROL_PAT_MAGIC) {
+			/* NOT to control cal count that was marked on external
+			 * factory ( E0~E5 )
+			 **/
+			if ((ts->cal_count >= PAT_MAGIC_NUMBER) &&
+				(ts->cal_count < PAT_MAX_MAGIC))
+				magic_cal = true;
+		}
+	}
+	input_info(true, &ts->client->dev,
+		"%s: cal_count(0x%02X) pat_function dt(%d) restore_cal(%d) magic_cal(%d)\n",
+		__func__, ts->cal_count, ts->plat_data->pat_function,
+		restore_cal, magic_cal);
+#endif
+
+	if (!bl_update) {
+#ifdef PAT_CONTROL
+		if ((ts->cal_count == 0) || (ts->cal_count == 0xFF) ||
+			(magic_cal == true)) {
+			input_err(true, &ts->client->dev,
+					"%s: RUN OFFSET CALIBRATION(0x%02X)\n",
+					__func__, ts->cal_count);
+
+			ret = sec_ts_execute_force_calibration(ts,
+							OFFSET_CAL_SEC);
+			if (ret < 0)
+				input_err(true, &ts->client->dev,
+						"%s: fail to write OFFSET CAL SEC!\n",
+						__func__);
+
+#ifdef USE_PRESSURE_SENSOR
+			ret = sec_ts_execute_force_calibration(ts,
+								PRESSURE_CAL);
+			if (ret < 0)
+				input_err(true, &ts->client->dev,
+						"%s: fail to write PRESSURE CAL!\n",
+						__func__);
+#endif
+			if (ret >= 0 && magic_cal) {
+
+				ts->cal_count = get_tsp_nvm_data(ts,
+						SEC_TS_NVM_OFFSET_CAL_COUNT);
+				if (ts->cal_count == 0x00 ||
+					ts->cal_count == 0xFF)
+					ts->cal_count = PAT_MAGIC_NUMBER;
+				else if (ts->cal_count >= PAT_MAGIC_NUMBER &&
+						ts->cal_count < PAT_MAX_MAGIC)
+					ts->cal_count++;
+
+				/* Use TSP NV area : in this model, use only
+				 *                   one byte
+				 * buff[0] : offset from user NVM storage
+				 * buff[1] : length of stored data - 1 (ex.
+				 *           using 1byte, value is  1 - 1 = 0)
+				 * buff[2] : write data
+				 **/
+				buff[0] = SEC_TS_NVM_OFFSET_CAL_COUNT;
+				buff[1] = 0;
+				buff[2] = ts->cal_count;
+
+				ret = ts->sec_ts_write(ts, SEC_TS_CMD_NVM,
+							buff, 3);
+				if (ret < 0)
+					input_err(true, &ts->client->dev,
+							"%s: nvm write failed. ret: %d\n",
+							__func__, ret);
+
+				sec_ts_delay(20);
+				ts->cal_count = get_tsp_nvm_data(ts,
+						SEC_TS_NVM_OFFSET_CAL_COUNT);
+				input_info(true, &ts->client->dev,
+						"%s: cal_count = [%02X]\n",
+						__func__, ts->cal_count);
+			}
+
+			ret = ts->sec_ts_read(ts, SEC_TS_READ_IMG_VERSION,
+						img_ver, 4);
+			if (ret < 0) {
+				input_err(true, &ts->client->dev,
+				    "%s: Image version read error\n", __func__);
+			} else {
+				memset(buff, 0x00, SEC_CMD_STR_LEN);
+				buff[0] = get_tsp_nvm_data(ts,
+						SEC_TS_NVM_OFFSET_TUNE_VERSION);
+				if (buff[0] == 0xFF) {
+					set_tsp_nvm_data_clear(ts,
+					    SEC_TS_NVM_OFFSET_TUNE_VERSION);
+					set_tsp_nvm_data_clear(ts,
+					    SEC_TS_NVM_OFFSET_TUNE_VERSION + 1);
+				}
+
+				ts->tune_fix_ver = (img_ver[2] << 8 |
+							img_ver[3]);
+				buff[0] = SEC_TS_NVM_OFFSET_TUNE_VERSION;
+				buff[1] = 1;// 2bytes
+				buff[2] = img_ver[2];
+				buff[3] = img_ver[3];
+				ret = ts->sec_ts_write(ts, SEC_TS_CMD_NVM,
+							buff, 4);
+				if (ret < 0) {
+					input_err(true, &ts->client->dev,
+						"%s: nvm write failed. ret: %d\n",
+						__func__, ret);
+				}
+				sec_ts_delay(20);
+
+				buff[0] = get_tsp_nvm_data(ts,
+						SEC_TS_NVM_OFFSET_TUNE_VERSION);
+				buff[1] = get_tsp_nvm_data(ts,
+					SEC_TS_NVM_OFFSET_TUNE_VERSION + 1);
+				ts->tune_fix_ver = buff[0]<<8 | buff[1];
+				input_info(true, &ts->client->dev,
+						"%s: tune_fix_ver [%02X %02X]\n",
+						__func__, buff[0], buff[1]);
+			}
+		} else {
+			input_err(true, &ts->client->dev,
+					"%s: DO NOT CALIBRATION(0x%02X)\n",
+					__func__, ts->cal_count);
+		}
+#else
+		/* auto-calibration if restore_cal = 0 */
+		if (!restore_cal) {
+			input_err(true, &ts->client->dev,
+					"%s: RUN OFFSET CALIBRATION\n",
+					__func__);
+
+			ret = sec_ts_execute_force_calibration(ts,
+					OFFSET_CAL_SEC);
+			if (ret < 0)
+				input_err(true, &ts->client->dev,
+						"%s: fail to write OFFSET CAL SEC!\n",
+						__func__);
+
+#ifdef USE_PRESSURE_SENSOR
+			ret = sec_ts_execute_force_calibration(ts,
+					PRESSURE_CAL);
+			if (ret < 0)
+				input_err(true, &ts->client->dev,
+						"%s: fail to write PRESSURE CAL!\n",
+						__func__);
+#endif
+
+			/* check mis-cal */
+			sec_ts_run_cal_check(ts);
+			/* Update calibration report */
+			sec_ts_read_calibration_report(ts);
+		} else
+			input_info(true, &ts->client->dev,
+					"%s: No calibration: restore_cal = %d\n",
+					__func__, restore_cal);
+#endif
+
+		/* Sense_on */
+		ret = ts->sec_ts_write(ts, SEC_TS_CMD_SENSE_ON, NULL, 0);
+		if (ret < 0) {
+			input_err(true, &ts->client->dev,
+					"%s: write fail, Sense_on\n", __func__);
+			return -EIO;
+		}
+
+		if (ts->sec_ts_read(ts, SEC_TS_READ_BOOT_STATUS,
+				    &fw_status, 1) < 0) {
+			input_err(true, &ts->client->dev,
+					"%s: read fail, read_boot_status = 0x%x\n",
+					__func__, fw_status);
+			return -EIO;
+		}
+
+		if (fw_status != SEC_TS_STATUS_APP_MODE) {
+			input_err(true, &ts->client->dev,
+					"%s: fw update sequence done, BUT read_boot_status = 0x%x\n",
+					__func__, fw_status);
+			return -EIO;
+		}
+
+		input_info(true, &ts->client->dev,
+				"%s: fw update Success! read_boot_status = 0x%x\n",
+				__func__, fw_status);
+
+		return 1;
+	} else {
+
+		if (ts->sec_ts_read(ts, SEC_TS_READ_ID, tBuff, 3) < 0) {
+			input_err(true, &ts->client->dev,
+					"%s: read device id fail after bl fw download\n",
+					__func__);
+			return -EIO;
+		}
+
+		if (tBuff[0] == 0xA0) {
+			input_info(true, &ts->client->dev,
+					"%s: bl fw download success - device id = %02X\n",
+					__func__, tBuff[0]);
+			return -EIO;
+		} else {
+			input_err(true, &ts->client->dev,
+					"%s: bl fw id does not match - device id = %02X\n",
+					__func__, tBuff[0]);
+			return -EIO;
+		}
+	}
+
+}
+
+int sec_ts_firmware_update_bl(struct sec_ts_data *ts)
+{
+	const struct firmware *fw_entry;
+	char fw_path[SEC_TS_MAX_FW_PATH];
+	int result = -1;
+
+	disable_irq(ts->client->irq);
+
+	snprintf(fw_path, SEC_TS_MAX_FW_PATH, "%s", SEC_TS_DEFAULT_BL_NAME);
+
+	input_info(true, &ts->client->dev,
+			"%s: initial bl update %s\n", __func__, fw_path);
+
+	/* Loading Firmware------------------------------------------ */
+	if (request_firmware(&fw_entry, fw_path, &ts->client->dev) !=  0) {
+		input_err(true, &ts->client->dev,
+				"%s: bt is not available\n", __func__);
+		goto err_request_fw;
+	}
+	input_info(true, &ts->client->dev,
+			"%s: request bt done! size = %d\n",
+			__func__, (int)fw_entry->size);
+
+	result = sec_ts_firmware_update(ts, fw_entry->data, fw_entry->size,
+					1, 0, 0);
+
+err_request_fw:
+	release_firmware(fw_entry);
+	enable_irq(ts->client->irq);
+
+	return result;
+}
+
+int sec_ts_bl_update(struct sec_ts_data *ts)
+{
+	int ret;
+	u8 tCmd[5] = { 0xDE, 0xAD, 0xBE, 0xEF };
+	u8 tBuff[3];
+
+	ret = ts->sec_ts_write(ts, SEC_TS_READ_BL_UPDATE_STATUS, tCmd, 4);
+	if (ret < 0) {
+		input_err(true, &ts->client->dev,
+				"%s: bl update command send fail!\n", __func__);
+		goto err;
+	}
+	sec_ts_delay(10);
+
+	do {
+		ret = ts->sec_ts_read(ts, SEC_TS_READ_BL_UPDATE_STATUS,
+				      tBuff, 1);
+		if (ret < 0) {
+			input_err(true, &ts->client->dev,
+				"%s: read bl update status fail!\n", __func__);
+			goto err;
+		}
+		sec_ts_delay(2);
+
+	} while (tBuff[0] == 0x1);
+
+	tCmd[0] = 0x55;
+	tCmd[1] = 0xAC;
+	ret = ts->sec_ts_write(ts, 0x57, tCmd, 2);
+	if (ret < 0) {
+		input_err(true, &ts->client->dev,
+				"%s: write passwd fail!\n", __func__);
+		goto err;
+	}
+
+	ret = ts->sec_ts_read(ts, SEC_TS_READ_ID, tBuff, 3);
+
+	if (tBuff[0]  == 0xB4) {
+		input_info(true, &ts->client->dev,
+				"%s: bl update completed!\n", __func__);
+		ret = 1;
+	} else {
+		input_info(true, &ts->client->dev,
+				"%s: bl updated but bl version not matching, ver=%02X\n",
+				__func__, tBuff[0]);
+		goto err;
+	}
+
+	return ret;
+err:
+	return -EIO;
+}
+
+int sec_ts_firmware_update_on_probe(struct sec_ts_data *ts, bool force_update)
+{
+	const struct firmware *fw_entry;
+	char fw_path[SEC_TS_MAX_FW_PATH];
+	int result = -1, restore_cal = 0;
+	int ii = 0;
+	int ret = 0;
+
+	if (ts->plat_data->bringup == 1 && ts->is_fw_corrupted == false) {
+		input_err(true, &ts->client->dev,
+				"%s: bringup. do not update\n", __func__);
+		return 0;
+	}
+
+	if (ts->plat_data->firmware_name)
+		snprintf(fw_path, SEC_TS_MAX_FW_PATH, "%s",
+				ts->plat_data->firmware_name);
+	else
+		return 0;
+
+	disable_irq(ts->client->irq);
+
+	/* read cal status */
+	ts->cal_status = sec_ts_read_calibration_report(ts);
+
+	input_info(true, &ts->client->dev,
+			"%s: initial firmware update %s, cal: %X\n",
+			__func__, fw_path, ts->cal_status);
+
+	/* Loading Firmware */
+	if (request_firmware(&fw_entry, fw_path, &ts->client->dev) !=  0) {
+		input_err(true, &ts->client->dev,
+				"%s: firmware is not available\n", __func__);
+		goto err_request_fw;
+	}
+	input_info(true, &ts->client->dev,
+			"%s: request firmware done! size = %d\n",
+			__func__, (int)fw_entry->size);
+
+	result = sec_ts_check_firmware_version(ts, fw_entry->data);
+
+	if (ts->plat_data->bringup == 2 && ts->is_fw_corrupted == false) {
+		input_err(true, &ts->client->dev,
+				"%s: bringup. do not update\n", __func__);
+		result = 0;
+		goto err_request_fw;
+	}
+
+#ifdef PAT_CONTROL
+	/* ic fw ver > bin fw ver && force is false
+	 **/
+	if ((result <= 0) && (!force_update)) {
+		/* clear nv, forced f/w update eventhough same f/w,
+		 * then apply pat magic
+		 **/
+		if (ts->plat_data->pat_function == PAT_CONTROL_FORCE_UPDATE) {
+			input_info(true, &ts->client->dev,
+					"%s: run forced f/w update and excute autotune\n",
+					__func__);
+		} else {
+			input_info(true, &ts->client->dev,
+					"%s: skip - fw update & nv read\n",
+					__func__);
+			goto err_request_fw;
+		}
+	}
+
+	ts->cal_count = get_tsp_nvm_data(ts, SEC_TS_NVM_OFFSET_CAL_COUNT);
+	input_info(true, &ts->client->dev,
+			"%s: cal_count [%02X]\n", __func__, ts->cal_count);
+
+	/* initialize nv default value from 0xff to 0x00 */
+	if (ts->cal_count == 0xFF) {
+		set_tsp_nvm_data_clear(ts, SEC_TS_NVM_OFFSET_CAL_COUNT);
+		set_tsp_nvm_data_clear(ts, SEC_TS_NVM_OFFSET_TUNE_VERSION);
+		set_tsp_nvm_data_clear(ts, SEC_TS_NVM_OFFSET_TUNE_VERSION+1);
+		input_info(true, &ts->client->dev,
+				"%s: initialize nv as default value & excute autotune\n",
+				__func__);
+	}
+
+	ts->tune_fix_ver = (get_tsp_nvm_data(ts,
+				SEC_TS_NVM_OFFSET_TUNE_VERSION) << 8) |
+			    get_tsp_nvm_data(ts,
+				SEC_TS_NVM_OFFSET_TUNE_VERSION + 1);
+	input_info(true, &ts->client->dev,
+			"%s: tune_fix_ver [%04X] afe_base [%04X]\n",
+			__func__, ts->tune_fix_ver, ts->plat_data->afe_base);
+
+	/* check dt to clear pat */
+	if (ts->plat_data->pat_function == PAT_CONTROL_CLEAR_NV ||
+		ts->plat_data->pat_function == PAT_CONTROL_FORCE_UPDATE)
+		set_tsp_nvm_data_clear(ts, SEC_TS_NVM_OFFSET_CAL_COUNT);
+	ts->cal_count = get_tsp_nvm_data(ts, SEC_TS_NVM_OFFSET_CAL_COUNT);
+
+	/* mismatch calibration -
+	 * ic has too old calibration data after pat enabled
+	 **/
+	if (ts->plat_data->afe_base > ts->tune_fix_ver) {
+		restore_cal = 1;
+		set_tsp_nvm_data_clear(ts, SEC_TS_NVM_OFFSET_CAL_COUNT);
+		ts->cal_count = get_tsp_nvm_data(ts,
+						SEC_TS_NVM_OFFSET_CAL_COUNT);
+	}
+
+	input_info(true, &ts->client->dev,
+		   "%s: cal_count [%02X]\n", __func__, ts->cal_count);
+#else
+	/* ic firmware version >= binary firmare version
+	 * && forced is FALSE
+	 * ic fw ver > bin fw ver && force is false
+	 **/
+	if ((result <= 0) && (!force_update)) {
+		input_info(true, &ts->client->dev,
+				"%s: skip fw update\n", __func__);
+		goto err_request_fw;
+	}
+#endif
+	input_info(true, &ts->client->dev, "%s: IC config %x %x, Bin config %x %x\n",
+			__func__, ts->plat_data->config_version_of_ic[2],
+			ts->plat_data->config_version_of_ic[3],
+			ts->plat_data->config_version_of_bin[2],
+			ts->plat_data->config_version_of_bin[3]);
+
+	/*judge auto-k by comparing config version*/
+	if (ts->plat_data->config_version_of_ic[2] !=
+		ts->plat_data->config_version_of_bin[2] ||
+		ts->plat_data->config_version_of_ic[3] !=
+		ts->plat_data->config_version_of_bin[3])
+		restore_cal = 0;
+	else
+		restore_cal = 1;
+
+	for (ii = 0; ii < 3; ii++) {
+		ret = sec_ts_firmware_update(ts, fw_entry->data,
+					    fw_entry->size, 0, restore_cal, ii);
+		if (ret >= 0)
+			break;
+	}
+
+	if (ret < 0) {
+		result = -1;
+	} else {
+		result = 0;
+#ifdef PAT_CONTROL
+		/* change cal_count from 0 to magic number to make virtual
+		 * pure auto tune
+		 **/
+		if ((ts->cal_count == 0
+		     && ts->plat_data->pat_function == PAT_CONTROL_PAT_MAGIC) ||
+		    (ts->plat_data->pat_function == PAT_CONTROL_FORCE_UPDATE)) {
+			set_pat_magic_number(ts);
+			ts->cal_count = get_tsp_nvm_data(ts,
+						SEC_TS_NVM_OFFSET_CAL_COUNT);
+		}
+#endif
+	}
+
+	sec_ts_save_version_of_ic(ts);
+
+err_request_fw:
+	release_firmware(fw_entry);
+	enable_irq(ts->client->irq);
+	return result;
+}
+
+static int sec_ts_load_fw_from_bin(struct sec_ts_data *ts)
+{
+	const struct firmware *fw_entry;
+	char fw_path[SEC_TS_MAX_FW_PATH];
+	int error = 0;
+
+	if (ts->client->irq)
+		disable_irq(ts->client->irq);
+
+	if (!ts->plat_data->firmware_name)
+		snprintf(fw_path, SEC_TS_MAX_FW_PATH, "%s",
+				SEC_TS_DEFAULT_FW_NAME);
+	else
+		snprintf(fw_path, SEC_TS_MAX_FW_PATH, "%s",
+				ts->plat_data->firmware_name);
+
+	input_info(true, &ts->client->dev,
+		    "%s: initial firmware update  %s\n", __func__, fw_path);
+
+	/* Loading Firmware */
+	if (request_firmware(&fw_entry, fw_path, &ts->client->dev) !=  0) {
+		input_err(true, &ts->client->dev,
+			    "%s: firmware is not available\n", __func__);
+		error = -1;
+		goto err_request_fw;
+	}
+	input_info(true, &ts->client->dev,
+		    "%s: request firmware done! size = %d\n",
+		    __func__, (int)fw_entry->size);
+
+	/* use virtual pat_control - magic cal 1 */
+	if (sec_ts_firmware_update(ts, fw_entry->data, fw_entry->size,
+					0, 1, 0) < 0)
+		error = -1;
+	else
+		error = 0;
+
+	sec_ts_save_version_of_ic(ts);
+
+err_request_fw:
+	release_firmware(fw_entry);
+	if (ts->client->irq)
+		enable_irq(ts->client->irq);
+
+	return error;
+}
+
+static int sec_ts_load_fw_from_ffu(struct sec_ts_data *ts)
+{
+	const struct firmware *fw_entry;
+	const char *fw_path = SEC_TS_DEFAULT_FFU_FW;
+	int result = -1, restore_cal = 0;
+
+	disable_irq(ts->client->irq);
+
+	input_info(true, ts->dev,
+		    "%s: Load firmware: %s\n", __func__, fw_path);
+
+	/* Loading Firmware */
+	if (request_firmware(&fw_entry, fw_path, &ts->client->dev) !=  0) {
+		input_err(true, &ts->client->dev,
+		    "%s: firmware is not available\n", __func__);
+		goto err_request_fw;
+	}
+	input_info(true, &ts->client->dev,
+		    "%s: request firmware done! size = %d\n",
+		    __func__, (int)fw_entry->size);
+
+	sec_ts_check_firmware_version(ts, fw_entry->data);
+
+	input_info(true, &ts->client->dev, "%s: IC config %x %x, Bin config %x %x\n",
+			__func__, ts->plat_data->config_version_of_ic[2],
+			ts->plat_data->config_version_of_ic[3],
+			ts->plat_data->config_version_of_bin[2],
+			ts->plat_data->config_version_of_bin[3]);
+
+	if (ts->plat_data->config_version_of_ic[2] !=
+		ts->plat_data->config_version_of_bin[2] ||
+		ts->plat_data->config_version_of_ic[3] !=
+		ts->plat_data->config_version_of_bin[3])
+		restore_cal = 0;
+	else
+		restore_cal = 1;
+
+	if (sec_ts_firmware_update(ts, fw_entry->data,
+			fw_entry->size, 0, restore_cal, 0) < 0)
+		result = -1;
+	else
+		result = 0;
+
+	sec_ts_save_version_of_ic(ts);
+
+err_request_fw:
+	release_firmware(fw_entry);
+	enable_irq(ts->client->irq);
+	return result;
+}
+
+int sec_ts_firmware_update_on_hidden_menu(struct sec_ts_data *ts,
+					    int update_type)
+{
+	int ret = 0;
+
+	/* Factory cmd for firmware update
+	 * argument represent what is source of firmware like below.
+	 *
+	 * 0 : [BUILT_IN] Getting firmware which is for user.
+	 * 1 : (deprecated) [UMS] Getting firmware from sd card.
+	 * 2 : none
+	 * 3 : [FFU] Getting firmware from air.
+	 */
+
+	switch (update_type) {
+	case BUILT_IN:
+		ret = sec_ts_load_fw_from_bin(ts);
+		break;
+	case FFU:
+		ret = sec_ts_load_fw_from_ffu(ts);
+		break;
+	case BL:
+		ret = sec_ts_firmware_update_bl(ts);
+		if (ret < 0) {
+			break;
+		} else if (!ret) {
+			ret = sec_ts_firmware_update_on_probe(ts, false);
+			break;
+		} else {
+			ret = sec_ts_bl_update(ts);
+			if (ret < 0)
+				break;
+			ret = sec_ts_firmware_update_on_probe(ts, false);
+			if (ret < 0)
+				break;
+		}
+		break;
+	default:
+		input_err(true, ts->dev, "%s: Not support command[%d]\n",
+				__func__, update_type);
+		break;
+	}
+
+#ifdef SEC_TS_SUPPORT_CUSTOMLIB
+	sec_ts_check_custom_library(ts);
+#endif
+
+	return ret;
+}
+EXPORT_SYMBOL(sec_ts_firmware_update_on_hidden_menu);
+
diff --git a/sec_ts_only_vendor.c b/sec_ts_only_vendor.c
new file mode 100644
index 0000000..205e801
--- /dev/null
+++ b/sec_ts_only_vendor.c
@@ -0,0 +1,544 @@
+/* drivers/input/touchscreen/sec_ts_fw.c
+ *
+ * Copyright (C) 2015 Samsung Electronics Co., Ltd.
+ * http://www.samsungsemi.com/
+ *
+ * Core file for Samsung TSC driver
+ *
+ * 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/kernel.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/input.h>
+#include <linux/input/mt.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/firmware.h>
+#include <linux/gpio.h>
+#include <linux/regulator/consumer.h>
+#include <linux/irq.h>
+#include <linux/of_gpio.h>
+#include <linux/time.h>
+#include <linux/vmalloc.h>
+
+#include <linux/uaccess.h>
+/*#include <asm/gpio.h>*/
+
+#include "sec_ts.h"
+
+u8 lv1cmd;
+u8 *read_lv1_buff;
+static int lv1_readsize;
+static int lv1_readremain;
+static int lv1_readoffset;
+
+u8 lv1cmd_manual;
+static int lv1_readsize_manual;
+static int lv1_readremain_manual;
+static int lv1_readoffset_manual;
+
+#define SEC_TS_CMD_BUF_SZ 64
+static u8 cmd_buf[SEC_TS_CMD_BUF_SZ];
+static int cmd_buf_num;
+
+static ssize_t sec_ts_reg_store(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t size);
+static ssize_t sec_ts_regreadsize_store(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t size);
+static inline ssize_t sec_ts_store_error(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t count);
+static ssize_t sec_ts_enter_recovery_store(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t size);
+static ssize_t sec_ts_regread_show(struct device *dev,
+		struct device_attribute *attr, char *buf);
+static ssize_t sec_ts_gesture_status_show(struct device *dev,
+		struct device_attribute *attr, char *buf);
+static inline ssize_t sec_ts_show_error(struct device *dev,
+		struct device_attribute *attr, char *buf);
+
+static ssize_t sec_ts_reg_manual_store(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t size);
+static ssize_t sec_ts_regreadsize_manual_store(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t size);
+static ssize_t sec_ts_regread_manual_show(struct device *dev,
+		struct device_attribute *attr, char *buf);
+
+static DEVICE_ATTR_WO(sec_ts_reg);
+static DEVICE_ATTR_WO(sec_ts_regreadsize);
+static DEVICE_ATTR_WO(sec_ts_enter_recovery);
+static DEVICE_ATTR_RO(sec_ts_regread);
+static DEVICE_ATTR_RO(sec_ts_gesture_status);
+
+static DEVICE_ATTR_WO(sec_ts_reg_manual);
+static DEVICE_ATTR_WO(sec_ts_regreadsize_manual);
+static DEVICE_ATTR_RO(sec_ts_regread_manual);
+
+static struct attribute *cmd_attributes[] = {
+	&dev_attr_sec_ts_reg.attr,
+	&dev_attr_sec_ts_regreadsize.attr,
+	&dev_attr_sec_ts_enter_recovery.attr,
+	&dev_attr_sec_ts_regread.attr,
+	&dev_attr_sec_ts_gesture_status.attr,
+	&dev_attr_sec_ts_reg_manual.attr,
+	&dev_attr_sec_ts_regreadsize_manual.attr,
+	&dev_attr_sec_ts_regread_manual.attr,
+	NULL,
+};
+
+static struct attribute_group cmd_attr_group = {
+	.attrs = cmd_attributes,
+};
+
+/* for debugging-------------------------------------------------------------*/
+static void sec_ts_parsing_cmds(struct device *dev,
+	const char *buf, size_t size, bool write)
+{
+	u8 result, n = 0;
+	char *p, *temp_buf, *token;
+	size_t token_len = 0;
+	struct sec_ts_data *ts = dev_get_drvdata(dev);
+
+	/* clear cmd_buf */
+	memset(cmd_buf, 0, sizeof(cmd_buf));
+	cmd_buf_num = 0;
+
+	/* pre-check input */
+	if (write) {
+		if (size < 2) {
+			input_info(true, &ts->client->dev,
+				"%s: invalid input size %d\n",
+				__func__);
+			return;
+		}
+	} else {
+		if (size < 3) {
+			input_info(true, &ts->client->dev,
+				"%s: invalid input size %d\n",
+				__func__);
+			return;
+		} else if (buf[0] != 'R' && buf[0] != 'r') {
+			input_info(true, &ts->client->dev,
+				"%s: invalid input %c, Have to start with R(r)\n",
+				__func__, buf[0]);
+			return;
+		}
+	}
+
+	/* alloc temp_buf for parsing
+	 * read case will skip 1st character
+	 */
+	temp_buf = kstrdup(buf, GFP_KERNEL);
+	if (!temp_buf) {
+		pr_err("%s: memory allocation failed!",
+			__func__);
+		return;
+	}
+	p = temp_buf;
+
+	/* newline case at last char */
+	if (p[size - 1] == '\n')
+		p[size - 1] = '\0';
+
+	/* skip 1st character for read case */
+	if (!write)
+		p++;
+
+	/* parsing */
+	while (p && (n < SEC_TS_CMD_BUF_SZ)) {
+
+		while (isspace(*p))
+			p++;
+
+		token = strsep(&p, " ");
+		if (!token || *token == '\0')
+			break;
+
+		token_len = strlen(token);
+		if (token_len != 2) {
+			pr_err("%s: bad len %zu\n", __func__, token_len);
+			n = 0;
+			break;
+		}
+
+		if (kstrtou8(token, 16, &result)) {
+			/* Conversion failed due to bad input.
+			 * Discard the entire buffer.
+			 */
+			pr_err("%s: bad input\n", __func__);
+			n = 0;
+			break;
+		}
+		/* found a valid cmd/args */
+		cmd_buf[n] = result;
+		n++;
+	}
+	kfree(temp_buf);
+	cmd_buf_num = n;
+}
+
+/* sysfs file node to write reg
+ *
+ *     echo _REG_ _VAL_ ... > sec_ts_reg_manual
+ *
+ *     e.g. write reg 0xD7 with 0x02 0x04
+ *     echo D7 02 04 > sec_ts_reg_manual
+ */
+static ssize_t sec_ts_reg_manual_store(struct device *dev,
+	struct device_attribute *attr, const char *buf, size_t size)
+{
+	struct sec_ts_data *ts = dev_get_drvdata(dev);
+
+	if (ts->power_status == SEC_TS_STATE_POWER_OFF) {
+		input_info(true, &ts->client->dev,
+			"%s: Power off state\n", __func__);
+		return -EIO;
+	}
+
+	sec_ts_parsing_cmds(dev, buf, size, true);
+
+	if (cmd_buf_num) {
+		ts->sec_ts_write_burst(ts, cmd_buf, cmd_buf_num);
+
+		input_info(true, &ts->client->dev,
+			"%s: size %d, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x\n",
+			__func__, cmd_buf_num, cmd_buf[0], cmd_buf[1],
+			cmd_buf[2], cmd_buf[3], cmd_buf[4]);
+	}
+
+	return size;
+}
+
+/* sysfs file node to read reg
+ *
+ * step 1: set reg and size that want to read
+ *     echo R_REG_ _SIZE_ > sec_ts_regreadsize_manual
+ *
+ *     e.g. read reg 0x52 for 3 bytes
+ *        echo R52 03 > sec_ts_regreadsize_manual
+ *
+ * step 2: read reg
+ *     cat sec_ts_regread_manual
+ */
+static ssize_t sec_ts_regreadsize_manual_store(struct device *dev,
+	struct device_attribute *attr, const char *buf, size_t size)
+{
+	struct sec_ts_data *ts = dev_get_drvdata(dev);
+
+	sec_ts_parsing_cmds(dev, buf, size, false);
+
+	if (cmd_buf_num == 2) {
+		lv1cmd_manual = cmd_buf[0];
+		lv1_readsize_manual = cmd_buf[1];
+		lv1_readoffset_manual = 0;
+		lv1_readremain_manual = 0;
+		input_info(true, &ts->client->dev,
+			"%s: read reg %X sz %d\n",
+			__func__, lv1cmd_manual, lv1_readsize_manual);
+	} else
+		input_info(true, &ts->client->dev,
+			"%s: invalid input to reg read! cmd_num %d, cmd %x %x\n",
+			__func__, cmd_buf_num, cmd_buf[0], cmd_buf[1]);
+
+	return size;
+}
+
+
+/* sysfs file node to read reg
+ *     check sec_ts_regreadsize_manual_store() above for details.
+ */
+static ssize_t sec_ts_regread_manual_show(struct device *dev,
+	struct device_attribute *attr, char *buf)
+{
+	u8 *read_lv1_buff_manual;
+	struct sec_ts_data *ts = dev_get_drvdata(dev);
+	unsigned int str_len = 0;
+	int ret = 0, i;
+
+	if (ts->power_status == SEC_TS_STATE_POWER_OFF) {
+		input_err(true, &ts->client->dev,
+			"%s: Power off state\n", __func__);
+		return -EIO;
+	}
+	if (lv1_readsize_manual < 1) {
+		input_err(true, &ts->client->dev,
+			"%s: Nothing to read\n", __func__);
+		return -EIO;
+	}
+
+	disable_irq(ts->client->irq);
+
+	read_lv1_buff_manual = kzalloc(lv1_readsize_manual, GFP_KERNEL);
+	if (!read_lv1_buff_manual)
+		goto malloc_err;
+
+	ret = ts->sec_ts_read_heap(ts, lv1cmd_manual,
+		read_lv1_buff_manual, lv1_readsize_manual);
+	if (ret < 0)
+		input_err(true, &ts->client->dev,
+			"%s: read reg %x failed!\n",
+			__func__, lv1cmd_manual);
+	else {
+		for (i = 0 ; i < lv1_readsize_manual ; i++)
+			str_len += scnprintf(buf + str_len,
+				PAGE_SIZE - str_len,
+				"%02X ",
+				(u8)read_lv1_buff_manual[i]);
+		str_len += scnprintf(buf + str_len, PAGE_SIZE - str_len, "\n");
+		input_info(true, &ts->client->dev, "%s: reg %X sz %d -> %s\n",
+			__func__, lv1cmd_manual, lv1_readsize_manual, buf);
+	}
+
+	kfree(read_lv1_buff_manual);
+
+malloc_err:
+	lv1_readremain_manual = 0;
+	enable_irq(ts->client->irq);
+
+	return str_len;
+}
+
+static ssize_t sec_ts_reg_store(struct device *dev,
+	struct device_attribute *attr, const char *buf, size_t size)
+{
+	struct sec_ts_data *ts = dev_get_drvdata(dev);
+
+	if (ts->power_status == SEC_TS_STATE_POWER_OFF) {
+		input_info(true, &ts->client->dev, "%s: Power off state\n",
+			    __func__);
+		return -EIO;
+	}
+
+	if (size > 0)
+		ts->sec_ts_write_burst(ts, (u8 *)buf, size);
+
+	input_info(true, &ts->client->dev,
+		"%s: 0x%x, 0x%x, size %d\n",
+		__func__, buf[0], buf[1], (int)size);
+	return size;
+}
+
+static ssize_t sec_ts_regread_show(struct device *dev,
+				    struct device_attribute *attr, char *buf)
+{
+	struct sec_ts_data *ts = dev_get_drvdata(dev);
+	int ret;
+
+	if (ts->power_status == SEC_TS_STATE_POWER_OFF) {
+		input_err(true, &ts->client->dev, "%s: Power off state\n",
+			    __func__);
+		return -EIO;
+	}
+
+	disable_irq(ts->client->irq);
+
+	mutex_lock(&ts->device_mutex);
+
+	read_lv1_buff = kzalloc(lv1_readsize, GFP_KERNEL);
+	if (!read_lv1_buff)
+		goto malloc_err;
+
+	ret = ts->sec_ts_read_heap(ts, lv1cmd, read_lv1_buff, lv1_readsize);
+	if (ret < 0) {
+		input_err(true, &ts->client->dev, "%s: read %x command fail\n",
+			__func__, lv1cmd);
+		goto i2c_err;
+	}
+
+	input_info(true, &ts->client->dev, "%s: lv1_readsize = %d\n",
+		    __func__, lv1_readsize);
+	memcpy(buf, read_lv1_buff + lv1_readoffset, lv1_readsize);
+
+i2c_err:
+	kfree(read_lv1_buff);
+malloc_err:
+	mutex_unlock(&ts->device_mutex);
+	lv1_readremain = 0;
+	enable_irq(ts->client->irq);
+
+	return lv1_readsize;
+}
+
+static ssize_t sec_ts_gesture_status_show(struct device *dev,
+					struct device_attribute *attr,
+					char *buf)
+{
+	struct sec_ts_data *ts = dev_get_drvdata(dev);
+
+	mutex_lock(&ts->device_mutex);
+	memcpy(buf, ts->gesture_status, sizeof(ts->gesture_status));
+	input_info(true, &ts->client->dev,
+		    "%s: GESTURE STATUS %x %x %x %x %x %x\n", __func__,
+		    ts->gesture_status[0], ts->gesture_status[1],
+		    ts->gesture_status[2], ts->gesture_status[3],
+		    ts->gesture_status[4], ts->gesture_status[5]);
+	mutex_unlock(&ts->device_mutex);
+
+	return sizeof(ts->gesture_status);
+}
+
+static ssize_t sec_ts_regreadsize_store(struct device *dev,
+					struct device_attribute *attr,
+					const char *buf, size_t size)
+{
+	struct sec_ts_data *ts = dev_get_drvdata(dev);
+
+	mutex_lock(&ts->device_mutex);
+
+	lv1cmd = buf[0];
+	lv1_readsize = ((unsigned int)buf[4] << 24) |
+			((unsigned int)buf[3] << 16) |
+			((unsigned int) buf[2] << 8) |
+			((unsigned int)buf[1] << 0);
+	lv1_readoffset = 0;
+	lv1_readremain = 0;
+
+	mutex_unlock(&ts->device_mutex);
+
+	return size;
+}
+
+static ssize_t sec_ts_enter_recovery_store(struct device *dev,
+					    struct device_attribute *attr,
+					    const char *buf, size_t size)
+{
+	struct sec_ts_data *ts = dev_get_drvdata(dev);
+	struct sec_ts_plat_data *pdata = ts->plat_data;
+	int ret;
+	unsigned long on;
+
+	ret = kstrtoul(buf, 10, &on);
+	if (ret != 0) {
+		input_err(true, &ts->client->dev, "%s: failed to read: %d\n",
+					__func__, ret);
+		return -EINVAL;
+	}
+
+	if (on == 1) {
+		disable_irq(ts->client->irq);
+		gpio_free(pdata->irq_gpio);
+
+		input_info(true, &ts->client->dev,
+			    "%s: gpio free\n", __func__);
+		if (gpio_is_valid(pdata->irq_gpio)) {
+			ret = gpio_request_one(pdata->irq_gpio,
+					    GPIOF_OUT_INIT_LOW, "sec,tsp_int");
+			input_info(true, &ts->client->dev,
+				    "%s: gpio request one\n", __func__);
+			if (ret < 0)
+				input_err(true, &ts->client->dev,
+				    "%s: Unable to request tsp_int [%d]: %d\n",
+				    __func__, pdata->irq_gpio, ret);
+		} else {
+			input_err(true, &ts->client->dev,
+				"%s: Failed to get irq gpio\n", __func__);
+			return -EINVAL;
+		}
+
+		pdata->power(ts, false);
+		sec_ts_delay(100);
+		pdata->power(ts, true);
+	} else {
+		gpio_free(pdata->irq_gpio);
+
+		if (gpio_is_valid(pdata->irq_gpio)) {
+			ret = gpio_request_one(pdata->irq_gpio, GPIOF_DIR_IN,
+						"sec,tsp_int");
+			if (ret) {
+				input_err(true, &ts->client->dev,
+				    "%s: Unable to request tsp_int [%d]\n",
+				    __func__, pdata->irq_gpio);
+				return -EINVAL;
+			}
+		} else {
+			input_err(true, &ts->client->dev,
+				"%s: Failed to get irq gpio\n", __func__);
+			return -EINVAL;
+		}
+
+		pdata->power(ts, false);
+		sec_ts_delay(500);
+		pdata->power(ts, true);
+		sec_ts_delay(500);
+
+		/* AFE Calibration */
+		ret = ts->sec_ts_write(ts,
+				    SEC_TS_CMD_CALIBRATION_AMBIENT, NULL, 0);
+		if (ret < 0)
+			input_err(true, &ts->client->dev,
+				"%s: fail to write AFE_CAL\n", __func__);
+
+		sec_ts_delay(1000);
+		enable_irq(ts->client->irq);
+	}
+
+	sec_ts_read_information(ts);
+
+	return size;
+}
+
+static inline ssize_t sec_ts_show_error(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct sec_ts_data *ts = dev_get_drvdata(dev);
+
+	input_err(true, &ts->client->dev,
+		"%s: read only function, %s\n", __func__, attr->attr.name);
+	return -EPERM;
+}
+
+static inline ssize_t sec_ts_store_error(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t count)
+{
+	struct sec_ts_data *ts = dev_get_drvdata(dev);
+
+	input_err(true, &ts->client->dev,
+		"%s: write only function, %s\n", __func__, attr->attr.name);
+	return -EPERM;
+}
+
+int sec_ts_raw_device_init(struct sec_ts_data *ts)
+{
+	int ret;
+
+#ifdef CONFIG_SEC_SYSFS
+	ts->dev = sec_device_create(ts, "sec_ts");
+#else
+	ts->dev = device_create(sec_class, NULL, 0, ts, "sec_ts");
+#endif
+	ret = IS_ERR(ts->dev);
+	if (ret) {
+		input_err(true, &ts->client->dev,
+			    "%s: fail - device_create\n", __func__);
+		return ret;
+	}
+
+	ret = sysfs_create_group(&ts->dev->kobj, &cmd_attr_group);
+	if (ret < 0) {
+		input_err(true, &ts->client->dev,
+			    "%s: fail - sysfs_create_group\n", __func__);
+		goto err_sysfs;
+	}
+
+	return ret;
+err_sysfs:
+	input_err(true, &ts->client->dev, "%s: fail\n", __func__);
+	return ret;
+}
+
+void sec_ts_raw_device_exit(struct sec_ts_data *ts)
+{
+	sysfs_remove_group(&ts->dev->kobj, &cmd_attr_group);
+#ifdef CONFIG_SEC_SYSFS
+	sec_device_destroy(ts->dev->devt);
+#else
+	device_destroy(sec_class, 0);
+#endif
+}
+