aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/input/touchscreen/mms152.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/input/touchscreen/mms152.c')
-rw-r--r--drivers/input/touchscreen/mms152.c2279
1 files changed, 2279 insertions, 0 deletions
diff --git a/drivers/input/touchscreen/mms152.c b/drivers/input/touchscreen/mms152.c
new file mode 100644
index 0000000..f3c75b0
--- /dev/null
+++ b/drivers/input/touchscreen/mms152.c
@@ -0,0 +1,2279 @@
+/* drivers/input/touchscreen/mms152.c
+ *
+ * Copyright (C) 2010 Melfas, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/earlysuspend.h>
+#include <linux/hrtimer.h>
+#include <linux/i2c.h>
+#include <linux/input.h>
+#include <linux/input/mt.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/mms152.h>
+#include <linux/gpio.h>
+#include <mach/cpufreq.h>
+
+/* firmware version start */
+#define HW_VERSION_EMPTY 0x00
+
+#define GFS_HW_BASE_VER 0x03
+#define GFS_SW_BASE_VER 0x08
+
+#define G2M_HW_BASE_VER 0x12
+#define G2M_SW_BASE_VER 0x09
+
+#define GFD_HW_BASE_VER 0x26
+#define GFD_SW_BASE_VER 0x04
+
+#define G2W_HW_BASE_VER 0x32
+#define G2W_SW_BASE_VER 0x01
+
+/* ISP mode Ver */
+#define GFS_HW_VER 0x03
+#define GFS_SW_VER 0x14
+
+#define G2M_HW_VER 0x12
+#define G2M_SW_VER 0x09
+
+#define GFD_HW_VER 0x26
+#define GFD_SW_VER 0x07
+
+#define G2W_HW_VER 0x32
+#define G2W_SW_VER 0x01
+
+/* ISC mode Ver */
+#define CORE_VER 0x20
+
+#define GFS_PRIVATE_VER 0x07
+#define GFS_PUBLIC_VER 0x08
+
+#define G2M_PRIVATE_VER 0x00
+#define G2M_PUBLIC_VER 0x01
+
+#define GFD_PRIVATE_VER 0x04
+#define GFD_PUBLIC_VER 0x05
+
+#define G2W_PRIVATE_VER 0x00
+#define G2W_PUBLIC_VER 0x01
+/* firmware version end */
+
+#define MELFAS_MAX_TOUCH 10
+
+#define TS_MAX_X_COORD 1023
+#define TS_MAX_Y_COORD 599
+#define TS_MAX_Z_TOUCH 255
+#define TS_MAX_W_TOUCH 30
+
+#define TS_READ_TSPCONNECT_ADDR 0x62
+#define TS_READ_VERSION_ADDR 0x63
+#define TS_READ_CORE_VERSION_ADDR 0x66
+#define TS_READ_PRIVATE_VERSION_ADDR 0x67
+#define TS_READ_PUBLIC_VERSION_ADDR 0x68
+#define TS_READ_REGS_LEN 66
+
+#define TS_READ_START_ADDR 0x0F
+#define TS_READ_START_ADDR2 0x10
+
+#define TS_WRITE_REGS_LEN 16
+#define TS_THRESHOLD 0x70
+/* #define TSP_FACTORY_TEST */
+#define ENABLE_NOISE_TEST_MODE
+#define TS_TA_STAT_ADDR 0x60
+/* #define DEBUG_LOW_DATA */
+
+#define I2C_RETRY_CNT 50
+#define P2_MAX_I2C_FAIL 50
+#define P2_MAX_INFO_READ_FAIL 3
+
+#define SET_DOWNLOAD_BY_GPIO 1
+
+#define PRESS_KEY 1
+#define RELEASE_KEY 0
+
+#define SHOW_COORD 0
+#define DEBUG_PRINT 0
+#define DEBUG_MODE
+
+#define TOUCH_BOOSTER 1
+#define SEC_DVFS_LOCK_TIMEOUT 3
+
+#define X_LINE 20
+#define Y_LINE 31
+#define TSP_CHIP_VENDER_NAME "MELFAS,MMS152"
+
+enum {
+ TSP_STATE_RELEASE = 0,
+ TSP_STATE_PRESS,
+ TSP_STATE_MOVE,
+};
+
+#if SET_DOWNLOAD_BY_GPIO
+#include "mms152_download.h"
+#endif
+
+struct melfas_ts_data {
+ uint16_t addr;
+ struct i2c_client *client;
+ struct input_dev *input_dev;
+ struct ts_platform_data *pdata;
+ struct work_struct work;
+ struct tsp_callbacks cb;
+ struct mutex m_lock;
+#if TOUCH_BOOSTER
+ struct delayed_work dvfs_work;
+ bool dvfs_lock_status;
+ int cpufreq_level;
+#endif
+ u8 finger_state[MELFAS_MAX_TOUCH];
+ uint32_t flags;
+ bool charging_status;
+ bool tsp_status;
+ int (*power)(int on);
+ struct early_suspend early_suspend;
+ void (*power_on)(void);
+ void (*power_off)(void);
+ void (*register_cb)(void *);
+ void (*read_ta_status)(bool *);
+ void (*set_touch_i2c)(void);
+ void (*set_touch_i2c_to_gpio)(void);
+ int touch_id;
+};
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+static void melfas_ts_early_suspend(struct early_suspend *h);
+static void melfas_ts_late_resume(struct early_suspend *h);
+#endif
+
+static struct multi_touch_info g_Mtouch_info[MELFAS_MAX_TOUCH];
+
+static bool debug_print;
+static int firm_status_data;
+
+#ifdef DEBUG_MODE
+static bool debug_on;
+
+static tCommandInfo_t tCommandInfo[] = {
+ { '?', "Help" },
+ { 'T', "Go to LOGGING mode" },
+ { 'M', "Go to MTSI_1_2_0 mode" },
+ { 'R', "Toggle LOG ([R]awdata)" },
+ { 'F', "Toggle LOG (Re[f]erence)" },
+ { 'I', "Toggle LOG ([I]ntensity)" },
+ { 'G', "Toggle LOG ([G]roup Image)" },
+ { 'D', "Toggle LOG ([D]elay Image)" },
+ { 'P', "Toggle LOG ([P]osition)" },
+ { 'B', "Toggle LOG (De[b]ug)" },
+ { 'V', "Toggle LOG (Debug2)" },
+ { 'L', "Toggle LOG (Profi[l]ing)" },
+ { 'O', "[O]ptimize Delay" },
+ { 'N', "[N]ormalize Intensity" }
+};
+
+static bool vbLogType[LT_LIMIT] = {0, };
+static const char mcLogTypeName[LT_LIMIT][20] = {
+ "LT_DIAGNOSIS_IMG",
+ "LT_RAW_IMG",
+ "LT_REF_IMG",
+ "LT_INTENSITY_IMG",
+ "LT_GROUP_IMG",
+ "LT_DELAY_IMG",
+ "LT_POS",
+ "LT_DEBUG",
+ "LT_DEBUG2",
+ "LT_PROFILING",
+};
+
+static void toggle_log(struct melfas_ts_data *ts, eLogType_t _eLogType);
+static void print_command_list(void);
+static int melfas_i2c_read(struct i2c_client *client, u16 addr,
+ u16 length, u8 *value);
+static void debug_i2c_read(struct i2c_client *client, u16 addr,
+ u8 *value, u16 length)
+{
+ melfas_i2c_read(client, addr, length, value);
+}
+
+static int debug_i2c_write(struct i2c_client *client, u8 *value, u16 length)
+{
+ return i2c_master_send(client, value, length);
+}
+
+static void key_handler(struct melfas_ts_data *ts, char key_val)
+{
+ u8 write_buf[2];
+ int ret = 0;
+ pr_info("[TSP] %s - %c\n", __func__, key_val);
+ switch (key_val) {
+ case '?':
+ case '/':
+ print_command_list();
+ break;
+ case 'T':
+ case 't':
+ write_buf[0] = ADDR_ENTER_LOGGING;
+ write_buf[1] = 1;
+ ret = debug_i2c_write(ts->client, write_buf, 2);
+ debug_on = true;
+ pr_info("result = %d", ret);
+ break;
+ case 'M':
+ case 'm':
+ write_buf[0] = ADDR_CHANGE_PROTOCOL;
+ write_buf[1] = 11;
+ debug_i2c_write(ts->client, write_buf, 2);
+ debug_on = false;
+ break;
+ case 'R':
+ case 'r':
+ toggle_log(ts, LT_RAW_IMG);
+ break;
+ case 'F':
+ case 'f':
+ toggle_log(ts, LT_REF_IMG);
+ break;
+ case 'I':
+ case 'i':
+ toggle_log(ts, LT_INTENSITY_IMG);
+ break;
+ case 'G':
+ case 'g':
+ toggle_log(ts, LT_GROUP_IMG);
+ break;
+ case 'D':
+ case 'd':
+ toggle_log(ts, LT_DELAY_IMG);
+ break;
+ case 'P':
+ case 'p':
+ toggle_log(ts, LT_POS);
+ break;
+ case 'B':
+ case 'b':
+ toggle_log(ts, LT_DEBUG);
+ break;
+ case 'V':
+ case 'v':
+ toggle_log(ts, LT_DEBUG2);
+ break;
+ case 'L':
+ case 'l':
+ toggle_log(ts, LT_PROFILING);
+ break;
+ case 'O':
+ case 'o':
+ pr_info("Enter 'Optimize Delay' mode!!!\n");
+ write_buf[0] = ADDR_CHANGE_OPMODE;
+ write_buf[1] = OM_OPTIMIZE_DELAY;
+ if (!debug_i2c_write(ts->client, write_buf, 2))
+ goto ERROR_HANDLE;
+ break;
+ case 'N':
+ case 'n':
+ pr_info("Enter 'Normalize Intensity' mode!!!\n");
+ write_buf[0] = ADDR_CHANGE_OPMODE;
+ write_buf[1] = OM_NORMALIZE_INTENSITY;
+ if (!debug_i2c_write(ts->client, write_buf, 2))
+ goto ERROR_HANDLE;
+ break;
+ default:
+ ;
+ }
+ return;
+ERROR_HANDLE:
+ pr_info("ERROR!!!\n");
+}
+
+static void print_command_list(void)
+{
+ int i;
+ pr_info("######################################################\n");
+ for (i = 0; i < sizeof(tCommandInfo) / sizeof(tCommandInfo_t); i++)
+ pr_info("[%c]: %s\n", tCommandInfo[i].cCommand,
+ tCommandInfo[i].sDescription);
+ pr_info("######################################################\n");
+}
+
+static void toggle_log(struct melfas_ts_data *ts, eLogType_t _eLogType)
+{
+ u8 write_buf[2];
+ vbLogType[_eLogType] ^= 1;
+ if (vbLogType[_eLogType]) {
+ write_buf[0] = ADDR_LOGTYPE_ON;
+ pr_info("%s ON\n", mcLogTypeName[_eLogType]);
+ } else {
+ write_buf[0] = ADDR_LOGTYPE_OFF;
+ pr_info("%s OFF\n", mcLogTypeName[_eLogType]);
+ }
+ write_buf[1] = _eLogType;
+ debug_i2c_write(ts->client, write_buf, 2);
+}
+
+static void logging_function(struct melfas_ts_data *ts)
+{
+ u8 read_buf[100];
+ u8 read_mode, read_num;
+ int FingerX, FingerY, FingerID;
+ int i;
+ static int past_read_mode = HEADER_NONE;
+ static char *ps;
+ static char s[500];
+
+ debug_i2c_read(ts->client, LOG_READ_ADDR, read_buf, 2);
+
+ read_mode = read_buf[0];
+ read_num = read_buf[1];
+
+ switch (read_mode) {
+ case HEADER_U08:
+ {
+ unsigned char* p = (unsigned char *) &read_buf[2];
+ i2c_master_recv(ts->client, read_buf, read_num + 2);
+ ps = s;
+ s[0] = '\0';
+
+ for (i = 0; i < read_num - 1; i++) {
+ sprintf(ps, "%4d,", p[i]);
+ ps = s + strlen(s);
+ }
+ sprintf(ps, "%4d\n", p[i]);
+ ps = s + strlen(s);
+ printk(KERN_DEBUG "%s", s);
+ break;
+ }
+ case HEADER_S08:
+ {
+ signed char* p = (signed char *) &read_buf[2];
+ i2c_master_recv(ts->client, read_buf, read_num + 2);
+ ps = s;
+ s[0] = '\0';
+
+ for (i = 0; i < read_num - 1; i++) {
+ sprintf(ps, "%4d,", p[i]);
+ ps = s + strlen(s);
+ }
+ sprintf(ps, "%4d\n", p[i]);
+ ps = s + strlen(s);
+ printk(KERN_DEBUG "%s", s);
+ break;
+ }
+ case HEADER_U16:
+ {
+ unsigned short* p = (unsigned short *) &read_buf[2];
+ i2c_master_recv(ts->client, read_buf, read_num * 2 + 2);
+ if (past_read_mode != HEADER_U16_NOCR) {
+ ps = s;
+ s[0] = '\0';
+ }
+
+ for (i = 0; i < read_num - 1; i++) {
+ sprintf(ps, "%5d,", p[i]);
+ ps = s + strlen(s);
+ }
+ sprintf(ps, "%5d\n", p[i]);
+ ps = s + strlen(s);
+ printk(KERN_DEBUG "%s", s);
+ break;
+ }
+ case HEADER_U16_NOCR:
+ {
+ unsigned short* p = (unsigned short *) &read_buf[2];
+ i2c_master_recv(ts->client, read_buf, read_num * 2 + 2);
+
+ if (past_read_mode != HEADER_U16_NOCR) {
+ ps = s;
+ s[0] = '\0';
+ }
+ for (i = 0; i < read_num; i++) {
+ sprintf(ps, "%5d,", p[i]);
+ ps = s + strlen(s);
+ }
+ break;
+ }
+ case HEADER_S16:
+ {
+ signed short* p = (signed short *) &read_buf[2];
+ i2c_master_recv(ts->client, read_buf, read_num * 2 + 2);
+
+ if (past_read_mode != HEADER_S16_NOCR) {
+ ps = s;
+ s[0] = '\0';
+ }
+
+ for (i = 0; i < read_num - 1; i++) {
+ sprintf(ps, "%5d,", p[i]);
+ ps = s + strlen(s);
+ }
+ sprintf(ps, "%5d\n", p[i]);
+ ps = s + strlen(s);
+ printk(KERN_DEBUG "%s", s);
+ break;
+ }
+ case HEADER_S16_NOCR:
+ {
+ signed short* p = (signed short *) &read_buf[2];
+ i2c_master_recv(ts->client, read_buf, read_num * 2 + 2);
+
+ if (past_read_mode != HEADER_S16_NOCR) {
+ ps = s;
+ s[0] = '\0';
+ }
+ for (i = 0; i < read_num; i++) {
+ sprintf(ps, "%5d,", p[i]);
+ ps = s + strlen(s);
+ }
+ break;
+ }
+ case HEADER_U32:
+ {
+ unsigned long* p = (unsigned long *) &read_buf[2];
+ i2c_master_recv(ts->client, read_buf, read_num * 4 + 4);
+
+ if (past_read_mode != HEADER_U32_NOCR) {
+ ps = s;
+ s[0] = '\0';
+ }
+
+ for (i = 0; i < read_num - 1; i++) {
+ sprintf(ps, "%10ld,", p[i]);
+ ps = s + strlen(s);
+ }
+ sprintf(ps, "%10ld\n", p[i]);
+ ps = s + strlen(s);
+ printk(KERN_DEBUG "%s", s);
+ break;
+ }
+ case HEADER_U32_NOCR:
+ {
+ unsigned long* p = (unsigned long *) &read_buf[2];
+ i2c_master_recv(ts->client, read_buf, read_num * 4 + 4);
+
+ if (past_read_mode != HEADER_U32_NOCR) {
+ ps = s;
+ s[0] = '\0';
+ }
+ for (i = 0; i < read_num; i++) {
+ sprintf(ps, "%10ld,", p[i]);
+ ps = s + strlen(s);
+ }
+ break;
+ }
+ case HEADER_S32:
+ {
+ signed long* p = (signed long *) &read_buf[2];
+ i2c_master_recv(ts->client, read_buf, read_num * 4 + 4);
+
+ if (past_read_mode != HEADER_S32_NOCR) {
+ ps = s;
+ s[0] = '\0';
+ }
+
+ for (i = 0; i < read_num - 1; i++) {
+ sprintf(ps, "%10ld,", p[i]);
+ ps = s + strlen(s);
+ }
+ sprintf(ps, "%10ld\n", p[i]);
+ ps = s + strlen(s);
+ printk(KERN_DEBUG "%s", s);
+ break;
+ }
+ case HEADER_S32_NOCR:
+ {
+ signed long* p = (signed long *) &read_buf[2];
+ i2c_master_recv(ts->client, read_buf, read_num * 4 + 4);
+
+ if (past_read_mode != HEADER_S32_NOCR) {
+ ps = s;
+ s[0] = '\0';
+ }
+ for (i = 0; i < read_num; i++) {
+ sprintf(ps, "%10ld,", p[i]);
+ ps = s + strlen(s);
+ }
+ break;
+ }
+ case HEADER_TEXT:
+ {
+ i2c_master_recv(ts->client, read_buf, read_num + 2);
+
+ ps = s;
+ s[0] = '\0';
+
+ for (i = 2; i < read_num + 2; i++) {
+ sprintf(ps, "%c", read_buf[i]);
+ ps = s + strlen(s);
+ }
+ printk(KERN_DEBUG "%s\n", s);
+ break;
+ }
+ case HEADER_FINGER:
+ {
+ i2c_master_recv(ts->client, read_buf, read_num * 4 + 2);
+
+ ps = s;
+ s[0] = '\0';
+ for (i = 2; i < read_num * 4 + 2; i = i + 4) {
+ FingerX = (read_buf[i + 1] & 0x07) << 8 | read_buf[i];
+ FingerY = (read_buf[i + 3] & 0x07) << 8
+ | read_buf[i + 2];
+
+ FingerID = (read_buf[i + 1] & 0xF8) >> 3;
+ sprintf(ps, "%2d (%4d,%4d) | ",
+ FingerID, FingerX, FingerY);
+ ps = s + strlen(s);
+ }
+ printk(KERN_DEBUG "%s\n", s);
+ break;
+ }
+ case HEADER_S12:
+ {
+ signed short* p = (signed short *) &read_buf[2];
+ i2c_master_recv(ts->client, read_buf, read_num * 2 + 2);
+
+ if (past_read_mode != HEADER_S12_NOCR) {
+ ps = s;
+ s[0] = '\0';
+ }
+ for (i = 0; i < read_num; i++) {
+ if (p[i] > 4096 / 2)
+ p[i] -= 4096;
+ }
+
+ for (i = 0; i < read_num - 1; i++) {
+ sprintf(ps, "%5d,", p[i]);
+ ps = s + strlen(s);
+ }
+ sprintf(ps, "%5d\n", p[i]);
+ ps = s + strlen(s);
+ printk(KERN_DEBUG "%s", s);
+ break;
+ }
+ case HEADER_S12_NOCR:
+ {
+ signed short* p = (signed short *) &read_buf[2];
+ i2c_master_recv(ts->client, read_buf, read_num * 2 + 2);
+
+ if (past_read_mode != HEADER_S12_NOCR) {
+ ps = s;
+ s[0] = '\0';
+ }
+ for (i = 0; i < read_num; i++) {
+ if (p[i] > 4096 / 2)
+ p[i] -= 4096;
+ }
+ for (i = 0; i < read_num; i++) {
+ sprintf(ps, "%5d,", p[i]);
+ ps = s + strlen(s);
+ }
+ break;
+ }
+ case HEADER_PRIVATE:
+ {
+ unsigned char* p = (unsigned char *) &read_buf[2];
+ i2c_master_recv(ts->client, read_buf,
+ read_num + 2 + read_num % 2);
+
+ ps = s;
+ s[0] = '\0';
+ sprintf(ps, "################## CUSTOM_PRIVATE LOG: ");
+ ps = s + strlen(s);
+ for (i = 0; i < read_num - 1; i++) {
+ sprintf(ps, "%5d,", p[i]);
+ ps = s + strlen(s);
+ }
+ sprintf(ps, "%5d\n", p[i]);
+ ps = s + strlen(s);
+ printk(KERN_DEBUG "%s", s);
+ break;
+ }
+ default:
+ break;
+ }
+
+ past_read_mode = read_mode;
+}
+#endif /* DEBUG_MODE */
+
+static int melfas_i2c_read(struct i2c_client *client,
+ u16 addr, u16 length, u8 *value)
+{
+ struct i2c_adapter *adapter = client->adapter;
+ struct i2c_msg msg[2];
+ int i;
+
+ msg[0].addr = client->addr;
+ msg[0].flags = 0x00;
+ msg[0].len = 2;
+ msg[0].buf = (u8 *) &addr;
+
+ msg[1].addr = client->addr;
+ msg[1].flags = I2C_M_RD;
+ msg[1].len = length;
+ msg[1].buf = (u8 *) value;
+
+ i = i2c_transfer(adapter, msg, 2);
+ if (i == 2)
+ return 0;
+ else{
+ pr_err("[TSP] melfas_i2c_read error : [%d]", i);
+ return -EIO;
+ }
+
+}
+
+static int melfas_i2c_write(struct i2c_client *client, char *buf, int length)
+{
+ int i;
+ char data[TS_WRITE_REGS_LEN];
+
+ if (length > TS_WRITE_REGS_LEN) {
+ pr_err("[TSP] size error - %s\n", __func__);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < length; i++)
+ data[i] = *buf++;
+
+ i = i2c_master_send(client, (char *)data, length);
+
+ if (i == length)
+ return length;
+ else{
+ pr_err("[TSP] melfas_i2c_write error : [%d]", i);
+ return -EIO;
+ }
+}
+
+static int read_input_info(struct melfas_ts_data *ts,
+ u8 *val, u8 start_addr, int read_length)
+{
+ return melfas_i2c_read(ts->client, start_addr, read_length, val);
+}
+
+static int check_detail_firmware(struct melfas_ts_data *ts, u8 *val)
+{
+ return melfas_i2c_read(ts->client, TS_READ_VERSION_ADDR, 6, val);
+}
+
+static int check_tsp_connect(struct melfas_ts_data *ts, u8 *val)
+{
+ return melfas_i2c_read(ts->client, TS_READ_TSPCONNECT_ADDR, 1, val);
+}
+
+static int firmware_update(struct melfas_ts_data *ts)
+{
+
+ int ret = 0, i = 0;
+ int touch_id = ts->touch_id;
+ uint8_t fw_ver[6] = {0,};
+ uint8_t tsp_connect_stat = 0;
+ uint8_t fw_isc_update = 0x00;
+ bool fw_isp_update = false;
+
+#if SET_DOWNLOAD_BY_GPIO
+
+ msleep(200);
+
+ for (i = 0 ; i < P2_MAX_INFO_READ_FAIL ; i++) {
+ ret = check_tsp_connect(ts, &tsp_connect_stat);
+ if (!ret)
+ break;
+ msleep(100);
+ }
+ if (i == P2_MAX_INFO_READ_FAIL) {
+ pr_err("[TSP] check_tsp_connect check fail! [%d]", ret);
+ fw_isp_update |= true;
+ }
+ pr_info("[TSP] TSP panel is %sconnected [%d]",
+ tsp_connect_stat ? "" : "dis", i);
+
+ if (touch_id == 3)
+ return 0;
+
+ for (i = 0 ; i < P2_MAX_INFO_READ_FAIL ; i++) {
+ ret = check_detail_firmware(ts, fw_ver);
+ if (!ret)
+ break;
+ }
+
+ if (i == P2_MAX_INFO_READ_FAIL) {
+ pr_err("[TSP] check_firmware fail! [%d]", ret);
+ fw_isp_update |= true;
+ } else {
+ pr_info("[TSP] Chk HW:[%x],SW:[%x],Core:[%x],Pri:[%x],Pub:[%x]",
+ fw_ver[0], fw_ver[1], fw_ver[3], fw_ver[4], fw_ver[5]);
+
+ /* basic status for ISP D/L */
+ if (ret > 0 || fw_ver[0] == HW_VERSION_EMPTY) {
+ fw_isp_update |= true;
+ } else if (fw_ver[0]>>4 != touch_id) {
+ if (fw_ver[3] == CORE_VER) {
+ fw_isc_update |= 0x06;
+ pr_info("[TSP] bin & panel dismatch ISC partial update!");
+ } else {
+ fw_isp_update |= true;
+ pr_info("[TSP] bin & panel dismatch ISP Full update!");
+ }
+ } else {
+ if (touch_id == 0) { /* GFF S-mac */
+ if (fw_ver[0] < GFS_HW_BASE_VER ||
+ (fw_ver[0] == GFS_HW_BASE_VER &&
+ fw_ver[1] < GFS_SW_BASE_VER))
+ fw_isp_update |= true;
+ } else if (touch_id == 1) { /* G2 -Morins */
+ if (fw_ver[0] < G2M_HW_BASE_VER ||
+ (fw_ver[0] == G2M_HW_BASE_VER &&
+ fw_ver[1] < G2M_SW_BASE_VER))
+ fw_isp_update |= true;
+ } else if (touch_id == 2) { /* GFF Digitec */
+ if (fw_ver[0] < GFD_HW_BASE_VER ||
+ (fw_ver[0] == GFD_HW_BASE_VER &&
+ fw_ver[1] < GFD_SW_BASE_VER))
+ fw_isp_update |= true;
+ } else if (touch_id == 3) {
+ pr_info("[TSP] touch_id=3 pannel is detached");
+ return 0;
+ }
+ }
+
+ if (!fw_isp_update && system_rev >= 2 && !fw_isc_update) {
+ if (fw_ver[3] < CORE_VER)
+ fw_isc_update |= 0x01;
+
+ if ((touch_id == 0 && fw_ver[4] < GFS_PRIVATE_VER) ||
+ (touch_id == 1
+ && fw_ver[4] < G2M_PRIVATE_VER) ||
+ (touch_id == 2
+ && fw_ver[4] < GFD_PRIVATE_VER) ||
+ (touch_id == 3 && fw_ver[4] < G2W_PRIVATE_VER))
+ fw_isc_update |= 0x02;
+
+ if ((touch_id == 0 && fw_ver[5] < GFS_PUBLIC_VER) ||
+ (touch_id == 1 && fw_ver[5] < G2M_PUBLIC_VER) ||
+ (touch_id == 2 && fw_ver[5] < GFD_PUBLIC_VER) ||
+ (touch_id == 3 && fw_ver[5] < G2W_PUBLIC_VER))
+ fw_isc_update |= 0x04;
+ }
+ }
+
+ if (!fw_isp_update && !fw_isc_update) {
+ pr_info("[TSP] ISC & ISP Download ALL skip ");
+ return 0;
+ } else
+ pr_info("[TSP] ISP D/L mode %s & ISC D/L mode %s [%x]",
+ fw_isp_update ? "ON" : "OFF",
+ fw_isc_update ? "ON" : "OFF", fw_isc_update);
+
+ ts->set_touch_i2c_to_gpio();
+
+ if (fw_isp_update)
+ ret = mcsdl_download_binary_data(touch_id);
+ else if (fw_isc_update) {
+ pr_info("[TSP] fw_isc_update bits = [%x]", fw_isc_update);
+ ret = mms100_ISC_download_binary_data(touch_id, fw_isc_update);
+ if (ret) {
+ pr_info("[TSP] ISC Fail & Try ISP mode D/L[%d]", ret);
+ ret = mcsdl_download_binary_data(touch_id);
+ if (ret)
+ pr_info("[TSP] ISC & ISP D/L Fail [%d]", ret);
+ }
+ }
+
+ ts->set_touch_i2c();
+ msleep(100);
+
+ /* reset chip */
+ ts->power_off();
+ msleep(200);
+ ts->power_on();
+ msleep(100);
+
+ ret = check_detail_firmware(ts, fw_ver);
+ if (ret)
+ pr_err("[TSP] check_firmware fail! [%d]", ret);
+ else
+ pr_info("[TSP] FW HW:[%x],SW:[%x],Core:[%x],Pri:[%x],Pub:[%x]",
+ fw_ver[0], fw_ver[1], fw_ver[3], fw_ver[4], fw_ver[5]);
+
+#endif
+
+ return ret;
+}
+
+#if TOUCH_BOOSTER
+static void free_dvfs_lock(struct work_struct *work)
+{
+
+ struct melfas_ts_data *ts = container_of(work,
+ struct melfas_ts_data, dvfs_work.work);
+
+ mutex_lock(&ts->m_lock);
+ exynos4_busfreq_lock_free(DVFS_LOCK_ID_TSP);
+ exynos_cpufreq_lock_free(DVFS_LOCK_ID_TSP);
+ ts->dvfs_lock_status = false;
+ pr_info("[TSP] DVFS Off!");
+ mutex_unlock(&ts->m_lock);
+}
+
+static void set_dvfs_lock(struct melfas_ts_data *ts, uint32_t on)
+{
+ mutex_lock(&ts->m_lock);
+ if (ts->cpufreq_level <= 0) {
+#ifdef CONFIG_TARGET_LOCALE_P2TMO_TEMP
+ /*dvfs freq is temp modified to resolve dvfs kernel panic*/
+ exynos_cpufreq_get_level(800000, &ts->cpufreq_level);
+#else
+ exynos_cpufreq_get_level(500000, &ts->cpufreq_level);
+#endif
+ }
+ if (on == 0) {
+ if (ts->dvfs_lock_status)
+ schedule_delayed_work(&ts->dvfs_work,
+ SEC_DVFS_LOCK_TIMEOUT * HZ);
+ } else if (on == 1) {
+ cancel_delayed_work(&ts->dvfs_work);
+ if (!ts->dvfs_lock_status) {
+ exynos4_busfreq_lock(DVFS_LOCK_ID_TSP, BUS_L1);
+ exynos_cpufreq_lock(DVFS_LOCK_ID_TSP,
+ ts->cpufreq_level);
+ ts->dvfs_lock_status = true;
+ pr_info("[TSP] DVFS On![%d]", ts->cpufreq_level);
+ }
+ } else if (on == 2) {
+ cancel_delayed_work(&ts->dvfs_work);
+ schedule_work(&ts->dvfs_work.work);
+ }
+ mutex_unlock(&ts->m_lock);
+}
+#endif
+
+static void release_all_fingers(struct melfas_ts_data *ts)
+{
+ int i;
+
+ for (i = 0; i < MELFAS_MAX_TOUCH; i++) {
+ ts->finger_state[i] = TSP_STATE_RELEASE;
+ input_mt_slot(ts->input_dev, i);
+ input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER,
+ false);
+ }
+ input_sync(ts->input_dev);
+
+#if TOUCH_BOOSTER
+ set_dvfs_lock(ts, 2);
+ pr_info("[TSP] release_all_fingers ");
+#endif
+}
+
+static void inform_charger_connection(struct tsp_callbacks *_cb, int mode)
+{
+ struct melfas_ts_data *ts = container_of(_cb,
+ struct melfas_ts_data, cb);
+ char buf[2];
+ buf[0] = TS_TA_STAT_ADDR;
+ buf[1] = !!mode;
+
+ if (ts->charging_status == !!mode) {
+ pr_info("[TSP] %s call but not change status", __func__);
+ } else {
+ ts->charging_status = !!mode;
+
+ pr_info("[TSP] %s : TSP %s & TA %sconnect ", __func__,
+ ts->tsp_status ? "ON" : "OFF",
+ ts->charging_status ? "" : "dis");
+
+ if (ts->tsp_status) {
+ melfas_i2c_write(ts->client, (char *)buf, 2);
+ msleep(150);
+ }
+ }
+}
+
+
+static void reset_tsp(struct melfas_ts_data *ts)
+{
+ int ta_status = ts->charging_status;
+ char buf[2];
+
+ buf[0] = TS_TA_STAT_ADDR;
+ buf[1] = ta_status;
+
+ release_all_fingers(ts);
+
+ ts->power_off();
+ msleep(200);
+ ts->power_on();
+ msleep(200);
+
+ pr_info("[TSP] reset_tsp & TA/USB %sconnect", ta_status ? "" : "dis");
+ melfas_i2c_write(ts->client, (char *)buf, 2);
+ msleep(150);
+
+}
+
+static void melfas_ts_read_input(struct melfas_ts_data *ts)
+{
+ int ret = 0, i;
+ uint8_t buf[TS_READ_REGS_LEN];
+ int touchStatus = 0;
+ int read_num, id, posX, posY, str, width;
+ int press_flag = 0;
+
+#if DEBUG_PRINT
+ pr_err("[TSP] melfas_ts_read_input\n");
+
+ if (ts == NULL)
+ pr_err("[TSP] melfas_ts_read_input : TS NULL\n");
+#endif
+
+#ifdef DEBUG_MODE
+ if (debug_on) {
+ logging_function(ts);
+ return;
+ }
+#endif
+
+ ret = read_input_info(ts, buf, TS_READ_START_ADDR, 1);
+ if (ret < 0) {
+ pr_err("[TSP] Failed to read the touch info\n");
+
+ for (i = 0; i < P2_MAX_I2C_FAIL; i++) {
+ ret = read_input_info(ts, buf, TS_READ_START_ADDR, 1);
+ if (ret >= 0)
+ break;
+ }
+
+ if (i == P2_MAX_I2C_FAIL) { /* ESD Detection - I2c Fail */
+ pr_err("[TSP] Melfas_ESD I2C FAIL\n");
+ reset_tsp(ts);
+ return;
+ }
+ }
+
+ read_num = buf[0];
+#if DEBUG_PRINT
+ pr_info("[TSP]touch count :[%d]", read_num/6);
+#endif
+
+ if (read_num <= 0) {
+ pr_err("[TSP] read_num error [%d]\n", read_num);
+ return;
+ }
+
+ ret = read_input_info(ts, buf, TS_READ_START_ADDR2, read_num);
+ if (ret < 0) {
+ pr_err("[TSP] Failed to read the touch info");
+ for (i = 0; i < P2_MAX_I2C_FAIL; i++) {
+ ret = read_input_info(ts, buf,
+ TS_READ_START_ADDR2, read_num);
+ if (ret >= 0)
+ break;
+ }
+ if (i == P2_MAX_I2C_FAIL) {
+ pr_err("[TSP] Melfas_ESD I2C FAIL\n");
+ reset_tsp(ts);
+ return ;
+ }
+ }
+
+ touchStatus = buf[0] & 0xFF;
+
+ if (touchStatus == 0x0F) {
+ pr_info("[TSP] TSP ESD Detection [%x]", buf[0]);
+ reset_tsp(ts);
+ return ;
+ } else if (touchStatus == 0x1F) {
+ pr_info("[TSP] TSP RF Noise Detection [%x]", buf[0]);
+ return ;
+ }
+
+ for (i = 0; i < read_num; i = i+6) {
+ id = (buf[i] & 0x0F)-1;
+ posX = (u16)(buf[i+1] & 0x0F) << 8 | buf[i+2];
+ posY = (u16)(buf[i+1] & 0xF0) << 4 | buf[i+3];
+ str = buf[i + 4];
+ width = buf[i+5];
+
+ if ((buf[i] & 0x80) == TSP_STATE_RELEASE) {
+ if (ts->finger_state[id] == TSP_STATE_RELEASE) {
+ pr_err("[TSP] abnormal release");
+ continue;
+ }
+ input_mt_slot(ts->input_dev, id);
+ input_mt_report_slot_state(ts->input_dev,
+ MT_TOOL_FINGER, false);
+#if SHOW_COORD
+ pr_info("[TSP] R [%d],([%4d],[%3d]),S:%d W:%d (%d)",
+ id, posX, posY, str, width,
+ ts->finger_state[id]);
+#else
+ pr_info("[TSP] R [%d] (%d)", id, ts->finger_state[id]);
+#endif
+ ts->finger_state[id] = TSP_STATE_RELEASE;
+ } else {
+ input_mt_slot(ts->input_dev, id);
+ input_mt_report_slot_state(ts->input_dev,
+ MT_TOOL_FINGER, true);
+ input_report_abs(ts->input_dev,
+ ABS_MT_POSITION_X, posX);
+ input_report_abs(ts->input_dev,
+ ABS_MT_POSITION_Y, posY);
+ input_report_abs(ts->input_dev,
+ ABS_MT_TOUCH_MAJOR, str);
+ input_report_abs(ts->input_dev,
+ ABS_MT_WIDTH_MAJOR, width);
+
+ if (ts->finger_state[id] == TSP_STATE_RELEASE) {
+#if SHOW_COORD
+ pr_info("[TSP] P [%d],([%4d],[%3d]),S:%d W:%d",
+ id, posX, posY, str, width);
+#else
+ pr_info("[TSP] P [%d]", id);
+#endif
+ ts->finger_state[id] = TSP_STATE_PRESS;
+ } else if (ts->finger_state[id] == TSP_STATE_PRESS)
+ ts->finger_state[id] = TSP_STATE_MOVE;
+ }
+ }
+ input_sync(ts->input_dev);
+
+ for (i = 0 ; i < MELFAS_MAX_TOUCH ; i++) {
+ if (ts->finger_state[i] == TSP_STATE_PRESS
+ || ts->finger_state[i] == TSP_STATE_MOVE) {
+ press_flag = 1;
+ break;
+ }
+ }
+
+#if TOUCH_BOOSTER
+ set_dvfs_lock(ts, press_flag);
+#endif
+}
+
+static irqreturn_t melfas_ts_irq_handler(int irq, void *handle)
+{
+ struct melfas_ts_data *ts = (struct melfas_ts_data *)handle;
+#if DEBUG_PRINT
+ pr_err("[TSP] melfas_ts_irq_handler");
+#endif
+
+ melfas_ts_read_input(ts);
+ return IRQ_HANDLED;
+}
+
+static ssize_t show_firm_version_panel(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct melfas_ts_data *ts = dev_get_drvdata(dev);
+ u8 fw_ver[6] = {0,};
+ int ret;
+
+ ret = check_detail_firmware(ts, fw_ver);
+ if (ret)
+ pr_err("[TSP] show_firm_version_panel fail! [%d]", ret);
+ else
+ pr_info("[TSP] show_firm_version_panel [%x][%x],[%x][%x][%x]",
+ fw_ver[0], fw_ver[1], fw_ver[3], fw_ver[4], fw_ver[5]);
+
+ if (ts->touch_id == 0)
+ return snprintf(buf, PAGE_SIZE,
+ "GFS_%2.2Xx%2.2X\n", fw_ver[0], fw_ver[1]);
+ else if (ts->touch_id == 1)
+ return snprintf(buf, PAGE_SIZE,
+ "G2M_%2.2Xx%2.2X\n", fw_ver[0], fw_ver[1]);
+ else if (ts->touch_id == 2)
+ return snprintf(buf, PAGE_SIZE,
+ "GFD_%2.2Xx%2.2X\n", fw_ver[0], fw_ver[1]);
+ else if (ts->touch_id == 3)
+ return snprintf(buf, PAGE_SIZE,
+ "G2W_%2.2Xx%2.2X\n", fw_ver[0], fw_ver[1]);
+ else
+ return snprintf(buf, PAGE_SIZE,
+ "MEL_%2.2Xx%2.2X\n", fw_ver[0], fw_ver[1]);
+ return 0;
+}
+
+static ssize_t show_firm_version_phone(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct melfas_ts_data *ts = dev_get_drvdata(dev);
+
+ if (ts->touch_id == 0)
+ return snprintf(buf, PAGE_SIZE,
+ "GFS_%2.2Xx%2.2X\n", GFS_HW_VER, GFS_SW_VER);
+ else if (ts->touch_id == 1)
+ return snprintf(buf, PAGE_SIZE,
+ "G2M_%2.2Xx%2.2X\n", G2M_HW_VER, G2M_SW_VER);
+ else if (ts->touch_id == 2)
+ return snprintf(buf, PAGE_SIZE,
+ "GFD_%2.2Xx%2.2X\n", GFD_HW_VER, GFD_SW_VER);
+ else if (ts->touch_id == 3)
+ return snprintf(buf, PAGE_SIZE,
+ "G2W_%2.2Xx%2.2X\n", G2W_HW_VER, G2W_SW_VER);
+ return 0;
+}
+
+static ssize_t show_firm_update_status(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+
+ int count;
+ pr_info("[TSP] Enter firmware_status_show by Factory command\n");
+
+ if (firm_status_data == 1)
+ count = sprintf(buf, "DOWNLOADING\n");
+ else if (firm_status_data == 2)
+ count = sprintf(buf, "PASS\n");
+ else if (firm_status_data == 3)
+ count = sprintf(buf, "FAIL\n");
+ else
+ count = sprintf(buf, "PASS\n");
+
+ return count;
+}
+
+static ssize_t tsp_firm_update(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t count)
+{
+ struct melfas_ts_data *ts = dev_get_drvdata(dev);
+ u8 fw_ver[6] = {0,};
+ int ret = 0;
+
+#if SET_DOWNLOAD_BY_GPIO
+
+ disable_irq(ts->client->irq);
+
+ firm_status_data = 1;
+
+ ts->set_touch_i2c_to_gpio();
+
+ pr_info("[TSP] ADB F/W UPDATE MODE ENTER! :%s", buf);
+ if (*buf == 'F')
+ ret = mcsdl_download_binary_data(ts->touch_id);
+ else if (*buf == '0') {
+ pr_info("[TSP] GFS F/W UPDATE !");
+ ret = mcsdl_download_binary_data(0);
+ } else if (*buf == '1') {
+ pr_info("[TSP] G2M F/W UPDATE !");
+ ret = mcsdl_download_binary_data(1);
+ } else if (*buf == '2') {
+ pr_info("[TSP] GFD F/W UPDATE !");
+ ret = mcsdl_download_binary_data(2);
+ } else if (*buf == '3') {
+ pr_info("[TSP] G2W F/W UPDATE !");
+ ret = mcsdl_download_binary_data(3);
+ } else
+ ret = mcsdl_download_binary_file();
+
+ pr_info("[TSP] ADB F/W UPDATE MODE FROM %s END! %s",
+ (*buf == 'F' ? "BINARY" : "FILE"), (ret ? "fail" : "success"));
+
+ firm_status_data = (ret ? 3 : 2);
+
+ ts->set_touch_i2c();
+
+ reset_tsp(ts);
+
+ enable_irq(ts->client->irq);
+#endif
+
+ ret = check_detail_firmware(ts, fw_ver);
+ if (ret)
+ pr_err("[TSP] check_firmware fail! [%d]", ret);
+ else
+ pr_info("[TSP] FW HW:[%x],SW:[%x],Core:[%x],Pri:[%x],Pub:[%x]",
+ fw_ver[0], fw_ver[1], fw_ver[3], fw_ver[4], fw_ver[5]);
+
+ return count;
+}
+
+static ssize_t tsp_firm_verify(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t count)
+{
+ struct melfas_ts_data *ts = dev_get_drvdata(dev);
+ int ret = 0;
+
+#if SET_DOWNLOAD_BY_GPIO
+
+ disable_irq(ts->client->irq);
+
+ ts->set_touch_i2c_to_gpio();
+
+ pr_info("[TSP] ADB F/W Verify MODE ENTER! :%s", buf);
+ if (*buf == 'F')
+ ret = mcsdl_download_binary_data_verify(ts->touch_id);
+ else if (*buf == '0') {
+ pr_info("[TSP] GFS F/W Verify !");
+ ret = mcsdl_download_binary_data_verify(0);
+ } else if (*buf == '1') {
+ pr_info("[TSP] G2M F/W Verify !");
+ ret = mcsdl_download_binary_data_verify(1);
+ } else if (*buf == '2') {
+ pr_info("[TSP] GFD F/W Verify !");
+ ret = mcsdl_download_binary_data_verify(2);
+ } else if (*buf == '3') {
+ pr_info("[TSP] G2W F/W Verify !");
+ ret = mcsdl_download_binary_data_verify(3);
+ } else
+ pr_info("[TSP] ADB F/W Verify MODE file error");
+
+ pr_info("[TSP] ADB F/W Verify %s", (ret ? "Fail" : "Success"));
+
+ ts->set_touch_i2c();
+
+ reset_tsp(ts);
+
+ enable_irq(ts->client->irq);
+#endif
+ return count;
+}
+
+
+static ssize_t store_debug_mode(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t count)
+{
+ struct melfas_ts_data *ts = dev_get_drvdata(dev);
+ char ch;
+
+ if (sscanf(buf, "%c", &ch) != 1)
+ return -EINVAL;
+
+ key_handler(ts, ch);
+
+ return count;
+}
+
+static ssize_t show_debug_mode(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, debug_on ? "ON\n" : "OFF\n");
+}
+
+static ssize_t store_debug_log(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t count)
+{
+ int i;
+
+ if (sscanf(buf, "%d", &i) != 1)
+ return -EINVAL;
+
+ if (i)
+ debug_print = 1;
+ else
+ debug_print = 0;
+
+ pr_info("[TSP] debug log %s", i ? "ON" : "OFF");
+
+ return count;
+}
+
+static ssize_t show_threshold(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct melfas_ts_data *ts = dev_get_drvdata(dev);
+ u8 threshold;
+ melfas_i2c_read(ts->client, TS_THRESHOLD, 1, &threshold);
+
+ return sprintf(buf, "%d\n", threshold);
+}
+
+
+static DEVICE_ATTR(tsp_threshold, S_IRUGO, show_threshold, NULL);
+static DEVICE_ATTR(tsp_firm_update, S_IWUSR | S_IWGRP,
+ NULL, tsp_firm_update);
+static DEVICE_ATTR(tsp_firm_verify, S_IWUSR | S_IWGRP,
+ NULL, tsp_firm_verify);
+static DEVICE_ATTR(tsp_firm_update_status, S_IRUGO,
+ show_firm_update_status, NULL);
+static DEVICE_ATTR(tsp_firm_version_phone, S_IRUGO,
+ show_firm_version_phone, NULL);
+static DEVICE_ATTR(tsp_firm_version_panel, S_IRUGO,
+ show_firm_version_panel, NULL);
+static DEVICE_ATTR(debug_mode, S_IWUSR|S_IRUGO,
+ show_debug_mode, store_debug_mode);
+static DEVICE_ATTR(debug_log, S_IWUSR|S_IRUGO, NULL, store_debug_log);
+
+
+#ifdef ENABLE_NOISE_TEST_MODE
+static DEVICE_ATTR(set_threshould, S_IRUGO, show_threshold, NULL);
+#else
+static DEVICE_ATTR(threshold, S_IRUGO, show_threshold, NULL);
+#endif
+
+static u16 index_reference;
+static u16 reference_data[X_LINE*Y_LINE] = { 0, };
+static u16 intensity_data[X_LINE*Y_LINE] = { 0, };
+static u16 inspection_data[X_LINE*Y_LINE] = { 0, };
+
+static int check_debug_data(struct melfas_ts_data *ts)
+{
+ u8 write_buffer[6];
+ u8 read_buffer[2];
+ int sensing_line, exciting_line;
+ int gpio = ts->pdata->gpio_int;
+ int count = 0;
+
+ disable_irq(ts->client->irq);
+
+ /* enter the debug mode */
+ write_buffer[0] = 0xA0;
+ write_buffer[1] = 0x1A;
+ write_buffer[2] = 0x0;
+ write_buffer[3] = 0x0;
+ write_buffer[4] = 0x0;
+ write_buffer[5] = 0x01;
+ melfas_i2c_write(ts->client, (char *)write_buffer, 6);
+
+ /* wating for the interrupt*/
+ while (gpio_get_value(gpio)) {
+ printk(".");
+ udelay(100);
+ count++;
+ if (count == 1000) {
+ enable_irq(ts->client->irq);
+ return -1;
+ }
+ }
+
+ if (debug_print)
+ pr_info("[TSP] read dummy\n");
+
+ /* read the dummy data */
+ melfas_i2c_read(ts->client, 0xA8, 2, read_buffer);
+
+ if (debug_print)
+ pr_info("[TSP] read inspenction data\n");
+ write_buffer[5] = 0x02;
+ for (sensing_line = 0; sensing_line < X_LINE; sensing_line++) {
+ for (exciting_line = 0; exciting_line < Y_LINE;
+ exciting_line++) {
+ write_buffer[2] = exciting_line;
+ write_buffer[3] = sensing_line;
+ melfas_i2c_write(ts->client, (char *)write_buffer, 6);
+ melfas_i2c_read(ts->client, 0xA8, 2, read_buffer);
+ reference_data[exciting_line + sensing_line * Y_LINE] =
+ (read_buffer[1] & 0xf) << 8 | read_buffer[0];
+ }
+ }
+
+ reset_tsp(ts);
+ msleep(200);
+ enable_irq(ts->client->irq);
+ return 0;
+}
+
+static ssize_t all_refer_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ int status = 0;
+ int i;
+ struct melfas_ts_data *ts = dev_get_drvdata(dev);
+
+ for (i = 0; i < 3; i++) {
+ if (!check_debug_data(ts)) {
+ status = 0;
+ break;
+ } else {
+ pr_info("[TSP] check_debug_data Error try=%d", i);
+ reset_tsp(ts);
+ msleep(300);
+ status = 1;
+ }
+ }
+
+ if (!status) {
+ for (i = 0; i < X_LINE*Y_LINE; i++) {
+ /* out of range */
+ if (reference_data[i] < 30) {
+ status |= 1;
+ break;
+ }
+
+ if (debug_print) {
+ if (0 == i % Y_LINE)
+ printk("\n");
+ printk(KERN_INFO "%5u ", reference_data[i]);
+ }
+ }
+ } else {
+ pr_info("[TSP] all_refer_show& check_debug_data error[%d]",
+ status);
+ return sprintf(buf, "%u\n", status);
+ }
+
+ pr_info("[TSP] all_refer_show func [%d]", status);
+ return sprintf(buf, "%u\n", status);
+}
+
+static void check_intesity_data(struct melfas_ts_data *ts)
+{
+ u8 write_buffer[6];
+ u8 read_buffer[2];
+ int sensing_line, exciting_line;
+ int gpio = ts->pdata->gpio_int;
+
+ if (0 == reference_data[0]) {
+ disable_irq(ts->client->irq);
+
+ /* enter the debug mode */
+ write_buffer[0] = 0xA0;
+ write_buffer[1] = 0x1A;
+ write_buffer[2] = 0x0;
+ write_buffer[3] = 0x0;
+ write_buffer[4] = 0x0;
+ write_buffer[5] = 0x01;
+ melfas_i2c_write(ts->client, (char *)write_buffer, 6);
+
+ /* wating for the interrupt*/
+ while (gpio_get_value(gpio)) {
+ printk(".");
+ udelay(100);
+ }
+
+ /* read the dummy data */
+ melfas_i2c_read(ts->client, 0xA8, 2, read_buffer);
+
+ if (debug_print)
+ pr_info("[TSP] read the dummy data\n");
+
+ write_buffer[5] = 0x02;
+ for (sensing_line = 0; sensing_line < X_LINE; sensing_line++) {
+ for (exciting_line = 0; exciting_line < Y_LINE;
+ exciting_line++) {
+ write_buffer[2] = exciting_line;
+ write_buffer[3] = sensing_line;
+ melfas_i2c_write(ts->client,
+ (char *)write_buffer, 6);
+ melfas_i2c_read(ts->client, 0xA8, 2,
+ read_buffer);
+ reference_data[exciting_line +
+ sensing_line * Y_LINE] =
+ (read_buffer[1] & 0xf) << 8
+ | read_buffer[0];
+ }
+ }
+ reset_tsp(ts);
+ msleep(100);
+ enable_irq(ts->client->irq);
+ msleep(100);
+ }
+
+ disable_irq(ts->client->irq);
+ release_all_fingers(ts);
+
+ write_buffer[0] = 0xA0;
+ write_buffer[1] = 0x1A;
+ write_buffer[4] = 0x0;
+ write_buffer[5] = 0x04;
+ for (sensing_line = 0; sensing_line < X_LINE; sensing_line++) {
+ for (exciting_line = 0; exciting_line < Y_LINE;
+ exciting_line++) {
+ write_buffer[2] = exciting_line;
+ write_buffer[3] = sensing_line;
+ melfas_i2c_write(ts->client, (char *)write_buffer, 6);
+ melfas_i2c_read(ts->client, 0xA8, 2, read_buffer);
+ intensity_data[exciting_line + sensing_line * Y_LINE] =
+ (read_buffer[1] & 0xf) << 8 | read_buffer[0];
+ }
+ }
+ enable_irq(ts->client->irq);
+}
+
+static ssize_t set_refer0_mode_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ u16 refrence = 0;
+ struct melfas_ts_data *ts = dev_get_drvdata(dev);
+
+ check_intesity_data(ts);
+
+ refrence = reference_data[95];
+ return sprintf(buf, "%u\n", refrence);
+}
+
+static ssize_t set_refer1_mode_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ u16 refrence = 0;
+ refrence = reference_data[529];
+ return sprintf(buf, "%u\n", refrence);
+}
+
+static ssize_t set_refer2_mode_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ u16 refrence = 0;
+ refrence = reference_data[294];
+ return sprintf(buf, "%u\n", refrence);
+}
+
+static ssize_t set_refer3_mode_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ u16 refrence = 0;
+ refrence = reference_data[89];
+ return sprintf(buf, "%u\n", refrence);
+}
+
+static ssize_t set_refer4_mode_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ u16 refrence = 0;
+ refrence = reference_data[554];
+ return sprintf(buf, "%u\n", refrence);
+}
+
+static ssize_t set_intensity0_mode_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ u16 intensity = 0;
+ intensity = intensity_data[95];
+ return sprintf(buf, "%u\n", intensity);
+}
+
+static ssize_t set_intensity1_mode_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ u16 intensity = 0;
+ intensity = intensity_data[529];
+ return sprintf(buf, "%u\n", intensity);
+}
+
+static ssize_t set_intensity2_mode_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ u16 intensity = 0;
+ intensity = intensity_data[294];
+ return sprintf(buf, "%u\n", intensity);
+}
+
+static ssize_t set_intensity3_mode_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ u16 intensity = 0;
+ intensity = intensity_data[89];
+ return sprintf(buf, "%u\n", intensity);
+}
+
+static ssize_t set_intensity4_mode_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ u16 intensity = 0;
+ intensity = intensity_data[554];
+ return sprintf(buf, "%u\n", intensity);
+}
+
+static ssize_t tsp_power_control(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t count)
+{
+ struct melfas_ts_data *ts = dev_get_drvdata(dev);
+
+ int ta_status = ts->charging_status;
+ char writebuf[2];
+
+ writebuf[0] = TS_TA_STAT_ADDR;
+ writebuf[1] = ta_status;
+
+ if (*buf == '0' && ts->tsp_status == true) {
+ ts->tsp_status = false;
+ release_all_fingers(ts);
+ ts->power_off();
+ msleep(200);
+ } else if (*buf == '1' && ts->tsp_status == false) {
+ ts->power_on();
+ msleep(200);
+ melfas_i2c_write(ts->client, (char *)writebuf, 2);
+ msleep(150);
+ ts->tsp_status = true;
+ } else
+ pr_info("[TSP]tsp_power_control bad command!");
+ return count;
+}
+
+static ssize_t show_tsp_info(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "%s\n", TSP_CHIP_VENDER_NAME);
+}
+
+static ssize_t show_tsp_x_line_info(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "%d\n", X_LINE);
+}
+
+static ssize_t show_tsp_y_line_info(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "%d\n", Y_LINE);
+}
+
+static int atoi(const char *str)
+{
+ int result = 0;
+ int count = 0;
+ char count_val = str[count];
+
+ if (str == NULL)
+ return -1;
+ while (str != NULL && count_val >= '0' && count_val <= '9') {
+ result = result * 10 + count_val - '0';
+ ++count;
+ }
+ return result;
+}
+
+static ssize_t set_debug_data1(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t count)
+{
+
+ struct melfas_ts_data *ts = dev_get_drvdata(dev);
+
+ u8 write_buffer[6];
+ u8 read_buffer[2];
+ int sensing_line, exciting_line;
+ int gpio = ts->pdata->gpio_int;
+
+ if (!ts->tsp_status) {
+ pr_info("[TSP] call set_debug_data1 but TSP status OFF!");
+ return count;
+ }
+
+ disable_irq(ts->client->irq);
+
+ /* enter the debug mode */
+ write_buffer[0] = 0xA0;
+ write_buffer[1] = 0x1A;
+ write_buffer[2] = 0x0;
+ write_buffer[3] = 0x0;
+ write_buffer[4] = 0x0;
+ write_buffer[5] = 0x01;
+ melfas_i2c_write(ts->client, (char *)write_buffer, 6);
+
+ /* wating for the interrupt*/
+ while (gpio_get_value(gpio)) {
+ printk(".");
+ udelay(100);
+ }
+
+ /* read the dummy data */
+ melfas_i2c_read(ts->client, 0xA8, 2, read_buffer);
+
+ pr_info("[TSP] read Reference data\n");
+ write_buffer[5] = 0x02;
+ for (sensing_line = 0; sensing_line < X_LINE; sensing_line++) {
+ for (exciting_line = 0; exciting_line < Y_LINE;
+ exciting_line++) {
+ write_buffer[2] = exciting_line;
+ write_buffer[3] = sensing_line;
+ melfas_i2c_write(ts->client, (char *)write_buffer, 6);
+ melfas_i2c_read(ts->client, 0xA8, 2, read_buffer);
+ reference_data[exciting_line + sensing_line * Y_LINE] =
+ (read_buffer[1] & 0xf) << 8 | read_buffer[0];
+ }
+ }
+
+ reset_tsp(ts);
+ msleep(200);
+ enable_irq(ts->client->irq);
+ return count;
+}
+
+static ssize_t set_debug_data2(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t count)
+{
+
+ struct melfas_ts_data *ts = dev_get_drvdata(dev);
+
+ u8 write_buffer[6];
+ u8 read_buffer[2];
+ int sensing_line, exciting_line;
+ int gpio = ts->pdata->gpio_int;
+
+ if (!ts->tsp_status) {
+ pr_info("[TSP] call set_debug_data2 but TSP status OFF!");
+ return count;
+ }
+
+ disable_irq(ts->client->irq);
+
+ /* enter the debug mode */
+ write_buffer[0] = 0xA0;
+ write_buffer[1] = 0x1A;
+ write_buffer[2] = 0x0;
+ write_buffer[3] = 0x0;
+ write_buffer[4] = 0x0;
+ write_buffer[5] = 0x01;
+ melfas_i2c_write(ts->client, (char *)write_buffer, 6);
+
+ /* wating for the interrupt*/
+ while (gpio_get_value(gpio)) {
+ printk(".");
+ udelay(100);
+ }
+
+ /* read the dummy data */
+ melfas_i2c_read(ts->client, 0xA8, 2, read_buffer);
+
+ pr_info("[TSP] read Inspection data\n");
+ write_buffer[5] = 0x03;
+ for (sensing_line = 0; sensing_line < X_LINE; sensing_line++) {
+ for (exciting_line = 0; exciting_line < Y_LINE;
+ exciting_line++) {
+ write_buffer[2] = exciting_line;
+ write_buffer[3] = sensing_line;
+ melfas_i2c_write(ts->client, (char *)write_buffer, 6);
+ melfas_i2c_read(ts->client, 0xA8, 2, read_buffer);
+ inspection_data[exciting_line +
+ sensing_line * Y_LINE] =
+ (read_buffer[1] & 0xf) << 8 | read_buffer[0];
+ }
+ }
+ reset_tsp(ts);
+ msleep(200);
+ enable_irq(ts->client->irq);
+ return count;
+}
+
+static ssize_t set_debug_data3(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t count)
+{
+
+ struct melfas_ts_data *ts = dev_get_drvdata(dev);
+
+ u8 write_buffer[6];
+ u8 read_buffer[2];
+ int sensing_line, exciting_line;
+
+ if (!ts->tsp_status) {
+ pr_info("[TSP] call set_debug_data3 but TSP status OFF!");
+ return count;
+ }
+
+ pr_info("[TSP] read lntensity data\n");
+
+ disable_irq(ts->client->irq);
+
+ /* enter the debug mode */
+ write_buffer[0] = 0xA0;
+ write_buffer[1] = 0x1A;
+ write_buffer[2] = 0x0;
+ write_buffer[3] = 0x0;
+ write_buffer[4] = 0x0;
+ write_buffer[5] = 0x04;
+ for (sensing_line = 0; sensing_line < X_LINE; sensing_line++) {
+ for (exciting_line = 0; exciting_line < Y_LINE;
+ exciting_line++) {
+ write_buffer[2] = exciting_line;
+ write_buffer[3] = sensing_line;
+ melfas_i2c_write(ts->client, (char *)write_buffer, 6);
+ melfas_i2c_read(ts->client, 0xA8, 2, read_buffer);
+ intensity_data[exciting_line + sensing_line * Y_LINE] =
+ (read_buffer[1] & 0xf) << 8 | read_buffer[0];
+ }
+ }
+
+ reset_tsp(ts);
+ msleep(200);
+ enable_irq(ts->client->irq);
+ return count;
+}
+
+
+
+static ssize_t set_index_reference(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t count)
+{
+ index_reference = atoi(buf);
+ if (index_reference < 0 || index_reference >= X_LINE*Y_LINE) {
+ pr_info("[TSP] input bad index_reference value");
+ return -1;
+ } else {
+ pr_info("[TSP]index_reference =%d ", index_reference);
+ return count;
+ }
+}
+static ssize_t show_reference_info(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ int i = 0;
+ if (debug_print) {
+ for (i = 0; i < X_LINE*Y_LINE; i++) {
+ if (0 == i % Y_LINE)
+ printk(KERN_INFO "\n");
+ printk(KERN_INFO "%4u", reference_data[i]);
+ }
+ }
+ return sprintf(buf, "%d\n", reference_data[index_reference]);
+}
+static ssize_t show_inspection_info(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ int i = 0;
+ if (debug_print) {
+ for (i = 0; i < X_LINE*Y_LINE; i++) {
+ if (0 == i % Y_LINE)
+ printk(KERN_INFO "\n");
+ printk(KERN_INFO "%5u", inspection_data[i]);
+ }
+ }
+ return sprintf(buf, "%d\n", inspection_data[index_reference]);
+}
+static ssize_t show_intensity_info(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ int i = 0, max_idx = 0, max_val = 0;
+ if (debug_print) {
+ for (i = 0; i < X_LINE*Y_LINE; i++) {
+ if (max_val < intensity_data[i]) {
+ max_val = intensity_data[i];
+ max_idx = i;
+ }
+ if (0 == i % Y_LINE)
+ printk(KERN_INFO "\n");
+ printk(KERN_INFO "%4u", intensity_data[i]);
+ }
+ pr_info("[TSP] max val=[%d] , index=[%d] ", max_val, max_idx);
+ }
+ return sprintf(buf, "%d\n", intensity_data[index_reference]);
+}
+
+static DEVICE_ATTR(set_all_refer, S_IRUGO, all_refer_show, NULL);
+static DEVICE_ATTR(set_refer0, S_IRUGO, set_refer0_mode_show, NULL);
+static DEVICE_ATTR(set_delta0, S_IRUGO, set_intensity0_mode_show, NULL);
+static DEVICE_ATTR(set_refer1, S_IRUGO, set_refer1_mode_show, NULL);
+static DEVICE_ATTR(set_delta1, S_IRUGO, set_intensity1_mode_show, NULL);
+static DEVICE_ATTR(set_refer2, S_IRUGO, set_refer2_mode_show, NULL);
+static DEVICE_ATTR(set_delta2, S_IRUGO, set_intensity2_mode_show, NULL);
+static DEVICE_ATTR(set_refer3, S_IRUGO, set_refer3_mode_show, NULL);
+static DEVICE_ATTR(set_delta3, S_IRUGO, set_intensity3_mode_show, NULL);
+static DEVICE_ATTR(set_refer4, S_IRUGO, set_refer4_mode_show, NULL);
+static DEVICE_ATTR(set_delta4, S_IRUGO, set_intensity4_mode_show, NULL);
+static DEVICE_ATTR(tsp_info, S_IRUGO, show_tsp_info, NULL);
+static DEVICE_ATTR(tsp_x_line, S_IRUGO, show_tsp_x_line_info, NULL);
+static DEVICE_ATTR(tsp_y_line, S_IRUGO, show_tsp_y_line_info, NULL);
+static DEVICE_ATTR(tsp_power, S_IWUSR | S_IWGRP, NULL, tsp_power_control);
+static DEVICE_ATTR(set_debug_data1, S_IWUSR | S_IWGRP, NULL, set_debug_data1);
+static DEVICE_ATTR(set_debug_data2, S_IWUSR | S_IWGRP, NULL, set_debug_data2);
+static DEVICE_ATTR(set_debug_data3, S_IWUSR | S_IWGRP, NULL, set_debug_data3);
+static DEVICE_ATTR(set_index_ref, S_IWUSR | S_IWGRP,
+ NULL, set_index_reference);
+static DEVICE_ATTR(show_reference_info, S_IRUGO, show_reference_info, NULL);
+static DEVICE_ATTR(show_inspection_info, S_IRUGO, show_inspection_info, NULL);
+static DEVICE_ATTR(show_intensity_info, S_IRUGO, show_intensity_info, NULL);
+
+
+static struct attribute *sec_touch_attributes[] = {
+ &dev_attr_tsp_threshold.attr,
+ &dev_attr_tsp_firm_update.attr,
+ &dev_attr_tsp_firm_verify.attr,
+ &dev_attr_tsp_firm_update_status.attr,
+ &dev_attr_tsp_firm_version_phone.attr,
+ &dev_attr_tsp_firm_version_panel.attr,
+ &dev_attr_debug_mode.attr,
+ &dev_attr_debug_log.attr,
+#ifndef ENABLE_NOISE_TEST_MODE
+ &dev_attr_threshold.attr,
+ &dev_attr_set_all_refer.attr,
+ &dev_attr_set_refer0.attr,
+ &dev_attr_set_delta0.attr,
+ &dev_attr_set_refer1.attr,
+ &dev_attr_set_delta1.attr,
+ &dev_attr_set_refer2.attr,
+ &dev_attr_set_delta2.attr,
+ &dev_attr_set_refer3.attr,
+ &dev_attr_set_delta3.attr,
+ &dev_attr_set_refer4.attr,
+ &dev_attr_set_delta4.attr,
+#endif
+ NULL,
+};
+
+static struct attribute_group sec_touch_attr_group = {
+ .attrs = sec_touch_attributes,
+};
+
+#ifdef ENABLE_NOISE_TEST_MODE
+static struct attribute *sec_touch_facotry_attributes[] = {
+ &dev_attr_set_all_refer.attr,
+ &dev_attr_set_refer0.attr,
+ &dev_attr_set_delta0.attr,
+ &dev_attr_set_refer1.attr,
+ &dev_attr_set_delta1.attr,
+ &dev_attr_set_refer2.attr,
+ &dev_attr_set_delta2.attr,
+ &dev_attr_set_refer3.attr,
+ &dev_attr_set_delta3.attr,
+ &dev_attr_set_refer4.attr,
+ &dev_attr_set_delta4.attr,
+ &dev_attr_set_threshould.attr,
+ &dev_attr_tsp_power.attr,
+ &dev_attr_tsp_info.attr,
+ &dev_attr_tsp_x_line.attr,
+ &dev_attr_tsp_y_line.attr,
+ &dev_attr_set_debug_data1.attr,
+ &dev_attr_set_debug_data2.attr,
+ &dev_attr_set_debug_data3.attr,
+ &dev_attr_set_index_ref.attr,
+ &dev_attr_show_reference_info.attr,
+ &dev_attr_show_inspection_info.attr,
+ &dev_attr_show_intensity_info.attr,
+ NULL,
+};
+
+static struct attribute_group sec_touch_factory_attr_group = {
+ .attrs = sec_touch_facotry_attributes,
+};
+#endif
+
+
+static int melfas_ts_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+
+ struct ts_platform_data *pdata = client->dev.platform_data;
+ struct melfas_ts_data *ts;
+ struct device *tsp_dev;
+
+#ifdef ENABLE_NOISE_TEST_MODE
+ struct device *test_dev;
+#endif
+
+ int ret = 0, i, irq;
+ const char buf;
+
+#if DEBUG_PRINT
+ pr_err("[TSP] kim ms : melfas_ts_probe\n");
+#endif
+
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+ pr_err("[TSP] melfas_ts_probe: need I2C_FUNC_I2C\n");
+ ret = -ENODEV;
+ goto err_check_functionality_failed;
+ }
+
+ ts = kmalloc(sizeof(struct melfas_ts_data), GFP_KERNEL);
+ if (ts == NULL) {
+ pr_err("[TSP] failed to create a state of melfas-ts");
+ ret = -ENOMEM;
+ goto err_alloc_data_failed;
+ }
+
+ ts->pdata = client->dev.platform_data;
+
+ ts->power_on = pdata->power_on;
+ ts->power_off = pdata->power_off;
+ ts->read_ta_status = pdata->read_ta_status;
+ ts->set_touch_i2c = pdata->set_touch_i2c;
+ ts->set_touch_i2c_to_gpio = pdata->set_touch_i2c_to_gpio;
+ ts->touch_id = pdata->gpio_touch_id;
+ ts->tsp_status = true;
+
+ mutex_init(&ts->m_lock);
+
+ ts->cb.inform_charger = inform_charger_connection;
+ if (pdata->register_cb)
+ pdata->register_cb(&ts->cb);
+
+ /* reset chip */
+ gpio_set_value(GPIO_TSP_RST, 0);
+ msleep(200);
+ gpio_set_value(GPIO_TSP_RST, 1);
+ msleep(100);
+
+
+ ts->client = client;
+ i2c_set_clientdata(client, ts);
+ ret = i2c_master_send(ts->client, &buf, 1);
+
+
+#if DEBUG_PRINT
+ pr_err("[TSP] melfas_ts_probe: i2c_master_send() [%d], Add[%d]\n",
+ ret, ts->client->addr);
+#endif
+
+ ret = firmware_update(ts);
+
+ ts->input_dev = input_allocate_device();
+ if (!ts->input_dev) {
+ pr_err("[TSP] melfas_ts_probe: Not enough memory\n");
+ ret = -ENOMEM;
+ goto err_input_dev_alloc_failed;
+ }
+
+ ts->input_dev->name = "sec_touchscreen" ;
+
+ __set_bit(EV_ABS, ts->input_dev->evbit);
+ __set_bit(EV_KEY, ts->input_dev->evbit);
+
+ input_mt_init_slots(ts->input_dev, MELFAS_MAX_TOUCH);
+ input_set_abs_params(ts->input_dev,
+ ABS_MT_POSITION_X, 0, TS_MAX_X_COORD, 0, 0);
+ input_set_abs_params(ts->input_dev,
+ ABS_MT_POSITION_Y, 0, TS_MAX_Y_COORD, 0, 0);
+ input_set_abs_params(ts->input_dev,
+ ABS_MT_TOUCH_MAJOR, 0, TS_MAX_Z_TOUCH, 0, 0);
+ input_set_abs_params(ts->input_dev,
+ ABS_MT_WIDTH_MAJOR, 0, TS_MAX_W_TOUCH, 0, 0);
+
+ __set_bit(MT_TOOL_FINGER, ts->input_dev->keybit);
+ __set_bit(EV_SYN, ts->input_dev->evbit);
+ __set_bit(INPUT_PROP_DIRECT, ts->input_dev->propbit);
+
+
+
+ ret = input_register_device(ts->input_dev);
+ if (ret) {
+ pr_err("[TSP] melfas_ts_probe: Failed to register device\n");
+ ret = -ENOMEM;
+ goto err_input_register_device_failed;
+ }
+
+ if (ts->client->irq) {
+ irq = ts->client->irq;
+
+ ret = request_threaded_irq(irq, NULL, melfas_ts_irq_handler,
+ IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+ ts->client->name, ts);
+ if (ret) {
+ pr_err("[TSP] %s: Can't allocate irq %d, ret %d\n",
+ __func__, irq, ret);
+ ret = -EBUSY;
+ goto err_request_irq;
+ }
+ }
+
+#if TOUCH_BOOSTER
+ INIT_DELAYED_WORK(&ts->dvfs_work, free_dvfs_lock);
+ ts->cpufreq_level = -1;
+ ts->dvfs_lock_status = false;
+#endif
+
+ for (i = 0; i < MELFAS_MAX_TOUCH; i++)
+ ts->finger_state[i] = TSP_STATE_RELEASE;
+
+#if DEBUG_PRINT
+ pr_err("[TSP] melfas_ts_probe: succeed to register input device\n");
+#endif
+
+/* ---------------------- */
+ tsp_dev = device_create(sec_class, NULL, 0, ts, "sec_touchscreen");
+ if (IS_ERR(tsp_dev))
+ pr_err("[TSP] Failed to create device for the sysfs\n");
+
+ ret = sysfs_create_group(&tsp_dev->kobj, &sec_touch_attr_group);
+ if (ret)
+ pr_err("[TSP] Failed to create sysfs group\n");
+/* ----------------------- */
+
+#ifdef ENABLE_NOISE_TEST_MODE
+ test_dev = device_create(sec_class, NULL, 0, ts, "tsp_noise_test");
+ if (IS_ERR(test_dev)) {
+ pr_err("Failed to create device for the factory test\n");
+ ret = -ENODEV;
+ }
+
+ ret = sysfs_create_group(&test_dev->kobj,
+ &sec_touch_factory_attr_group);
+ if (ret)
+ pr_err("Failed to create sysfs group for the factory test\n");
+#endif
+
+
+#if CONFIG_HAS_EARLYSUSPEND
+ ts->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1;
+ ts->early_suspend.suspend = melfas_ts_early_suspend;
+ ts->early_suspend.resume = melfas_ts_late_resume;
+ register_early_suspend(&ts->early_suspend);
+#endif
+
+#if DEBUG_PRINT
+ pr_info("melfas_ts_probe: Start touchscreen. name: %s, irq: %d\n",
+ ts->client->name, ts->client->irq);
+#endif
+ return 0;
+
+err_request_irq:
+ pr_err("[TSP] melfas-ts: err_request_irq failed\n");
+ free_irq(client->irq, ts);
+err_input_register_device_failed:
+ pr_err("[TSP] melfas-ts: err_input_register_device failed\n");
+ input_free_device(ts->input_dev);
+err_input_dev_alloc_failed:
+ pr_err("[TSP] melfas-ts: err_input_dev_alloc failed\n");
+err_alloc_data_failed:
+ pr_err("[TSP] melfas-ts: err_alloc_data failed_\n");
+ kfree(ts);
+err_check_functionality_failed:
+ pr_err("[TSP] melfas-ts: err_check_functionality failed_\n");
+
+ return ret;
+}
+
+static int melfas_ts_remove(struct i2c_client *client)
+{
+ struct melfas_ts_data *ts = i2c_get_clientdata(client);
+
+ unregister_early_suspend(&ts->early_suspend);
+ free_irq(client->irq, ts);
+ input_unregister_device(ts->input_dev);
+ kfree(ts);
+ return 0;
+}
+
+static int melfas_ts_suspend(struct i2c_client *client, pm_message_t mesg)
+{
+ char buf[2];
+ struct melfas_ts_data *ts = i2c_get_clientdata(client);
+ ts->tsp_status = false;
+
+#ifdef DEBUG_MODE
+ if (debug_on) {
+ pr_info("[TSP] Out of debug-mode before suspend ");
+ buf[0] = ADDR_CHANGE_PROTOCOL;
+ buf[1] = 11;
+ debug_i2c_write(ts->client, buf, 2);
+ debug_on = false;
+ msleep(150);
+ }
+#endif
+
+ disable_irq(ts->client->irq);
+ release_all_fingers(ts);
+
+ ts->power_off();
+
+ return 0;
+}
+
+static int melfas_ts_resume(struct i2c_client *client)
+{
+ struct melfas_ts_data *ts = i2c_get_clientdata(client);
+ int ta_status = ts->charging_status;
+ char buf[2];
+
+ ts->power_on();
+ msleep(100);
+
+ if (ta_status) {
+ buf[0] = TS_TA_STAT_ADDR;
+ buf[1] = ta_status;
+ melfas_i2c_write(ts->client, (char *)buf, 2);
+ msleep(150);
+ }
+
+ enable_irq(ts->client->irq);
+ pr_info("[TSP] melfas_ts_resume TA %sconnection",
+ ta_status ? "" : "dis");
+
+ ts->tsp_status = true;
+
+ return 0;
+}
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+static void melfas_ts_early_suspend(struct early_suspend *h)
+{
+ struct melfas_ts_data *ts;
+ ts = container_of(h, struct melfas_ts_data, early_suspend);
+ melfas_ts_suspend(ts->client, PMSG_SUSPEND);
+}
+
+static void melfas_ts_late_resume(struct early_suspend *h)
+{
+ struct melfas_ts_data *ts;
+ ts = container_of(h, struct melfas_ts_data, early_suspend);
+ melfas_ts_resume(ts->client);
+}
+#endif
+
+static const struct i2c_device_id melfas_ts_id[] = {
+ { TS_DEV_NAME, 0 },
+ { }
+};
+
+static struct i2c_driver melfas_ts_driver = {
+ .driver = {
+ .name = TS_DEV_NAME,
+ },
+ .id_table = melfas_ts_id,
+ .probe = melfas_ts_probe,
+ .remove = __devexit_p(melfas_ts_remove),
+#ifndef CONFIG_HAS_EARLYSUSPEND
+ .suspend = melfas_ts_suspend,
+ .resume = melfas_ts_resume,
+#endif
+};
+
+static int __devinit melfas_ts_init(void)
+{
+ return i2c_add_driver(&melfas_ts_driver);
+}
+
+static void __exit melfas_ts_exit(void)
+{
+ i2c_del_driver(&melfas_ts_driver);
+}
+
+MODULE_DESCRIPTION("Driver for Melfas MTSI Touchscreen Controller");
+MODULE_AUTHOR("MinSang, Kim <kimms@melfas.com>");
+MODULE_VERSION("0.1");
+MODULE_LICENSE("GPL");
+
+module_init(melfas_ts_init);
+module_exit(melfas_ts_exit);