summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoger Liao <rogerliao@google.com>2020-06-11 11:03:55 +0800
committerRoger Liao <rogerliao@google.com>2020-06-11 11:04:00 +0800
commit97eeffb353e48ff7a7cd4d44e7dedb40a9290bed (patch)
treecb1b6a813186a64b166372964810177b69475775
parentb8c1024889a6cd711e6677c6262555138982fdd8 (diff)
parent7fb646d439aa9b2751b08ff2e44dab2c9e6a4ec8 (diff)
downloadsec_touch-97eeffb353e48ff7a7cd4d44e7dedb40a9290bed.tar.gz
Merge branch 'android-msm-pixel-4.19' into android-msm-barbet-4.19
From build 6575781 Bug: 158714637 Signed-off-by: Roger Liao <rogerliao@google.com> Change-Id: I7a015909f4376153405934a4959196ae01a9afcd
-rw-r--r--Kbuild3
-rw-r--r--Kconfig23
-rw-r--r--Makefile7
-rw-r--r--sec_cmd.c554
-rw-r--r--sec_cmd.h161
-rw-r--r--sec_ts.c4828
-rw-r--r--sec_ts.h1162
-rw-r--r--sec_ts_fac_spec.h518
-rw-r--r--sec_ts_fn.c8058
-rw-r--r--sec_ts_fw.c1601
-rw-r--r--sec_ts_only_vendor.c544
11 files changed, 17459 insertions, 0 deletions
diff --git a/Kbuild b/Kbuild
new file mode 100644
index 0000000..04453d7
--- /dev/null
+++ b/Kbuild
@@ -0,0 +1,3 @@
+obj-$(CONFIG_TOUCHSCREEN_SEC_TS) += sec_touch.o
+sec_touch-objs += sec_cmd.o sec_ts.o sec_ts_fw.o sec_ts_fn.o \
+ sec_ts_only_vendor.o
diff --git a/Kconfig b/Kconfig
new file mode 100644
index 0000000..5193e28
--- /dev/null
+++ b/Kconfig
@@ -0,0 +1,23 @@
+#
+# Samsung Electronics TOUCH driver configuration
+#
+
+config TOUCHSCREEN_SEC_TS
+ tristate "Samsung Electronics Touchscreen"
+ depends on I2C
+ 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..dbc92ee
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,7 @@
+KERNEL_SRC ?= /lib/modules/$(shell uname -r)/build
+M ?= $(shell pwd)
+
+KBUILD_OPTIONS += CONFIG_TOUCHSCREEN_SEC_TS=m
+
+modules modules_install clean:
+ $(MAKE) -C $(KERNEL_SRC) M=$(M) $(KBUILD_OPTIONS) $(@)
diff --git a/sec_cmd.c b/sec_cmd.c
new file mode 100644
index 0000000..fe452d4
--- /dev/null
+++ b/sec_cmd.c
@@ -0,0 +1,554 @@
+/*
+ * 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);
+}
+
+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);
+}
+
+#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_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_list);
+
+static struct attribute *sec_fac_attrs[] = {
+ &dev_attr_cmd.attr,
+ &dev_attr_cmd_status.attr,
+ &dev_attr_cmd_result.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..5299cf4
--- /dev/null
+++ b/sec_cmd.h
@@ -0,0 +1,161 @@
+
+#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];
+ 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 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..f3a0918
--- /dev/null
+++ b/sec_ts.c
@@ -0,0 +1,4828 @@
+/* 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"
+
+/* 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);
+static void sec_ts_charger_work(struct work_struct *work);
+
+#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
+
+int sec_ts_read_information(struct sec_ts_data *ts);
+
+#ifndef I2C_INTERFACE
+int sec_ts_spi_delay(u8 reg);
+#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 } };
+ 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;
+ }
+
+ usleep_range(sec_ts_spi_delay(reg),
+ sec_ts_spi_delay(reg));
+
+ // 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;
+
+ 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;
+ }
+ continue;
+ } else
+ break;
+ }
+ if (ret == 0)
+ memcpy(data, ts->io_read_buf +
+ SEC_TS_SPI_READ_HEADER_SIZE, len);
+#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;
+ }
+
+ usleep_range(sec_ts_spi_delay(reg),
+ sec_ts_spi_delay(reg));
+
+ 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);
+#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 */
+ if (ts->io_err_count >= SEC_TS_IO_RESET_CNT) {
+ ts->io_err_count = 0;
+ sec_ts_hw_reset(ts);
+ }
+
+ 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);
+}
+
+#ifndef I2C_INTERFACE
+int sec_ts_spi_delay(u8 reg)
+{
+ switch (reg) {
+ case SEC_TS_READ_TOUCH_RAWDATA:
+ return 400;
+ case SEC_TS_CMD_HEATMAP_READ:
+ return 500;
+ case SEC_TS_READ_ALL_EVENT:
+ return 500;
+ case SEC_TS_READ_CSRAM_RTDP_DATA:
+ return 500;
+ case SEC_TS_CAAT_READ_STORED_DATA:
+ return 500;
+ case SEC_TS_CMD_FLASH_READ_DATA:
+ return 1800;
+ case SEC_TS_READ_FIRMWARE_INTEGRITY:
+ return 20*1000;
+ case SEC_TS_READ_SELFTEST_RESULT:
+ return 3500;
+ default: return 100;
+ }
+}
+#endif
+
+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 read custom library command\n", __func__);
+
+ 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 count:%d, fail count:%d, status:%X, param version:%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;
+}
+
+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)
+{
+ /* Motion filter timeout, in milliseconds */
+ const u32 mf_timeout_ms = 500;
+ u8 next_state;
+ /* Count the active touches */
+ u8 touches = hweight32(ts->tid_touch_state);
+
+ 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);
+ const 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->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};
+
+ 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);
+ /*
+ * 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;
+ }
+
+ 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->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->frame_type != TYPE_SIGNAL_DATA) {
+ input_info(true, &ts->client->dev,
+ "%s: frame_type change from %#x\n",
+ __func__, ts->frame_type);
+
+ /* Check raw type is TYPE_INVALID_DATA */
+ if (ts->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->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->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
+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
+
+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->coord[t_id].minor = p_event_coord->minor;
+
+ if (!ts->coord[t_id].palm &&
+ (ts->coord[t_id].ttype == SEC_TS_TOUCHTYPE_PALM))
+ ts->coord[t_id].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].z <= 0)
+ ts->coord[t_id].z = 1;
+
+ 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) {
+
+ do_gettimeofday(&ts->time_released[t_id]);
+
+ if (ts->time_longest <
+ (ts->time_released[t_id].tv_sec -
+ ts->time_pressed[t_id].tv_sec))
+ ts->time_longest =
+ (ts->time_released[t_id].tv_sec
+ - ts->time_pressed[t_id].tv_sec);
+
+ 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->touch_count--;
+ 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);
+ 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);
+
+ } else if (ts->coord[t_id].action ==
+ SEC_TS_COORDINATE_ACTION_PRESS) {
+ do_gettimeofday(&ts->time_pressed[t_id]);
+
+ ts->touch_count++;
+ ts->all_finger_count++;
+
+ 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;
+
+ input_mt_slot(ts->input_dev, t_id);
+ __set_bit(t_id, &ts->tid_touch_state);
+ if (ts->coord[t_id].palm) {
+ input_mt_report_slot_state(
+ ts->input_dev, MT_TOOL_PALM, 1);
+ __set_bit(t_id, &ts->tid_palm_state);
+ __clear_bit(t_id, &ts->tid_grip_state);
+ } else if (ts->coord[t_id].grip) {
+ input_mt_report_slot_state(
+ ts->input_dev, MT_TOOL_PALM, 1);
+ __clear_bit(t_id, &ts->tid_palm_state);
+ __set_bit(t_id, &ts->tid_grip_state);
+ } else {
+ input_mt_report_slot_state(
+ ts->input_dev,
+ MT_TOOL_FINGER, 1);
+ __clear_bit(t_id, &ts->tid_palm_state);
+ __clear_bit(t_id, &ts->tid_grip_state);
+ }
+ 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 ((ts->touch_count > 4) &&
+ (ts->check_multi == 0)) {
+ ts->check_multi = 1;
+ ts->multi_count++;
+ }
+
+ } else if (ts->coord[t_id].action ==
+ SEC_TS_COORDINATE_ACTION_MOVE) {
+#ifdef SW_GLOVE
+ if ((ts->coord[t_id].ttype ==
+ SEC_TS_TOUCHTYPE_GLOVE) &&
+ !ts->touchkey_glove_mode_status) {
+ ts->touchkey_glove_mode_status = true;
+ 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) {
+ ts->touchkey_glove_mode_status = false;
+ input_report_switch(ts->input_dev,
+ SW_GLOVE, 0);
+ }
+#endif
+ input_mt_slot(ts->input_dev, t_id);
+ __set_bit(t_id, &ts->tid_touch_state);
+ if (ts->coord[t_id].palm) {
+ input_mt_report_slot_state(
+ ts->input_dev, MT_TOOL_PALM, 1);
+ __set_bit(t_id, &ts->tid_palm_state);
+ __clear_bit(t_id, &ts->tid_grip_state);
+ } else if (ts->coord[t_id].grip) {
+ input_mt_report_slot_state(
+ ts->input_dev, MT_TOOL_PALM, 1);
+ __clear_bit(t_id, &ts->tid_palm_state);
+ __set_bit(t_id, &ts->tid_grip_state);
+ } else {
+ input_mt_report_slot_state(
+ ts->input_dev,
+ MT_TOOL_FINGER, 1);
+ __clear_bit(t_id, &ts->tid_palm_state);
+ __clear_bit(t_id, &ts->tid_grip_state);
+ }
+ 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);
+ ts->coord[t_id].mcount++;
+ } 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);
+}
+
+#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
+
+#define MAX_EVENT_COUNT 32
+static void sec_ts_read_event(struct sec_ts_data *ts)
+{
+ int ret;
+ u8 t_id;
+ 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;
+ unsigned long last_tid_palm_state = ts->tid_palm_state;
+ unsigned long last_tid_grip_state = ts->tid_grip_state;
+
+ 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 = t_id = 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->temp == 0x01)
+ 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 {
+ s16 max_force_p = 0;
+
+ event_buff = read_event_buff[curr_pos];
+ event_id = event_buff[0] & 0x3;
+
+ if (ts->temp == 0x01)
+ 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:
+ p_event_status =
+ (struct sec_ts_event_status *)event_buff;
+
+ /* tchsta == 0 && ttype == 0 && eid == 0 : buffer empty
+ **/
+ if (p_event_status->stype > 0) {
+ /* Demote 'vendor' messages */
+ if (p_event_status->stype ==
+ TYPE_STATUS_EVENT_VENDOR_INFO) {
+ u8 status_id =
+ p_event_status->status_id;
+ u8 status_data_1 =
+ p_event_status->status_data_1;
+
+ input_dbg(true, &ts->client->dev,
+ "%s: STATUS %x %x %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], event_buff[6],
+ event_buff[7]);
+
+ switch (status_id) {
+ case SEC_TS_EVENT_STATUS_ID_WLC:
+ input_info(true,
+ &ts->client->dev,
+ "STATUS: wlc mode change to %x\n",
+ status_data_1);
+ break;
+
+ case SEC_TS_EVENT_STATUS_ID_NOISE:
+ input_info(true,
+ &ts->client->dev,
+ "STATUS: noise mode change to %x\n",
+ status_data_1);
+ break;
+
+ case SEC_TS_EVENT_STATUS_ID_GRIP:
+ input_info(true,
+ &ts->client->dev,
+ "STATUS: detect grip %s!\n",
+ (status_data_1) ?
+ "enter" : "leave");
+ break;
+
+ case SEC_TS_EVENT_STATUS_ID_PALM:
+ input_info(true,
+ &ts->client->dev,
+ "STATUS: detect palm!\n");
+ break;
+
+ default:
+ break;
+ }
+ } else
+ input_info(true, &ts->client->dev,
+ "%s: STATUS %x %x %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], event_buff[6],
+ event_buff[7]);
+ }
+
+ 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 !? */
+ sec_ts_unlocked_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 done\n",
+ __func__);
+ sec_ts_unlocked_release_all_finger(ts);
+ complete_all(&ts->boot_completed);
+ break;
+ case 0x10:
+ input_info(true, &ts->client->dev,
+ "%s: hw_reset done\n",
+ __func__);
+ sec_ts_unlocked_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_unlocked_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
+ sec_ts_handle_lib_status_event(ts, p_event_status);
+#endif
+ break;
+
+ case SEC_TS_COORDINATE_EVENT:
+ processed_pointer_event = true;
+ sec_ts_handle_coord_event(ts,
+ (struct sec_ts_event_coordinate *)event_buff);
+ break;
+
+ case SEC_TS_GESTURE_EVENT:
+ p_gesture_status =
+ (struct sec_ts_gesture_status *)event_buff;
+#ifdef SEC_TS_SUPPORT_CUSTOMLIB
+ sec_ts_handle_gesture_event(ts, p_gesture_status);
+#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;
+ }
+
+ 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:%d 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) {
+ input_dbg(false, &ts->client->dev,
+ "%s[R] tID:%d mc:%d tc:%d lx:%d ly:%d f:%d v:%02X%02X cal:%02X(%02X) id(%d,%d) p:%d P%02XT%04X\n",
+ ts->dex_name,
+ t_id, ts->coord[t_id].mcount,
+ ts->touch_count,
+ ts->coord[t_id].x, ts->coord[t_id].y,
+ max_force_p,
+ 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].palm_count,
+ ts->cal_count, ts->tune_fix_ver);
+
+ ts->coord[t_id].action =
+ SEC_TS_COORDINATE_ACTION_NONE;
+ ts->coord[t_id].mcount = 0;
+ ts->coord[t_id].palm_count = 0;
+ max_force_p = 0;
+ }
+ }
+
+ curr_pos++;
+ remain_event_count--;
+ } while (remain_event_count >= 0);
+
+ input_sync(ts->input_dev);
+#if IS_ENABLED(CONFIG_TOUCHSCREEN_HEATMAP)
+ if (processed_pointer_event) {
+ 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");
+ }
+ }
+#endif
+}
+
+static irqreturn_t sec_ts_isr(int irq, void *handle)
+{
+ struct sec_ts_data *ts = (struct sec_ts_data *)handle;
+
+ ts->timestamp = ktime_get();
+ input_set_timestamp(ts->input_dev, ts->timestamp);
+
+ 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 */
+ pm_qos_update_request(&ts->pm_qos_req, 100);
+ pm_wakeup_event(&ts->client->dev, MSEC_PER_SEC);
+
+ mutex_lock(&ts->eventlock);
+
+ sec_ts_read_event(ts);
+
+ mutex_unlock(&ts->eventlock);
+
+#if IS_ENABLED(CONFIG_TOUCHSCREEN_HEATMAP)
+ /* Disable the firmware motion filter during single touch */
+ update_motion_filter(ts);
+#endif
+
+ pm_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;
+}
+
+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;
+
+}
+
+static int sec_ts_power(void *data, bool on)
+{
+ struct sec_ts_data *ts = (struct sec_ts_data *)data;
+ const struct sec_ts_plat_data *pdata = ts->plat_data;
+ struct regulator *regulator_dvdd = NULL;
+ struct regulator *regulator_avdd = NULL;
+ static bool dvdd_enabled, avdd_enabled;
+ int ret = 0;
+
+ if (pdata->regulator_dvdd) {
+ regulator_dvdd = regulator_get(&ts->client->dev,
+ pdata->regulator_dvdd);
+ if (IS_ERR_OR_NULL(regulator_dvdd))
+ input_err(true, &ts->client->dev,
+ "%s: Failed to get %s regulator.\n",
+ __func__, pdata->regulator_dvdd);
+ }
+
+ if (pdata->regulator_avdd) {
+ regulator_avdd = regulator_get(&ts->client->dev,
+ pdata->regulator_avdd);
+ if (IS_ERR_OR_NULL(regulator_avdd))
+ input_err(true, &ts->client->dev,
+ "%s: Failed to get %s regulator.\n",
+ __func__, pdata->regulator_avdd);
+ }
+
+ if (regulator_dvdd && (dvdd_enabled != on)) {
+ ret = (on) ? regulator_enable(regulator_dvdd) :
+ regulator_disable(regulator_dvdd);
+ if (ret)
+ input_err(true, &ts->client->dev,
+ "%s: Failed to control dvdd: %d\n",
+ __func__, ret);
+ else {
+ sec_ts_delay(1);
+ dvdd_enabled = on;
+ }
+ }
+
+ if (regulator_avdd && (avdd_enabled != on)) {
+ ret = (on) ? regulator_enable(regulator_avdd) :
+ regulator_disable(regulator_avdd);
+ if (ret)
+ input_err(true, &ts->client->dev,
+ "%s: Failed to control avdd: %d\n",
+ __func__, ret);
+ else
+ avdd_enabled = on;
+ }
+
+ if (regulator_dvdd) {
+ input_info(true, &ts->client->dev, "%s: %s: dvdd:%s\n",
+ __func__, on ? "on" : "off",
+ regulator_is_enabled(regulator_dvdd) ? "on" : "off");
+ regulator_put(regulator_dvdd);
+ }
+
+ if (regulator_avdd) {
+ input_info(true, &ts->client->dev, "%s: %s: avdd:%s\n",
+ __func__, on ? "on" : "off",
+ regulator_is_enabled(regulator_avdd) ? "on" : "off");
+ regulator_put(regulator_avdd);
+ }
+
+ 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];
+ 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_err(true, dev,
+ "%s: Failed to get tsp-icid gpio\n", __func__);
+ }
+
+ pdata->tsp_vsync = of_get_named_gpio(np, "sec,tsp_vsync_gpio", 0);
+ if (gpio_is_valid(pdata->tsp_vsync))
+ input_info(true, &client->dev, "%s: vsync %s\n", __func__,
+ gpio_get_value(pdata->tsp_vsync) ?
+ "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_err(true, dev,
+ "%s: Failed to get irq_type property\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;
+
+#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__);
+ }
+
+ 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_err(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_err(true, dev, "%s: Failed to get 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;
+ }
+ //TODO: check this
+ 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);
+
+ } 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_err(true, &client->dev,
+ "%s: skipped to get project_name property\n", __func__);
+ if (of_property_read_string_index(np, "sec,project_name",
+ 1, &pdata->model_name))
+ input_err(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;
+
+ if (of_property_read_string(np,
+ "sec,regulator_dvdd", &pdata->regulator_dvdd))
+ input_err(true, dev,
+ "%s: Failed to get regulator_dvdd name property\n",
+ __func__);
+
+ if (of_property_read_string(np,
+ "sec,regulator_avdd", &pdata->regulator_avdd))
+ input_err(true, dev,
+ "%s: Failed to get regulator_avdd name property\n",
+ __func__);
+
+ 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,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;
+
+#ifdef PAT_CONTROL
+ input_err(true, &client->dev,
+ "%s: buffer limit: %d, lcd_id:%06X, bringup:%d, FW:%s(%d), id:%d,%d, pat_function:%d mis_cal:%d dex:%d, gesture:%d\n",
+ __func__, pdata->io_burstmax, lcdtype, pdata->bringup,
+ pdata->firmware_name, count, pdata->tsp_id, pdata->tsp_icid,
+ pdata->pat_function, pdata->mis_cal_check, pdata->support_dex,
+ pdata->support_sidegesture);
+#else
+ input_err(true, &client->dev,
+ "%s: buffer limit: %d, lcd_id:%06X, bringup:%d, FW:%s(%d), id:%d,%d, dex:%d, gesture:%d\n",
+ __func__, pdata->io_burstmax, lcdtype, pdata->bringup,
+ pdata->firmware_name, count, pdata->tsp_id, pdata->tsp_icid,
+ pdata->support_dex, pdata->support_sidegesture);
+#endif
+ 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:%X, nRX:%X, 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: 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: TOUCH 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, 0, 0);
+ input_set_abs_params(dev, ABS_MT_TOUCH_MINOR, 0, 255, 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);
+
+ 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: TOUCH 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->gainTable = kzalloc(ts->tx_count * ts->rx_count, GFP_KERNEL);
+ if (!ts->gainTable) {
+ kfree(ts->pFrame);
+ ts->pFrame = NULL;
+ return SEC_TS_ERR_ALLOC_GAINTABLE;
+ }
+
+ 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 struct notifier_block sec_ts_screen_nb;
+static struct notifier_block sec_ts_psy_nb;
+
+#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
+ input_info(true, &client->dev, "%s: SPI interface\n", __func__);
+#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 (!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);
+ INIT_WORK(&ts->charger_work, sec_ts_charger_work);
+ 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)
+ ts->tbn = tbn_init(&ts->client->dev);
+ if (!ts->tbn) {
+ input_err(true, &ts->client->dev,
+ "%s: TBN initialization error\n", __func__);
+ ret = -ENODEV;
+ goto err_init_tbn;
+ }
+#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);
+ if (!pdata->regulator_boot_on)
+ sec_ts_delay(70);
+ ts->power_status = SEC_TS_STATE_POWER_ON;
+ ts->external_factory = 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__);
+ goto err_init;
+ }
+
+ input_info(true, &ts->client->dev,
+ "%s: Attempting to reflash the firmware. Boot status = 0x%02X\n",
+ __func__, boot_status);
+ if (boot_status != SEC_TS_STATUS_BOOT_MODE)
+ input_err(true, &ts->client->dev,
+ "%s: device is not in bootloader mode!\n",
+ __func__);
+
+ ts->is_fw_corrupted = true;
+ }
+
+ 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:
+ goto err_init;
+ case SEC_TS_ERR_ALLOC_FRAME:
+ goto err_allocate_frame;
+ 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;
+ }
+ }
+
+ pm_qos_add_request(&ts->pm_qos_req, PM_QOS_CPU_DMA_LATENCY,
+ 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;
+#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) {
+ input_err(true, &ts->client->dev,
+ "%s: Heatmap probe failed\n", __func__);
+ goto err_irq;
+ }
+#endif
+
+ 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;
+ }
+
+ ts->notifier = sec_ts_screen_nb;
+ ret = drm_panel_notifier_register(pdata->panel, &ts->notifier);
+ if (ret < 0) {
+ input_err(true, &ts->client->dev,
+ "%s: drm_panel_notifier_register failed. ret = 0x%08X\n",
+ __func__, ret);
+ goto err_register_drm_client;
+ }
+
+#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");
+ 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");
+
+ input_err(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);
+ **/
+err_register_drm_client:
+ free_irq(client->irq, ts);
+err_heatmap:
+#if IS_ENABLED(CONFIG_TOUCHSCREEN_HEATMAP)
+ heatmap_remove(&ts->v4l2);
+err_irq:
+#endif
+ pm_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:
+ kfree(ts->gainTable);
+err_allocate_gaintable:
+ 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)
+ tbn_cleanup(ts->tbn);
+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;
+
+ for (i = 0; i < MAX_SUPPORT_TOUCH_COUNT; i++) {
+ input_mt_slot(ts->input_dev, i);
+ 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)) {
+
+ ts->coord[i].action = SEC_TS_COORDINATE_ACTION_RELEASE;
+ input_info(true, &ts->client->dev,
+ "%s: [RA] tID:%d mc:%d tc:%d v:%02X%02X cal:%02X(%02X) id(%d,%d) p:%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].palm_count);
+
+ do_gettimeofday(&ts->time_released[i]);
+
+ if (ts->time_longest <
+ (ts->time_released[i].tv_sec -
+ ts->time_pressed[i].tv_sec))
+ ts->time_longest =
+ (ts->time_released[i].tv_sec -
+ ts->time_pressed[i].tv_sec);
+ }
+
+ ts->coord[i].mcount = 0;
+ ts->coord[i].palm_count = 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)
+{
+ int i;
+
+ mutex_lock(&ts->eventlock);
+
+ for (i = 0; i < MAX_SUPPORT_TOUCH_COUNT; i++) {
+ input_mt_slot(ts->input_dev, i);
+ 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)) {
+
+ ts->coord[i].action = SEC_TS_COORDINATE_ACTION_RELEASE;
+ input_info(true, &ts->client->dev,
+ "%s: [RA] tID:%d mc: %d tc:%d, v:%02X%02X, cal:%X(%X|%X), id(%d,%d), p:%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->cal_count,
+ ts->tspid_val, ts->tspicid_val,
+ ts->coord[i].palm_count);
+
+ do_gettimeofday(&ts->time_released[i]);
+
+ if (ts->time_longest <
+ (ts->time_released[i].tv_sec -
+ ts->time_pressed[i].tv_sec))
+ ts->time_longest =
+ (ts->time_released[i].tv_sec -
+ ts->time_pressed[i].tv_sec);
+ }
+
+ ts->coord[i].mcount = 0;
+ ts->coord[i].palm_count = 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);
+
+ 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);
+
+ if (ts->input_dev_touch->disabled) {
+ input_err(true, &ts->client->dev,
+ "%s: call input_close\n", __func__);
+
+ sec_ts_input_close(ts->input_dev);
+
+ if ((ts->lowpower_mode & SEC_TS_MODE_CUSTOMLIB_AOD) &&
+ ts->use_customlib) {
+ 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;
+ }
+
+ 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__);
+
+ 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__);
+ enable_irq(ts->client->irq);
+ }
+ }
+ ts->reset_is_on_going = 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);
+}
+
+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 int sec_ts_remove(struct i2c_client *client)
+#else
+static int 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;
+
+ input_info(true, &ts->client->dev, "%s\n", __func__);
+
+ if (ts_dup == NULL || ts->probe_done == false)
+ return 0;
+
+ /* 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);
+ drm_panel_notifier_unregister(pdata->panel, &ts->notifier);
+
+ cancel_work_sync(&ts->suspend_work);
+ cancel_work_sync(&ts->resume_work);
+ cancel_work_sync(&ts->charger_work);
+ destroy_workqueue(ts->event_wq);
+
+#ifdef SEC_TS_FW_UPDATE_ON_PROBE
+ cancel_work_sync(&ts->fw_update_work);
+#else
+ cancel_delayed_work_sync(&ts->fw_update_work);
+ destroy_workqueue(ts->fw_update_wq);
+#endif
+
+ 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_HEATMAP)
+ heatmap_remove(&ts->v4l2);
+#endif
+
+ pm_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)
+ tbn_cleanup(ts->tbn);
+#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);
+#endif
+ kfree(ts->gainTable);
+ kfree(ts->pFrame);
+ kfree(ts);
+ return 0;
+}
+
+#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_err(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);
+
+ 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__);
+ 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\n", __func__);
+
+ mutex_lock(&ts->device_mutex);
+
+ reinit_completion(&ts->bus_resumed);
+
+ if (ts->power_status == SEC_TS_STATE_SUSPEND) {
+ input_err(true, &ts->client->dev, "%s: already suspended.\n",
+ __func__);
+ mutex_unlock(&ts->device_mutex);
+ return;
+ }
+
+ pm_stay_awake(&ts->client->dev);
+
+ /* 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)
+ tbn_release_bus(ts->tbn);
+#endif
+ pm_relax(&ts->client->dev);
+ mutex_unlock(&ts->device_mutex);
+}
+
+static void sec_ts_resume_work(struct work_struct *work)
+{
+ struct sec_ts_data *ts = container_of(work, struct sec_ts_data,
+ resume_work);
+ int ret = 0;
+
+ input_info(true, &ts->client->dev, "%s\n", __func__);
+
+ mutex_lock(&ts->device_mutex);
+
+#if IS_ENABLED(CONFIG_TOUCHSCREEN_TBN)
+ if (ts->tbn)
+ tbn_request_bus(ts->tbn);
+#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 = sec_ts_system_reset(ts);
+ if (ret < 0)
+ input_err(true, &ts->client->dev,
+ "%s: reset 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
+
+ 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__);
+ }
+
+ /* 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);
+ queue_work(ts->event_wq, &ts->charger_work);
+
+ /* 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__);
+
+ enable_irq(ts->client->irq);
+
+ complete_all(&ts->bus_resumed);
+
+ mutex_unlock(&ts->device_mutex);
+}
+
+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;
+
+ /* usb case */
+ 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 */
+ 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");
+
+ if (usb_present == ts->usb_present &&
+ wlc_online == ts->wlc_online &&
+ ts->keep_wlc_mode == false)
+ return;
+
+ /* keep wlc mode if usb plug in w/ wlc off case */
+ if (ts->keep_wlc_mode) {
+ input_info(true, &ts->client->dev,
+ "keep wlc mode after usb plug in during wlc online");
+ charger_mode = SEC_TS_BIT_CHARGER_MODE_WIRELESS_CHARGER;
+ }
+
+ input_info(true, &ts->client->dev,
+ "%s: keep_wlc_mode %d, USB(%d->%d), WLC(%d->%d), charger_mode(%#x->%#x)",
+ __func__,
+ ts->keep_wlc_mode,
+ 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->keep_wlc_mode = false;
+}
+
+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_info(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;
+}
+
+static int sec_ts_screen_state_chg_callback(struct notifier_block *nb,
+ unsigned long val, void *data)
+{
+ struct sec_ts_data *ts = container_of(nb, struct sec_ts_data,
+ notifier);
+ struct drm_panel_notifier *evdata = (struct drm_panel_notifier *)data;
+ unsigned int blank;
+
+ input_dbg(true, &ts->client->dev, "%s: enter.\n", __func__);
+
+ if (val != DRM_PANEL_EVENT_BLANK && val != DRM_PANEL_EARLY_EVENT_BLANK)
+ return NOTIFY_DONE;
+
+ if (!ts || !evdata || !evdata->data) {
+ input_err(true, &ts->client->dev,
+ "%s: Bad screen state change notifier call.\n",
+ __func__);
+ return NOTIFY_DONE;
+ }
+
+ blank = *((unsigned int *)evdata->data);
+ switch (blank) {
+ case DRM_PANEL_BLANK_POWERDOWN:
+ case DRM_PANEL_BLANK_LP:
+ if (val == DRM_PANEL_EARLY_EVENT_BLANK) {
+ input_dbg(true, &ts->client->dev,
+ "%s: DRM_PANEL_BLANK_POWERDOWN.\n", __func__);
+ sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SCREEN_ON, false);
+ }
+ break;
+ case DRM_PANEL_BLANK_UNBLANK:
+ if (val == DRM_PANEL_EVENT_BLANK) {
+ input_dbg(true, &ts->client->dev,
+ "%s: DRM_PANEL_BLANK_UNBLANK.\n", __func__);
+ sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SCREEN_ON, true);
+ }
+ break;
+ }
+
+ return NOTIFY_OK;
+}
+
+static struct notifier_block sec_ts_screen_nb = {
+ .notifier_call = sec_ts_screen_state_chg_callback,
+};
+
+/*
+ * power supply callback
+ */
+static int sec_ts_psy_cb(struct notifier_block *nb,
+ unsigned long val, void *data)
+{
+ u64 debounce = 500;
+ 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->wireless_psy == NULL ||
+ 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_timestamp = ktime_get();
+ if (ts->wlc_online) {
+ input_dbg(true, &ts->client->dev,
+ "%s: ignore this usb_psy changed during wlc_online!",
+ __func__);
+ return NOTIFY_OK;
+ }
+ }
+
+ if (ts->wireless_psy == data) {
+ /* keep wlc mode after usb plug in during wlc online */
+ if (ts->wlc_online == true &&
+ ts->usb_present == false &&
+ ktime_before(ktime_get(),
+ ktime_add_ms(ts->usb_changed_timestamp, debounce)))
+ ts->keep_wlc_mode = true;
+ }
+
+ 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,
+};
+
+#ifdef CONFIG_OF
+static const struct of_device_id sec_ts_match_table[] = {
+ { .compatible = "sec,sec_ts",},
+ { },
+};
+#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
+ pr_err("%s %s\n", SECLOG, __func__);
+
+#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..4ebae8b
--- /dev/null
+++ b/sec_ts.h
@@ -0,0 +1,1162 @@
+/* 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 <linux/input/heatmap.h>
+#endif
+#include <linux/input/mt.h>
+#include "sec_cmd.h"
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <drm/drm_panel.h>
+#include <linux/of_gpio.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 <linux/input/touch_bus_negotiator.h>
+#endif
+
+#define SEC_TS_NAME "sec_ts"
+#define SEC_TS_DEVICE_NAME "SEC_TS"
+
+#undef SEC_TS_DEBUG_IO
+#define USE_OPEN_CLOSE
+#undef USE_RESET_DURING_POWER_ON
+#undef USE_RESET_EXIT_LPM
+#undef USE_POR_AFTER_I2C_RETRY
+#undef USER_OPEN_DWORK
+#undef USE_PRESSURE_SENSOR //TODO: check this
+#undef PAT_CONTROL //TODO: check this
+
+#if defined(USE_RESET_DURING_POWER_ON) ||\
+ defined(USE_POR_AFTER_I2C_RETRY) || defined(USE_RESET_EXIT_LPM)
+#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_UMS_FW "/sdcard/Firmware/TSP/lsi.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 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
+};
+
+enum {
+ SEC_TS_ERR_NA = 0,
+ SEC_TS_ERR_INIT,
+ SEC_TS_ERR_ALLOC_FRAME,
+ 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 100
+
+#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
+};
+
+/* 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;
+#endif
+
+#define TEST_MODE_MIN_MAX false
+#define TEST_MODE_ALL_NODE true
+#define TEST_MODE_READ_FRAME false
+#define TEST_MODE_READ_CHANNEL true
+
+/* factory test mode */
+struct sec_ts_test_mode {
+ u8 type;
+ short min[REGION_TYPE_COUNT];
+ short max[REGION_TYPE_COUNT];
+ bool allnode;
+ bool 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_NOISE 0x64
+#define SEC_TS_EVENT_STATUS_ID_WLC 0x66
+#define SEC_TS_EVENT_STATUS_ID_GRIP 0x69
+#define SEC_TS_EVENT_STATUS_ID_PALM 0x70
+
+/* 8 byte */
+struct sec_ts_event_status {
+ 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;
+
+/* 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;
+
+/* 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;
+ u8 major;
+ u8 minor;
+ bool palm;
+ int palm_count;
+ u8 left_event;
+ bool grip;
+};
+
+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
+ **/
+
+ struct timeval time_pressed[MAX_SUPPORT_TOUCH_COUNT +
+ MAX_SUPPORT_HOVER_COUNT];
+ struct timeval time_released[MAX_SUPPORT_TOUCH_COUNT +
+ MAX_SUPPORT_HOVER_COUNT];
+ long time_longest;
+
+ 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;
+
+ int touch_count;
+ 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 notifier_block notifier;
+
+ 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 frame_type;
+#if IS_ENABLED(CONFIG_TOUCHSCREEN_HEATMAP)
+ struct v4l2_heatmap v4l2;
+ strength_t *heatmap_buff;
+#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
+ struct work_struct charger_work; /* charger work */
+ 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;
+ short *pFrame;
+ u8 *gainTable;
+
+ 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 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 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 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
+ int temp;
+
+ 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)
+ struct tbn_context *tbn;
+#endif
+
+ struct power_supply *wireless_psy;
+ struct power_supply *usb_psy;
+ struct notifier_block psy_nb;
+ bool wlc_online;
+ bool usb_present;
+ bool keep_wlc_mode;
+ ktime_t usb_changed_timestamp;
+
+ 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 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;
+#ifdef PAT_CONTROL
+ int pat_function;
+ int afe_base;
+#endif
+ const char *firmware_name;
+ const char *model_name;
+ const char *project_name;
+ const char *regulator_dvdd;
+ const char *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 tsp_vsync;
+ 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;
+};
+
+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);
+int sec_ts_sw_reset(struct sec_ts_data *ts);
+int sec_ts_system_reset(struct sec_ts_data *ts);
+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);
+
+#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..4d0eecf
--- /dev/null
+++ b/sec_ts_fn.c
@@ -0,0 +1,8058 @@
+/* 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"
+#include "sec_ts_fac_spec.h"
+
+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_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
+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_coordinate_report(void *device_data);
+static void enable_gain_limit(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 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("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
+ {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_coordinate_report", enable_coordinate_report),},
+ {SEC_CMD("enable_gain_limit", enable_gain_limit),},
+ {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("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;
+ u8 ret = 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)
+ 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;
+ u8 ret = 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)
+ 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;
+ u8 ret = 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)
+ 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;
+ u8 ret = 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)
+ 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;
+ u8 ret = 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)
+ 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->time_longest = 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: %ld\n", __func__,
+ ts->time_longest);
+
+ return snprintf(buf, SEC_CMD_BUF_SIZE, "%ld", ts->time_longest);
+}
+
+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
+}
+
+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: 0x%02X\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: 0x%02X, 0x%02X, 0x%02X, 0x%02X\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: 0x%02X, 0x%02X\n", data[0], data[1]);
+
+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_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_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);
+ sec_ts_delay(20);
+
+ ret = ts->sec_ts_write(ts, SEC_TS_CMD_CHG_SYSMODE, tBuff,
+ sizeof(tBuff));
+ 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);
+ sec_ts_delay(20);
+
+ return ret;
+}
+
+/* sec_ts_cm_spec_over_check : apply gap calculation with ts->pFrame 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;
+
+ input_info(true, &ts->client->dev, "%s\n", __func__);
+
+ /* Get x-direction cm gap */
+ if (!gap_dir) {
+ input_info(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->pFrame[pos1];
+ dpos2 = ts->pFrame[pos2];
+
+ if (dpos1 > dpos2)
+ gapx = 100 - (dpos2 * 100 / dpos1);
+ else
+ gapx = 100 - (dpos1 * 100 / dpos2);
+
+ gap[pos1] = gapx;
+
+ if (gapx > cm_gap[i][j])
+ specover_count++;
+ }
+ }
+ }
+
+ /* get y-direction cm gap */
+ else {
+ input_info(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->pFrame[pos1];
+ dpos2 = ts->pFrame[pos2];
+
+ if (dpos1 > dpos2)
+ gapy = 100 - (dpos2 * 100 / dpos1);
+ else
+ gapy = 100 - (dpos1 * 100 / dpos2);
+
+ gap[pos1] = gapy;
+
+ if (gapy > cm_gap[i][j])
+ specover_count++;
+ }
+ }
+ }
+
+ input_info(true, &ts->client->dev, "%s: Gap NG for %d node(s)\n",
+ gap_dir == 0 ? "gapX" : "gapY", specover_count);
+
+ return specover_count;
+}
+
+static int sec_ts_cs_spec_over_check(struct sec_ts_data *ts, short *gap)
+{
+ int i;
+ int specover_count = 0;
+ short dTmp;
+
+ for (i = 0; i < ts->tx_count - 1; i++) {
+ dTmp = ts->pFrame[i] - ts->pFrame[i + 1];
+ if (dTmp < 0)
+ dTmp *= -1;
+
+ gap[i] = dTmp;
+
+ if (dTmp > cs_tx_gap)
+ specover_count++;
+ }
+
+ for (i = ts->tx_count; i < ts->tx_count + ts->rx_count - 1; i++) {
+ dTmp = ts->pFrame[i] - ts->pFrame[i + 1];
+ if (dTmp < 0)
+ dTmp *= -1;
+
+ gap[i] = dTmp;
+
+ if (dTmp > cs_rx_gap)
+ specover_count++;
+ }
+
+ input_info(true, &ts->client->dev, "%s: Gap NG for %d node(s)\n",
+ __func__, specover_count);
+
+ return specover_count;
+}
+
+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;
+}
+
+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 dTmp = 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->frame_type, 1);
+ if (ret < 0) {
+ input_err(true, &ts->client->dev,
+ "%s: read rawdata type failed\n",
+ __func__);
+ goto ErrorExit;
+ }
+
+ if (ts->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->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];
+ }
+
+ /* spec check */
+ if (*spec_check == SPEC_CHECK) {
+ int specover_count = 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;
+ }
+ }
+
+ 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->frame_type = mode;
+
+ErrorExit:
+ kfree(pRead);
+
+ return ret;
+}
+
+static void sec_ts_print_channel(struct sec_ts_data *ts)
+{
+ 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",
+ ts->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);
+
+ 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;
+ }
+
+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;
+}
+
+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_read_raw_data(struct sec_ts_data *ts,
+ struct sec_cmd_data *sec, struct sec_ts_test_mode *mode)
+{
+ int ii, jj;
+ 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)
+ ret = sec_ts_read_channel(ts, mode->type, mode->min,
+ mode->max, &mode->spec_check);
+ else
+ ret = sec_ts_read_frame(ts, mode->type, mode->min,
+ mode->max, &mode->spec_check);
+ 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) {
+ if (mode->spec_check == SPEC_PASS) {
+ buff_len += scnprintf(buff + buff_len,
+ buff_size - buff_len,
+ "OK %d %d",
+ ts->rx_count, ts->tx_count);
+ } else if (mode->spec_check == SPEC_FAIL) {
+ buff_len += scnprintf(buff + buff_len,
+ buff_size - buff_len,
+ "NG %d %d",
+ ts->rx_count, ts->tx_count);
+ }
+ 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]);
+ }
+ }
+ } else {
+ 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");
+ }
+ }
+ }
+ } else {
+ buff_len += scnprintf(buff + buff_len, buff_size - buff_len,
+ "%3d,%3d", mode->min[0], mode->max[0]);
+ }
+
+ 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;
+}
+
+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;
+}
+
+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;
+ mode.spec_check = SPEC_CHECK;
+
+ 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;
+ mode.spec_check = SPEC_CHECK;
+
+ sec_ts_read_raw_data(ts, sec, &mode);
+
+ 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;
+ int i;
+ short *gap_x, *gap_y;
+ short dTmp;
+ char *buff;
+ char temp[SEC_CMD_STR_LEN] = { 0 };
+ 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;
+
+ if (!sec)
+ return;
+
+ 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) {
+ snprintf(temp, sizeof(temp), "FAIL");
+ sec->cmd_state = SEC_CMD_STATUS_FAIL;
+ sec_cmd_set_cmd_result(sec, temp, sizeof(temp));
+ goto ErrorAlloc;
+ }
+
+ mode.type = TYPE_OFFSET_DATA_SDC;
+ mode.allnode = TEST_MODE_ALL_NODE;
+ mode.spec_check = SPEC_NO_CHECK;
+
+ 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);
+
+ if (0 == (ret_x + ret_y)) {
+ strlcat(buff, "OK", buff_size);
+ sec->cmd_state = SEC_CMD_STATUS_OK;
+ } else {
+ strlcat(buff, "NG", buff_size);
+ sec->cmd_state = SEC_CMD_STATUS_FAIL;
+ }
+ strlcat(buff, "\n", buff_size);
+ for (i = 0; i < (ts->tx_count * ts->rx_count); i++) {
+ dTmp = (gap_x[i] > gap_y[i]) ? gap_x[i] : gap_y[i];
+ snprintf(temp, sizeof(temp), "%3d,", dTmp);
+ strlcat(buff, temp, buff_size);
+ if (i % ts->tx_count == (ts->tx_count - 1))
+ strlcat(buff, "\n", buff_size);
+ memset(temp, 0x00, sizeof(temp));
+ }
+ strlcat(buff, "\n", 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]);
+ }
+ }
+ }
+
+ 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;
+ }
+
+ 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;
+ mode.spec_check = SPEC_CHECK;
+
+ 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;
+ mode.spec_check = SPEC_CHECK;
+ 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;
+ mode.spec_check = SPEC_CHECK;
+ 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];
+ if (ts->pFrame[i] > noi_mm)
+ result |= 0x4;
+ }
+
+ 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;
+ mode.spec_check = SPEC_CHECK;
+
+ 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;
+ mode.spec_check = SPEC_CHECK;
+
+ 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 i;
+ 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;
+ unsigned int buff_len = 0;
+
+ 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;
+
+ 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);
+
+ if (ret == 0) {
+ buff_len = scnprintf(buff, buff_size, "OK\n ");
+ sec->cmd_state = SEC_CMD_STATUS_OK;
+ } else {
+ buff_len = scnprintf(buff, buff_size, "NG\n ");
+ sec->cmd_state = SEC_CMD_STATUS_FAIL;
+ }
+
+ 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]);
+ }
+
+ sec_cmd_set_cmd_result(sec, buff, buff_len);
+
+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;
+}
+
+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_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 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);
+}
+
+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;
+ char mis_cal_data = 0xF0;
+
+ 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) {
+ buff[0] = 0;
+ rc = ts->sec_ts_write(ts, SEC_TS_CMD_STATEMANAGE_ON,
+ buff, 1);
+ if (rc < 0) {
+ input_err(true, &ts->client->dev,
+ "%s: mis_cal_check error[1] ret: %d\n",
+ __func__, rc);
+ }
+
+ buff[0] = 0x2;
+ buff[1] = 0x2;
+ rc = ts->sec_ts_write(ts, SEC_TS_CMD_CHG_SYSMODE,
+ buff, 2);
+ if (rc < 0) {
+ input_err(true, &ts->client->dev,
+ "%s: mis_cal_check error[2] ret: %d\n",
+ __func__, rc);
+ }
+
+ input_err(true, &ts->client->dev,
+ "%s: try mis Cal. check\n", __func__);
+ rc = ts->sec_ts_write(ts, SEC_TS_CMD_MIS_CAL_CHECK,
+ NULL, 0);
+ if (rc < 0) {
+ input_err(true, &ts->client->dev,
+ "%s: mis_cal_check error[3] 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: fail!, %d\n", __func__, rc);
+ mis_cal_data = 0xF3;
+ } else {
+ input_info(true, &ts->client->dev,
+ "%s: miss cal data : %d\n",
+ __func__, mis_cal_data);
+ }
+
+ buff[0] = 1;
+ rc = ts->sec_ts_write(ts, SEC_TS_CMD_STATEMANAGE_ON,
+ buff, 1);
+ if (rc < 0) {
+ input_err(true, &ts->client->dev,
+ "%s: mis_cal_check error[4] ret: %d\n",
+ __func__, rc);
+ }
+
+ if (mis_cal_data) {
+ 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;
+
+ 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_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;
+ }
+
+ active = sec->cmd_param[0];
+ input_info(true, &ts->client->dev,
+ "%s: %s\n", __func__, active ? "enable" : "disable");
+ if (active)
+ pm_stay_awake(&ts->client->dev);
+ else
+ pm_relax(&ts->client->dev);
+
+ ret = sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_FORCE_ACTIVE, 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->temp = 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)));
+}
+
+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, do touch system reset\n",
+ __func__, sec->cmd_param[0]);
+ sec_ts_system_reset(ts);
+ 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: FTS 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
+ input_info(true, &ts->client->dev,
+ "%s: mutual %d : Max/Min %d,%d ##\n",
+ __func__, sec->cmd_param[0],
+ max[0], min[0]);
+
+ 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
+ input_info(true, &ts->client->dev,
+ "%s: self %d : Max/Min %d,%d ##\n",
+ __func__, sec->cmd_param[0], max[0],
+ min[0]);
+
+ 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;
+ }
+
+ sec_ts_read_gain_table(ts);
+
+ 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
+ input_info(true, &ts->client->dev,
+ "%s: mutual %d : Max/Min %d,%d ##\n",
+ __func__, test_type[i], max[0], min[0]);
+ 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
+ input_info(true, &ts->client->dev,
+ "%s: self %d : Max/Min %d,%d ##\n",
+ __func__, test_type[i], max[0],
+ min[0]);
+ 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;
+ }
+
+ sec_ts_read_gain_table(ts);
+
+ 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..fa1ae58
--- /dev/null
+++ b/sec_ts_fw.c
@@ -0,0 +1,1601 @@
+/* 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,
+ 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_hw_reset(struct sec_ts_data *ts)
+{
+ int reset_gpio = ts->plat_data->reset_gpio;
+
+ input_info(true, &ts->client->dev, "%s\n", __func__);
+
+ 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);
+
+ return 0;
+}
+
+int sec_ts_sw_reset(struct sec_ts_data *ts)
+{
+ int ret;
+
+ input_info(true, &ts->client->dev, "%s\n", __func__);
+
+ ret = ts->sec_ts_write(ts, SEC_TS_CMD_SW_RESET, NULL, 0);
+ if (ret < 0) {
+ input_err(true, &ts->client->dev,
+ "%s: write fail, sw_reset\n", __func__);
+ return 0;
+ }
+
+ /* wait 70 ms at least from bootloader to applicateion mode */
+ sec_ts_delay(70);
+
+ ret = sec_ts_wait_for_ready(ts, SEC_TS_ACK_BOOT_COMPLETE);
+ if (ret < 0) {
+ input_err(true, &ts->client->dev, "%s: time out\n", __func__);
+ return 0;
+ }
+
+ input_info(true, &ts->client->dev, "%s: sw_reset\n", __func__);
+
+ /* 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 0;
+ }
+
+ return ret;
+}
+
+int sec_ts_system_reset(struct sec_ts_data *ts)
+{
+ int ret = -1;
+
+ 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: write fail, sw_reset\n",
+ __func__);
+ else {
+ /* wait 70 ms at least from bootloader to applicateion mode */
+ sec_ts_delay(70);
+ 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
+ /* Normally it should not happen with any retry.
+ * But, if happened, retry less time to wait ack
+ */
+ ret = sec_ts_wait_for_ready_with_count(ts,
+ SEC_TS_ACK_BOOT_COMPLETE, 10);
+
+ if (ret < 0)
+ input_err(true, &ts->client->dev,
+ "%s: sw_reset time out!\n", __func__);
+ else
+ input_info(true,
+ &ts->client->dev, "%s: sw_reset done\n",
+ __func__);
+ }
+
+ if (ret < 0) {
+ if (!gpio_is_valid(ts->plat_data->reset_gpio)) {
+ input_err(true, &ts->client->dev,
+ "%s: reset gpio is unavailable!\n", __func__);
+ goto err_system_reset;
+ }
+
+ 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);
+ if (ret) {
+ input_err(true, &ts->client->dev,
+ "%s: hw_reset failed\n", __func__);
+ goto err_system_reset;
+ }
+
+ 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);
+
+ if (ret < 0) {
+ input_err(true,
+ &ts->client->dev, "%s: hw_reset time out\n",
+ __func__);
+ goto err_system_reset;
+ }
+ input_info(true, &ts->client->dev, "%s: hw_reset done\n",
+ __func__);
+ }
+
+ /* 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__);
+ goto err_system_reset;
+ }
+
+ return 0;
+
+err_system_reset:
+
+ complete_all(&ts->boot_completed);
+ 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);
+ /* need to wait 500us for reading next flash area */
+ udelay(500);
+ 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_err(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_err(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_sw_reset(ts);
+
+#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 */
+ if (ts->plat_data->mis_cal_check) {
+ u8 buff[2];
+ u8 mis_cal_data;
+
+ buff[0] = STATE_MANAGE_OFF;
+ ret = ts->sec_ts_write(ts,
+ SEC_TS_CMD_STATEMANAGE_ON, buff, 1);
+ if (ret < 0)
+ input_err(true, &ts->client->dev,
+ "%s: mis_cal_check error[1] ret: %d\n",
+ __func__, ret);
+
+ buff[0] = TOUCH_SYSTEM_MODE_TOUCH;
+ buff[1] = TOUCH_MODE_STATE_TOUCH;
+ ret = ts->sec_ts_write(ts,
+ SEC_TS_CMD_CHG_SYSMODE, buff, 2);
+ if (ret < 0)
+ input_err(true, &ts->client->dev,
+ "%s: mis_cal_check error[2] ret: %d\n",
+ __func__, ret);
+
+ input_info(true, &ts->client->dev,
+ "%s: mis_cal check\n", __func__);
+ ret = ts->sec_ts_write(ts,
+ SEC_TS_CMD_MIS_CAL_CHECK, NULL, 0);
+ if (ret < 0)
+ input_err(true, &ts->client->dev,
+ "%s: mis_cal_check error[3] ret: %d\n",
+ __func__, ret);
+ sec_ts_delay(200);
+
+ 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);
+ else
+ input_info(true, &ts->client->dev,
+ "%s: mis_cal data : %d\n",
+ __func__, mis_cal_data);
+
+ buff[0] = STATE_MANAGE_ON;
+ ret = ts->sec_ts_write(ts,
+ SEC_TS_CMD_STATEMANAGE_ON, buff, 1);
+ if (ret < 0)
+ input_err(true, &ts->client->dev,
+ "%s: mis_cal_check error[4] ret: %d\n",
+ __func__, ret);
+ }
+
+ /* 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_ums(struct sec_ts_data *ts)
+{
+ fw_header *fw_hd;
+ struct file *fp;
+ mm_segment_t old_fs;
+ long fw_size, nread;
+ int error = 0;
+
+ old_fs = get_fs();
+ set_fs(KERNEL_DS);
+
+ fp = filp_open(SEC_TS_DEFAULT_UMS_FW, O_RDONLY, S_IRUSR);
+ if (IS_ERR(fp)) {
+ input_err(true, ts->dev, "%s: failed to open %s.\n", __func__,
+ SEC_TS_DEFAULT_UMS_FW);
+ error = -ENOENT;
+ goto open_err;
+ }
+
+ fw_size = fp->f_path.dentry->d_inode->i_size;
+
+ if (fw_size > 0) {
+ unsigned char *fw_data;
+
+ fw_data = kzalloc(fw_size, GFP_KERNEL);
+ nread = vfs_read(fp, (char __user *)fw_data,
+ fw_size, &fp->f_pos);
+
+ input_info(true, ts->dev,
+ "%s: start, file path %s, size %ld Bytes\n",
+ __func__, SEC_TS_DEFAULT_UMS_FW, fw_size);
+
+ if (nread != fw_size) {
+ input_err(true, ts->dev,
+ "%s: failed to read firmware file, nread %ld Bytes\n",
+ __func__, nread);
+ error = -EIO;
+ } else {
+ fw_hd = (fw_header *)fw_data;
+ /*
+ * sec_ts_check_firmware_version(ts, fw_data);
+ **/
+ input_info(true, &ts->client->dev,
+ "%s: firmware version %08X\n",
+ __func__, fw_hd->fw_ver);
+ input_info(true, &ts->client->dev,
+ "%s: parameter version %08X\n",
+ __func__, fw_hd->para_ver);
+
+ if (ts->client->irq)
+ disable_irq(ts->client->irq);
+ /* use virtual pat_control - magic cal 1 */
+ if (sec_ts_firmware_update(ts, fw_data, fw_size,
+ 0, 1, 0) < 0)
+ goto done;
+
+ sec_ts_save_version_of_ic(ts);
+ }
+
+ if (error < 0)
+ input_err(true, ts->dev, "%s: failed update firmware\n",
+ __func__);
+
+done:
+ if (ts->client->irq)
+ enable_irq(ts->client->irq);
+ kfree(fw_data);
+ }
+
+ filp_close(fp, NULL);
+
+open_err:
+ set_fs(old_fs);
+ 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 : [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 UMS:
+ ret = sec_ts_load_fw_from_ums(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..d4a740b
--- /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
+}
+