input: touchscreen: synaptics_3200: Add Synaptics 3200 driver

HTC kernel version: evitaul-jb-crc-3.4.10-ec474a3

Change-Id: I4acac53e40e4b47f249f631e7b92d9dfe7cb9e79
diff --git a/drivers/input/misc/gpio_input.c b/drivers/input/misc/gpio_input.c
index 6a0c315..f4b9a5a 100644
--- a/drivers/input/misc/gpio_input.c
+++ b/drivers/input/misc/gpio_input.c
@@ -22,6 +22,78 @@
 #include <linux/slab.h>
 #include <linux/wakelock.h>
 
+#ifdef CONFIG_TOUCHSCREEN_SYNAPTICS_3K
+static uint8_t power_key_state;
+static spinlock_t power_key_state_lock;
+
+#define PWRKEY_PRESS_DUE 1*HZ
+#include <linux/module.h>
+static void init_power_key_api(void)
+{
+	spin_lock_init(&power_key_state_lock);
+	power_key_state = 0;
+}
+
+static void setPowerKeyState(uint8_t flag)
+{
+	spin_lock(&power_key_state_lock);
+	power_key_state = flag;
+	spin_unlock(&power_key_state_lock);
+}
+
+uint8_t getPowerKeyState(void)
+{
+	uint8_t value;
+
+	spin_lock(&power_key_state_lock);
+	value = power_key_state;
+	spin_unlock(&power_key_state_lock);
+
+	return value;
+}
+EXPORT_SYMBOL(getPowerKeyState);
+
+static void power_key_state_disable_work_func(struct work_struct *dummy)
+{
+	setPowerKeyState(0);
+	printk(KERN_INFO "[KEY][PWR][STATE]power key pressed outdated\n");
+}
+static DECLARE_DELAYED_WORK(power_key_state_disable_work, power_key_state_disable_work_func);
+
+static void handle_power_key_state(unsigned int code, int value)
+{
+	int ret = 0;
+	if (code == KEY_POWER && value == 1) {
+		printk(KERN_INFO "[PWR][STATE]try to schedule power key pressed due\n");
+		ret = schedule_delayed_work(&power_key_state_disable_work, PWRKEY_PRESS_DUE);
+		if (!ret) {
+			printk(KERN_INFO "[PWR][STATE]Schedule power key pressed due failed, seems already have one, try to cancel...\n");
+			ret = cancel_delayed_work(&power_key_state_disable_work);
+			if (!ret) {
+				setPowerKeyState(1);
+				if (schedule_delayed_work(&power_key_state_disable_work, PWRKEY_PRESS_DUE)) {
+					printk(KERN_INFO "[PWR][STATE]Re-schedule power key pressed due SCCUESS.\n");
+					printk(KERN_INFO "[PWR][STATE] start count for power key pressed due\n");
+					setPowerKeyState(1);
+				} else
+					printk(KERN_INFO "[PWR][STATE]Re-schedule power key pressed due FAILED, reason unknown, give up.\n");
+			} else {
+				printk(KERN_INFO "[PWR][STATE]Cancel scheduled power key due success, now re-schedule.\n");
+				if (schedule_delayed_work(&power_key_state_disable_work, PWRKEY_PRESS_DUE)) {
+					printk(KERN_INFO "[PWR][STATE]Re-schedule power key pressed due SCCUESS.\n");
+					printk(KERN_INFO "[PWR][STATE] start count for power key pressed due\n");
+					setPowerKeyState(1);
+				} else
+					printk(KERN_INFO "[PWR][STATE]Re-schedule power key pressed due FAILED, reason unknown, give up.\n");
+			}
+		} else {
+			printk(KERN_INFO "[PWR][STATE] start count for power key pressed due\n");
+			setPowerKeyState(1);
+		}
+	}
+}
+#endif /* CONFIG_TOUCHSCREEN_SYNAPTICS_3K */
+
 enum {
 	DEBOUNCE_UNSTABLE     = BIT(0),	/* Got irq, while debouncing */
 	DEBOUNCE_PRESSED      = BIT(1),
@@ -130,6 +202,9 @@
 			pr_info("gpio_keys_scan_keys: key %x-%x, %d (%d) "
 				"changed to %d\n", ds->info->type,
 				key_entry->code, i, key_entry->gpio, pressed);
+#ifdef CONFIG_TOUCHSCREEN_SYNAPTICS_3K
+		handle_power_key_state(key_entry->code, pressed);
+#endif
 		input_event(ds->input_devs->dev[key_entry->dev], ds->info->type,
 			    key_entry->code, pressed);
 		sync_needed = true;
@@ -239,6 +314,9 @@
 			}
 		}
 	}
+#ifdef CONFIG_TOUCHSCREEN_SYNAPTICS_3K
+	init_power_key_api();
+#endif
 	return 0;
 
 	for (i = ds->info->keymap_size - 1; i >= 0; i--) {
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index 4a80fa5..388f977 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -1021,3 +1021,9 @@
 	depends on I2C
 	help
 	  Enables support for Cypress CY8C_CS touchkeys.
+
+config TOUCHSCREEN_SYNAPTICS_3K
+	tristate "Synaptics 3K i2c touchscreen"
+	depends on I2C
+	help
+	  This enables support for Synaptics RMI4 over I2C based touchscreens.
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
index f49c48a..ba0e55a 100644
--- a/drivers/input/touchscreen/Makefile
+++ b/drivers/input/touchscreen/Makefile
@@ -88,3 +88,4 @@
 obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE) 	+= synaptics_fw_update.o
 obj-$(CONFIG_TOUCHSCREEN_ATMEL_224E)	+= atmel_224e.o
 obj-$(CONFIG_TOUCHSCREEN_CYPRESS_CS)	+= cy8c_cs.o
+obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_3K)	+= synaptics_3200.o rmi_dev.o
diff --git a/drivers/input/touchscreen/rmi_dev.c b/drivers/input/touchscreen/rmi_dev.c
new file mode 100644
index 0000000..78aface
--- /dev/null
+++ b/drivers/input/touchscreen/rmi_dev.c
@@ -0,0 +1,338 @@
+/*
+ * Copyright (c) 2011 Synaptics Incorporated
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/fs.h>
+#include <linux/delay.h>
+#include <linux/uaccess.h>
+#include <linux/slab.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/syscalls.h>
+#include <linux/i2c.h>
+#include <linux/rmi.h>
+
+#define CHAR_DEVICE_NAME "rmi"
+
+#define REG_ADDR_LIMIT 0xFFFF
+
+static int rmi_char_dev_major_num;
+
+
+
+static loff_t rmi_char_dev_llseek(struct file *filp, loff_t off, int whence)
+{
+	loff_t newpos;
+	struct rmi_char_dev *my_char_dev = filp->private_data;
+
+	if (IS_ERR(my_char_dev)) {
+		pr_err("%s: pointer of char device is invalid", __func__);
+		return -EBADF;
+	}
+
+	mutex_lock(&(my_char_dev->mutex_file_op));
+
+	switch (whence) {
+	case SEEK_SET:
+		newpos = off;
+		break;
+
+	case SEEK_CUR:
+		newpos = filp->f_pos + off;
+		break;
+
+	case SEEK_END:
+		newpos = REG_ADDR_LIMIT + off;
+		break;
+
+	default:		
+		newpos = -EINVAL;
+		goto clean_up;
+	}
+
+	if (newpos < 0 || newpos > REG_ADDR_LIMIT) {
+		dev_err(my_char_dev->phys->dev, "newpos 0x%04x is invalid.\n",
+			(unsigned int)newpos);
+		newpos = -EINVAL;
+		goto clean_up;
+	}
+
+	filp->f_pos = newpos;
+
+clean_up:
+	mutex_unlock(&(my_char_dev->mutex_file_op));
+	return newpos;
+}
+
+static ssize_t rmi_char_dev_read(struct file *filp, char __user *buf,
+		size_t count, loff_t *f_pos)
+{
+	struct rmi_char_dev *my_char_dev = filp->private_data;
+	ssize_t ret_value  = 0;
+	unsigned char tmpbuf[count+1];
+	
+
+	
+	if (count > (REG_ADDR_LIMIT - *f_pos))
+		count = REG_ADDR_LIMIT - *f_pos;
+
+	if (count == 0)
+		return 0;
+
+	if (IS_ERR(my_char_dev)) {
+		pr_err("%s: pointer of char device is invalid", __func__);
+		ret_value = -EBADF;
+		return ret_value;
+	}
+
+	mutex_lock(&(my_char_dev->mutex_file_op));
+
+	
+
+	
+	ret_value = i2c_rmi_read(*f_pos, tmpbuf, count);
+
+
+	if (ret_value < 0)
+		goto clean_up;
+	else
+		*f_pos += ret_value;
+
+	if (copy_to_user(buf, tmpbuf, count))
+		ret_value = -EFAULT;
+
+clean_up:
+
+	mutex_unlock(&(my_char_dev->mutex_file_op));
+
+	return ret_value;
+}
+
+static ssize_t rmi_char_dev_write(struct file *filp, const char __user *buf,
+		size_t count, loff_t *f_pos)
+{
+	struct rmi_char_dev *my_char_dev = filp->private_data;
+	ssize_t ret_value  = 0;
+	unsigned char tmpbuf[count+1];
+	
+
+	
+	if (count > (REG_ADDR_LIMIT - *f_pos))
+		count = REG_ADDR_LIMIT - *f_pos;
+
+	if (count == 0)
+		return 0;
+
+	if (IS_ERR(my_char_dev)) {
+		pr_err("%s: pointer of char device is invalid", __func__);
+		ret_value = -EBADF;
+		return ret_value;
+	}
+
+	if (copy_from_user(tmpbuf, buf, count)) {
+		ret_value = -EFAULT;
+		return ret_value;
+	}
+
+	mutex_lock(&(my_char_dev->mutex_file_op));
+
+	
+
+	
+	ret_value = i2c_rmi_write(*f_pos, tmpbuf, count);
+
+	if (ret_value >= 0)
+		*f_pos += count;
+
+	mutex_unlock(&(my_char_dev->mutex_file_op));
+
+	return ret_value;
+}
+
+static int rmi_char_dev_open(struct inode *inp, struct file *filp)
+{
+	
+	struct rmi_char_dev *my_dev = container_of(inp->i_cdev,
+			struct rmi_char_dev, main_dev);
+	
+	int ret_value = 0;
+
+	filp->private_data = my_dev;
+
+	
+		
+
+	mutex_lock(&(my_dev->mutex_file_op));
+	if (my_dev->ref_count < 1)
+		my_dev->ref_count++;
+	else
+		ret_value = -EACCES;
+
+	mutex_unlock(&(my_dev->mutex_file_op));
+
+	return ret_value;
+}
+
+static int rmi_char_dev_release(struct inode *inp, struct file *filp)
+{
+	struct rmi_char_dev *my_dev = container_of(inp->i_cdev,
+			struct rmi_char_dev, main_dev);
+
+	mutex_lock(&(my_dev->mutex_file_op));
+
+	my_dev->ref_count--;
+	if (my_dev->ref_count < 0)
+		my_dev->ref_count = 0;
+
+	mutex_unlock(&(my_dev->mutex_file_op));
+
+	return 0;
+}
+
+static const struct file_operations rmi_char_dev_fops = {
+	.owner =    THIS_MODULE,
+	.llseek =   rmi_char_dev_llseek,
+	.read =     rmi_char_dev_read,
+	.write =    rmi_char_dev_write,
+	.open =     rmi_char_dev_open,
+	.release =  rmi_char_dev_release,
+};
+
+static void rmi_char_dev_clean_up(struct rmi_char_dev *char_dev,
+			struct class *char_device_class)
+{
+	dev_t devno;
+
+	
+	if (char_dev) {
+		devno = char_dev->main_dev.dev;
+
+		cdev_del(&char_dev->main_dev);
+		kfree(char_dev);
+
+		if (char_device_class) {
+			device_destroy(char_device_class, devno);
+			class_unregister(char_device_class);
+			class_destroy(char_device_class);
+		}
+
+		
+		unregister_chrdev_region(devno, 1);
+		pr_debug("%s: rmi_char_dev is removed\n", __func__);
+	}
+}
+
+static char *rmi_char_devnode(struct device *dev, mode_t *mode)
+{
+	if (!mode)
+		return NULL;
+	
+	
+	*mode = (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
+
+	return kasprintf(GFP_KERNEL, "rmi/%s", dev_name(dev));
+}
+
+int rmi_char_dev_register(void)
+{
+	struct rmi_char_dev *char_dev;
+	dev_t dev_no;
+	int err;
+	int result;
+	struct device *device_ptr;
+	struct class *rmi_char_device_class;
+
+	if (rmi_char_dev_major_num) {
+		dev_no = MKDEV(rmi_char_dev_major_num, 0);
+		result = register_chrdev_region(dev_no, 1, CHAR_DEVICE_NAME);
+	} else {
+		result = alloc_chrdev_region(&dev_no, 0, 1, CHAR_DEVICE_NAME);
+		
+		rmi_char_dev_major_num = MAJOR(dev_no);
+		printk(KERN_ERR "Major number of rmi_char_dev: %d\n",
+				 rmi_char_dev_major_num);
+	}
+	if (result < 0)
+		return result;
+
+	char_dev = kzalloc(sizeof(struct rmi_char_dev), GFP_KERNEL);
+	if (!char_dev) {
+		printk(KERN_ERR "Failed to allocate rmi_char_dev.\n");
+		
+		__unregister_chrdev(rmi_char_dev_major_num, MINOR(dev_no), 1,
+				CHAR_DEVICE_NAME);
+		return -ENOMEM;
+	}
+
+	mutex_init(&char_dev->mutex_file_op);
+
+
+	cdev_init(&char_dev->main_dev, &rmi_char_dev_fops);
+
+	err = cdev_add(&char_dev->main_dev, dev_no, 1);
+	if (err) {
+		printk(KERN_ERR "Error %d adding rmi_char_dev.\n", err);
+		
+		
+		return err;
+	}
+
+	
+	rmi_char_device_class =
+		class_create(THIS_MODULE, CHAR_DEVICE_NAME);
+
+	if (IS_ERR(rmi_char_device_class)) {
+		printk(KERN_INFO "Failed to create /dev/%s.\n",
+			CHAR_DEVICE_NAME);
+		rmi_char_dev_clean_up(char_dev,
+				 rmi_char_device_class);
+		return -ENODEV;
+	}
+	
+	rmi_char_device_class->devnode = rmi_char_devnode;
+
+	
+	device_ptr = device_create(
+			rmi_char_device_class,
+			NULL, dev_no, NULL,
+			CHAR_DEVICE_NAME"%d",
+			MINOR(dev_no));
+
+	if (IS_ERR(device_ptr)) {
+		printk(KERN_ERR "Failed to create rmi device.\n");
+		rmi_char_dev_clean_up(char_dev,
+				 rmi_char_device_class);
+		return -ENODEV;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(rmi_char_dev_register);
+
+
+void rmi_char_dev_unregister(struct rmi_phys_device *phys)
+{
+	
+	if (phys)
+		rmi_char_dev_clean_up(phys->char_dev,
+				 phys->rmi_char_device_class);
+}
+EXPORT_SYMBOL(rmi_char_dev_unregister);
+
+MODULE_AUTHOR("Synaptics, Inc.");
+MODULE_DESCRIPTION("RMI4 Char Device");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/touchscreen/synaptics_3200.c b/drivers/input/touchscreen/synaptics_3200.c
new file mode 100644
index 0000000..e1207c3
--- /dev/null
+++ b/drivers/input/touchscreen/synaptics_3200.c
@@ -0,0 +1,3109 @@
+/* drivers/input/touchscreen/synaptics_3200.c - Synaptics 3200 serious touch panel driver
+ *
+ * Copyright (C) 2011 HTC Corporation.
+ *
+ *
+ * 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/interrupt.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/synaptics_i2c_rmi.h>
+#include <linux/slab.h>
+#include <linux/rmi.h>
+#include <mach/board.h>
+#include <mach/msm_hsusb.h>
+#include <asm/gpio.h>
+#include <linux/input/mt.h>
+#include <linux/pl_sensor.h>
+
+#define SYN_I2C_RETRY_TIMES 10
+#define SHIFT_BITS 10
+#define SYN_WIRELESS_DEBUG
+#define SYN_CALIBRATION_CONTROL
+
+struct synaptics_ts_data {
+	uint16_t addr;
+	struct i2c_client *client;
+	struct input_dev *input_dev;
+	struct input_dev *sr_input_dev;
+	struct workqueue_struct *syn_wq;
+	struct function_t *address_table;
+	int use_irq;
+	int gpio_irq;
+	int gpio_reset;
+	struct hrtimer timer;
+	struct work_struct  work;
+	uint16_t max[2];
+	uint32_t flags;
+	uint8_t num_function;
+	uint8_t finger_support;
+	uint16_t finger_pressed;
+	int (*power)(int on);
+	struct early_suspend early_suspend;
+	int pre_finger_data[11][4];
+	uint32_t debug_log_level;
+	uint32_t raw_base;
+	uint32_t raw_ref;
+	uint64_t timestamp;
+	uint16_t *filter_level;
+	uint8_t *reduce_report_level;
+	unsigned long tap_timeout[10];
+	int16_t *report_data;
+	uint8_t *temp_report_data;
+	uint8_t grip_suppression;
+	uint8_t grip_b_suppression;
+	uint16_t tap_suppression;
+	uint8_t ambiguous_state;
+	uint8_t diag_command;
+	uint8_t cable_support;
+	uint8_t cable_config;
+	uint8_t key_number;
+	uint16_t key_postion_x[4];
+	uint16_t key_postion_y;
+	uint8_t intr_bit;
+	uint8_t finger_count;
+	uint8_t page_select;
+	uint8_t config_table[SYN_CONFIG_SIZE];
+	uint8_t x_channel;
+	uint8_t y_channel;
+	uint8_t *config;
+	uint32_t config_version;
+	uint16_t package_id;
+	uint32_t packrat_number;
+	int layout[4];
+	uint8_t htc_event;
+	atomic_t data_ready;
+	uint8_t relaxation;
+	uint8_t irq_enabled;
+	uint8_t large_obj_check;
+	uint8_t default_large_obj;
+	uint16_t tw_vendor;
+	uint16_t tw_pin_mask;
+	uint8_t support_htc_event;
+	uint8_t mfg_flag;
+	uint8_t first_pressed;
+	uint8_t segmentation_bef_unlock;
+	uint8_t segmentation_aft_unlock;
+	uint8_t psensor_status;
+	uint8_t i2c_err_handler_en;
+	uint8_t threshold_bef_unlock;
+	uint8_t threshold_aft_unlock;
+	uint16_t saturation_bef_unlock;
+	uint16_t saturation_aft_unlock;
+	uint8_t energy_ratio_relaxation;
+	uint8_t multitouch_calibration;
+	uint32_t width_factor;
+	uint32_t height_factor;
+	uint8_t psensor_detection;
+	uint8_t psensor_resume_enable;
+	uint8_t psensor_phone_enable;
+	uint8_t PixelTouchThreshold_bef_unlock;
+	uint8_t PixelTouchThreshold_aft_unlock;
+	struct work_struct  psensor_work;
+	struct workqueue_struct *syn_psensor_wq;
+	struct synaptics_virtual_key *button;
+};
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+static void synaptics_ts_early_suspend(struct early_suspend *h);
+static void synaptics_ts_late_resume(struct early_suspend *h);
+#endif
+
+static DECLARE_WAIT_QUEUE_HEAD(syn_data_ready_wq);
+static DEFINE_MUTEX(syn_mutex);
+
+static struct synaptics_ts_data *gl_ts;
+static uint16_t syn_panel_version;
+static uint8_t vk_press;
+
+static int i2c_syn_write_byte_data(struct i2c_client *client, uint16_t addr, uint8_t value);
+static int syn_pdt_scan(struct synaptics_ts_data *ts, int num_page);
+static int synaptics_init_panel(struct synaptics_ts_data *ts);
+
+static irqreturn_t synaptics_irq_thread(int irq, void *ptr);
+
+extern unsigned int get_tamper_sf(void);
+
+static void syn_page_select(struct i2c_client *client, uint8_t page)
+{
+	struct synaptics_ts_data *ts = i2c_get_clientdata(client);
+	if (page ^ ts->page_select) {
+		i2c_smbus_write_byte_data(client, 0xFF, page);
+		ts->page_select = page;
+	}
+
+}
+
+static int i2c_syn_read(struct i2c_client *client, uint16_t addr, uint8_t *data, uint16_t length)
+{
+	uint8_t retry, buf;
+
+	struct i2c_msg msg[] = {
+		{
+			.addr = client->addr,
+			.flags = 0,
+			.len = 1,
+			.buf = &buf,
+		},
+		{
+			.addr = client->addr,
+			.flags = I2C_M_RD,
+			.len = length,
+			.buf = data,
+		}
+	};
+	buf = addr & 0xFF;
+
+	mutex_lock(&syn_mutex);
+	syn_page_select(client, addr >> 8);
+	for (retry = 0; retry < SYN_I2C_RETRY_TIMES; retry++) {
+		if (i2c_transfer(client->adapter, msg, 2) == 2)
+			break;
+		msleep(10);
+	}
+	mutex_unlock(&syn_mutex);
+
+	if (retry == SYN_I2C_RETRY_TIMES) {
+		printk(KERN_INFO "[TP] i2c_read retry over %d\n",
+			SYN_I2C_RETRY_TIMES);
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int i2c_syn_write(struct i2c_client *client, uint16_t addr, uint8_t *data, uint16_t length)
+{
+	uint8_t retry;
+	uint8_t buf[length + 1];
+
+	struct i2c_msg msg[] = {
+		{
+			.addr = client->addr,
+			.flags = 0,
+			.len = length + 1,
+			.buf = buf,
+		}
+	};
+
+	mutex_lock(&syn_mutex);
+	syn_page_select(client, addr >> 8);
+
+	buf[0] = addr & 0xFF;
+	memcpy(&buf[1], &data[0], length);
+
+	for (retry = 0; retry < SYN_I2C_RETRY_TIMES; retry++) {
+		if (i2c_transfer(client->adapter, msg, 1) == 1)
+			break;
+		mdelay(10);
+	}
+	mutex_unlock(&syn_mutex);
+
+	if (retry == SYN_I2C_RETRY_TIMES) {
+		printk(KERN_INFO "[TP] i2c_write retry over %d\n",
+			SYN_I2C_RETRY_TIMES);
+		return -EIO;
+	}
+
+	return 0;
+}
+
+int i2c_rmi_read(uint16_t addr, uint8_t *data, uint16_t length)
+{
+	uint8_t retry, buf;
+	struct synaptics_ts_data *ts = gl_ts;
+	struct i2c_msg msg[] = {
+		{
+			.addr = ts->client->addr,
+			.flags = 0,
+			.len = 1,
+			.buf = &buf,
+		},
+		{
+			.addr = ts->client->addr,
+			.flags = I2C_M_RD,
+			.len = length,
+			.buf = data,
+		}
+	};
+	buf = addr & 0xFF;
+
+	mutex_lock(&syn_mutex);
+	syn_page_select(ts->client, addr >> 8);
+	for (retry = 0; retry < SYN_I2C_RETRY_TIMES; retry++) {
+		if (i2c_transfer(ts->client->adapter, msg, 2) == 2)
+			break;
+		msleep(10);
+	}
+	mutex_unlock(&syn_mutex);
+
+	if (retry == SYN_I2C_RETRY_TIMES) {
+		printk(KERN_INFO "[TP] i2c_read retry over %d\n",
+			SYN_I2C_RETRY_TIMES);
+		return -EIO;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(i2c_rmi_read);
+
+int i2c_rmi_write(uint16_t addr, uint8_t *data, uint16_t length)
+{
+	uint8_t retry;
+	uint8_t buf[length + 1];
+	struct synaptics_ts_data *ts = gl_ts;
+	struct i2c_msg msg[] = {
+		{
+			.addr = ts->client->addr,
+			.flags = 0,
+			.len = length + 1,
+			.buf = buf,
+		}
+	};
+
+	mutex_lock(&syn_mutex);
+	syn_page_select(ts->client, addr >> 8);
+
+	buf[0] = addr & 0xFF;
+	memcpy(&buf[1], &data[0], length);
+
+	for (retry = 0; retry < SYN_I2C_RETRY_TIMES; retry++) {
+		if (i2c_transfer(ts->client->adapter, msg, 1) == 1)
+			break;
+		mdelay(10);
+	}
+	mutex_unlock(&syn_mutex);
+
+	if (retry == SYN_I2C_RETRY_TIMES) {
+		printk(KERN_INFO "[TP] i2c_write retry over %d\n",
+			SYN_I2C_RETRY_TIMES);
+		return -EIO;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(i2c_rmi_write);
+
+static int i2c_syn_write_byte_data(struct i2c_client *client, uint16_t addr, uint8_t value)
+{
+	return i2c_syn_write(client, addr, &value, 1);
+}
+
+static int i2c_syn_error_handler(struct synaptics_ts_data *ts, uint8_t reset, char *reason, const char *fun_name)
+{
+	int ret;
+
+	if (reason && fun_name)
+		printk(KERN_ERR "[TP] TOUCH_ERR: I2C Error: %s:%s, reset = %d\n", fun_name, reason, reset);
+	else
+		printk(KERN_INFO "[TP] %s: rason and fun_name can't be null\n", __func__);
+
+	if (reset) {
+		if (ts->power) {
+			ret = ts->power(0);
+			if (ret < 0)
+				printk(KERN_ERR "[TP] TOUCH_ERR: synaptics i2c error handler power off failed\n");
+			msleep(10);
+			ret = ts->power(1);
+			if (ret < 0)
+				printk(KERN_ERR "[TP] TOUCH_ERR: synaptics i2c error handler power on failed\n");
+			ret = synaptics_init_panel(ts);
+			if (ret < 0)
+				printk(KERN_ERR "[TP] TOUCH_ERR: synaptics i2c error handler init panel failed\n");
+		} else if (ts->gpio_reset) {
+			gpio_direction_output(ts->gpio_reset, 0);
+			msleep(1);
+			gpio_direction_output(ts->gpio_reset, 1);
+			printk(KERN_INFO "[TP] %s: synaptics touch chip reseted.\n", __func__);
+		}
+
+		if (!ts->use_irq) {
+			hrtimer_cancel(&ts->timer);
+			hrtimer_start(&ts->timer, ktime_set(1, 0), HRTIMER_MODE_REL);
+		}
+	}
+
+	return -EIO;
+}
+
+static int get_address_base(struct synaptics_ts_data *ts, uint8_t command, uint8_t type)
+{
+	uint8_t i;
+	for (i = 0; i < ts->num_function; i++) {
+		if (ts->address_table[i].function_type == command) {
+			switch (type) {
+			case QUERY_BASE:
+				return ts->address_table[i].query_base;
+			case COMMAND_BASE:
+				return ts->address_table[i].command_base;
+			case CONTROL_BASE:
+				return ts->address_table[i].control_base;
+			case DATA_BASE:
+				return ts->address_table[i].data_base;
+			case INTR_SOURCE:
+				return ts->address_table[i].interrupt_source;
+			case FUNCTION:
+				return 1;
+			}
+		}
+	}
+	if (type == FUNCTION)
+		return 0;
+	else
+		return -1;
+}
+static int get_int_mask(uint8_t number, uint8_t offset)
+{
+	uint8_t i, mask = 0;
+	for (i = 0; i < number; i++)
+		mask |= BIT(i);
+	return mask << offset;
+}
+
+static uint32_t syn_crc(uint16_t *data, uint16_t len)
+{
+	uint32_t sum1, sum2;
+	sum1 = sum2 = 0xFFFF;
+	while (len--) {
+		sum1 += *data++;
+		sum2 += sum1;
+		sum1 = (sum1 & 0xFFFF) + (sum1 >> 16);
+		sum2 = (sum2 & 0xFFFF) + (sum2 >> 16);
+	}
+	return sum1 | (sum2 << 16);
+}
+
+static int wait_flash_interrupt(struct synaptics_ts_data *ts, int attr)
+{
+	uint8_t data = 0;
+	int i, ret;
+
+	for (i = 0; i < 5; i++) {
+#ifdef SYN_FLASH_PROGRAMMING_LOG
+		printk(KERN_INFO "[TP] ATT: %d\n", gpio_get_value(attr));
+#endif
+		if (!gpio_get_value(attr)) {
+			ret = i2c_syn_read(ts->client,
+				get_address_base(ts, 0x01, DATA_BASE) + 1, &data, 1);
+			if (ret < 0)
+				return i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "r:1", __func__);
+			if ((data & 0x01) == 0x01) {
+#ifdef SYN_FLASH_PROGRAMMING_LOG
+				printk(KERN_INFO "[TP] ATT: %d, status: %x\n", gpio_get_value(attr), data);
+#endif
+				break;
+			}
+		}
+		msleep(20);
+	}
+
+	if (i == 5 && syn_panel_version == 0) {
+		ret = i2c_syn_read(ts->client, get_address_base(ts, 0x01, DATA_BASE) + 1, &data, 1);
+		if (ret < 0)
+			return i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "r:2", __func__);
+	} else if (i == 5) {
+		printk(KERN_INFO "[TP] wait_flash_interrupt: interrupt over time!\n");
+		return SYN_PROCESS_ERR;
+	}
+
+	ret = i2c_syn_read(ts->client,
+		get_address_base(ts, 0x34, DATA_BASE) + 18, &data, 1);
+	if (ret < 0)
+		return i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "r:3", __func__);
+	
+	if (data != 0x80) {
+		printk(KERN_INFO "[TP] wait_flash_interrupt: block config fail!\n");
+		return SYN_PROCESS_ERR;
+	}
+	return 0;
+}
+
+static int enable_flash_programming(struct synaptics_ts_data *ts, int attr)
+{
+	int ret;
+	uint8_t data[2];
+
+	
+	ret = i2c_syn_read(ts->client,
+		get_address_base(ts, 0x34, QUERY_BASE), data, 2);
+	if (ret < 0)
+		return i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "r:1", __func__);
+	
+
+	ret = i2c_syn_write(ts->client,
+		get_address_base(ts, 0x34, DATA_BASE) + 2, data, 2);
+	if (ret < 0)
+		return i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "w:2", __func__);
+
+	ret = i2c_syn_write_byte_data(ts->client,
+		get_address_base(ts, 0x34, DATA_BASE) + 18, 0x0F);
+	if (ret < 0)
+		return i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "w:3", __func__);
+
+	ret = wait_flash_interrupt(ts, attr);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static int crc_comparison(struct synaptics_ts_data *ts, uint32_t config_crc, int attr)
+{
+	int ret;
+	uint8_t data[17];
+	uint32_t flash_crc;
+#ifdef SYN_FLASH_PROGRAMMING_LOG
+	uint8_t i, j;
+
+	for (i = 0; i < 0x20; i++) {
+		data[0] = i;
+		data[1] = 0x00;
+#else
+		data[0] = 0x1F;
+		data[1] = 0x00;
+#endif
+		ret = i2c_syn_write(ts->client,
+			get_address_base(ts, 0x34, DATA_BASE), data, 2);
+		if (ret < 0)
+			return i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "w:1", __func__);
+
+		ret = i2c_syn_write_byte_data(ts->client,
+			get_address_base(ts, 0x34, DATA_BASE) + 18, 0x05);
+		if (ret < 0)
+			return i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "w:2", __func__);
+
+		ret = wait_flash_interrupt(ts, attr);
+		if (ret < 0)
+			return ret;
+
+		ret = i2c_syn_read(ts->client,
+			get_address_base(ts, 0x34, DATA_BASE) + 2, data, 17);
+		if (ret < 0)
+			return i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "r:3", __func__);
+
+		memcpy(&flash_crc, &data[12], 4);
+
+#ifdef SYN_FLASH_PROGRAMMING_LOG
+		printk(KERN_INFO "[TP] config_crc = %X, flash_crc = %X\n", config_crc, flash_crc);
+		for (j = 0; j < 0x11; j++)
+			printk(KERN_INFO " %d:%X ", j, data[j]);
+		printk(KERN_INFO "\n");
+	}
+#endif
+
+	if (flash_crc == config_crc)
+		return 0;
+	else
+		return 1;
+}
+
+static int program_config(struct synaptics_ts_data *ts, uint8_t *config, int attr)
+{
+	int ret;
+	uint8_t data[19];
+	uint16_t i;
+
+	ret = i2c_syn_read(ts->client,
+		get_address_base(ts, 0x34, QUERY_BASE), data, 2);
+	
+	if (ret < 0)
+		return i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "r:1", __func__);
+
+	ret = i2c_syn_write(ts->client,
+		get_address_base(ts, 0x34, DATA_BASE) + 2, data, 2);
+	if (ret < 0)
+		return i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "w:2", __func__);
+
+	
+	ret = i2c_syn_write_byte_data(ts->client,
+		get_address_base(ts, 0x34, DATA_BASE) + 18, 0x07);
+	if (ret < 0)
+		return i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "w:3", __func__);
+
+	ret = wait_flash_interrupt(ts, attr);
+	if (ret < 0)
+		return ret;
+
+	for (i = 0; i < 0x20; i++) {
+		data[0] = i & 0xFF;
+		data[1] = (i & 0xFF00) >> 8;
+		memcpy(&data[2], &config[16 * i], 16);
+		data[18] = 0x06;
+		ret = i2c_syn_write(ts->client,
+			get_address_base(ts, 0x34, DATA_BASE), data, 19);
+		if (ret < 0)
+			return i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "w:4", __func__);
+
+		ret = wait_flash_interrupt(ts, attr);
+		if (ret < 0)
+			return ret;
+	}
+
+	return 0;
+}
+
+static int disable_flash_programming(struct synaptics_ts_data *ts, int status)
+{
+	int ret;
+	uint8_t data = 0, i;
+
+	ret = i2c_syn_write_byte_data(ts->client,
+		get_address_base(ts, 0x01, COMMAND_BASE), 0x01);
+	if (ret < 0)
+		return i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "w:1", __func__);
+
+	for (i = 0; i < 25; i++) {
+		ret = i2c_syn_read(ts->client,
+			get_address_base(ts, 0x01, DATA_BASE), &data, 1);
+		if (ret < 0)
+			return i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "r:2", __func__);
+
+		if ((data & 0x40) == 0)
+			break;
+		else
+			msleep(20);
+	}
+
+	if (i == 25) {
+		printk(KERN_INFO "[TP] Disable flash programming fail! F01_data: %X\n", data);
+		return SYN_PROCESS_ERR;
+	} else {
+		printk(KERN_INFO "[TP] Disable flash programming success! F01_data: %X\n", data);
+		return status;
+	}
+}
+
+static int syn_config_update(struct synaptics_ts_data *ts, int attr)
+{
+	uint8_t retry;
+	uint32_t crc_checksum;
+	int ret;
+
+	crc_checksum =
+		syn_crc((uint16_t *)ts->config, SYN_CONFIG_SIZE / 2 - 2);
+	memcpy(&ts->config[SYN_CONFIG_SIZE - 4], &crc_checksum, 4);
+	printk(KERN_INFO "[TP] CRC = %X\n" , syn_crc((uint16_t *)ts->config, SYN_CONFIG_SIZE / 2 - 2));
+
+	if (ts->tw_pin_mask == 0) {
+		ret = enable_flash_programming(ts, attr);
+		if (ret < 0) {
+			printk(KERN_INFO "[TP] syn_config_update: Enable flash programming fail!\n");
+			return disable_flash_programming(ts, ret);
+		}
+
+		ret = syn_pdt_scan(ts, SYN_BL_PAGE);
+		if (ret < 0) {
+			printk(KERN_INFO "[TP] syn_config_update: pdt scan failed\n");
+			return disable_flash_programming(ts, ret);
+		}
+	}
+
+	if ((ts->config != NULL && (ts->config[0] << 24 | ts->config[1] << 16 |
+		ts->config[2] << 8 | ts->config[3]) == ts->config_version)) {
+		ret = crc_comparison(ts, crc_checksum, attr);
+		if (ret < 0) {
+			printk(KERN_INFO "[TP] syn_config_update: CRC comparison fail!\n");
+			return disable_flash_programming(ts, ret);
+		} else if (ret == 0)
+			return disable_flash_programming(ts, 1);
+	}
+
+	for (retry = 0; retry < 3; retry++) {
+		ret = program_config(ts, ts->config, attr);
+		if (ret < 0) {
+#ifdef SYN_FLASH_PROGRAMMING_LOG
+			printk(KERN_INFO "[TP] syn_config_update: Program config fail %d!\n", retry + 1);
+#endif
+			continue;
+		}
+
+		ret = disable_flash_programming(ts, 0);
+		if (ret == 0)
+			break;
+		else
+			printk(KERN_INFO "[TP] syn_config_update: Disable flash programming fail %d\n", retry + 1);
+	}
+
+	if (retry == 3) {
+		printk(KERN_INFO "[TP] syn_config_update: Program config fail 3 times\n");
+		return ret;
+	}
+	return 0;
+}
+
+static int syn_get_tw_vendor(struct synaptics_ts_data *ts, int attr)
+{
+	uint8_t data[2] = {0};
+	int ret;
+
+	ret = enable_flash_programming(ts, attr);
+	if (ret < 0) {
+		printk(KERN_INFO "[TP] Enable flash programming fail!\n");
+		return disable_flash_programming(ts, -1);
+	}
+
+	ret = syn_pdt_scan(ts, SYN_BL_PAGE);
+	if (ret < 0) {
+		printk(KERN_INFO "[TP] syn_config_update: pdt scan failed\n");
+		return disable_flash_programming(ts, ret);
+	}
+
+	memcpy(&data, &ts->tw_pin_mask, sizeof(ts->tw_pin_mask));
+	printk(KERN_INFO "[TP] tw mask = %X %X , %X\n", data[0], data[1], ts->tw_pin_mask);
+	i2c_syn_write(ts->client,
+		get_address_base(ts, 0x34, DATA_BASE) + 2, data, 2);
+	i2c_syn_write(ts->client,
+		get_address_base(ts, 0x34, DATA_BASE) + 4, data, 2);
+	i2c_syn_write_byte_data(ts->client,
+		get_address_base(ts, 0x34, DATA_BASE) + 18, 0x08);
+
+	if (wait_flash_interrupt(ts, attr) < 0)
+		return disable_flash_programming(ts, -1);
+
+	i2c_syn_read(ts->client,
+		get_address_base(ts, 0x34, DATA_BASE) + 6, data, 2);
+	ts->tw_vendor = (data[1] << 8) | data[0];
+	printk(KERN_INFO "[TP] tw vendor= %x %x\n", data[1], data[0]);
+
+	return 0;
+}
+
+static int synaptics_input_register(struct synaptics_ts_data *ts)
+{
+	int ret;
+	ts->input_dev = input_allocate_device();
+	if (ts->input_dev == NULL) {
+		ret = -ENOMEM;
+		printk(KERN_ERR "[TP] TOUCH_ERR: %s: Failed to allocate input device\n", __func__);
+		return ret;
+	}
+	ts->input_dev->name = "synaptics-rmi-touchscreen";
+	set_bit(EV_SYN, ts->input_dev->evbit);
+	set_bit(EV_KEY, ts->input_dev->evbit);
+	set_bit(EV_ABS, ts->input_dev->evbit);
+
+	set_bit(KEY_BACK, ts->input_dev->keybit);
+	set_bit(KEY_HOME, ts->input_dev->keybit);
+	set_bit(KEY_MENU, ts->input_dev->keybit);
+	set_bit(KEY_SEARCH, ts->input_dev->keybit);
+	set_bit(KEY_APP_SWITCH, ts->input_dev->keybit);
+
+	printk(KERN_INFO "[TP] input_set_abs_params: mix_x %d, max_x %d, min_y %d, max_y %d\n",
+		ts->layout[0], ts->layout[1], ts->layout[2], ts->layout[3]);
+
+	if (ts->htc_event == SYN_AND_REPORT_TYPE_B) {
+		input_mt_init_slots(ts->input_dev, ts->finger_support);
+	} else {
+		ts->input_dev->mtsize = ts->finger_support;
+		input_set_abs_params(ts->input_dev, ABS_MT_TRACKING_ID, 0,
+			ts->finger_support - 1, 0, 0);
+	}
+	input_set_abs_params(ts->input_dev, ABS_MT_POSITION_X,
+		ts->layout[0], ts->layout[1], 0, 0);
+	input_set_abs_params(ts->input_dev, ABS_MT_POSITION_Y,
+		ts->layout[2], ts->layout[3], 0, 0);
+
+	input_set_abs_params(ts->input_dev, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0);
+	input_set_abs_params(ts->input_dev, ABS_MT_WIDTH_MAJOR, 0, 30, 0, 0);
+	input_set_abs_params(ts->input_dev, ABS_MT_PRESSURE, 0, 30, 0, 0);
+
+	input_set_abs_params(ts->input_dev, ABS_MT_AMPLITUDE,
+			0, ((255 << 16) | 15), 0, 0);
+	input_set_abs_params(ts->input_dev, ABS_MT_POSITION,
+		0, ((1 << 31) | (ts->layout[1] << 16) | ts->layout[3]), 0, 0);
+
+	return input_register_device(ts->input_dev);
+}
+
+static ssize_t touch_vendor_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	ssize_t ret = 0;
+	char fw_version[2];
+	struct synaptics_ts_data *ts;
+
+	ts = gl_ts;
+	memcpy(fw_version, &syn_panel_version, 2);
+	ret = sprintf(buf, "synaptics-%d_%c.%c", ts->package_id, fw_version[1], fw_version[0]);
+	if (ts->tw_pin_mask != 0)
+		ret += sprintf(buf+ret, "_twID-%x", ts->tw_vendor);
+	else
+		ret += sprintf(buf+ret, "\n");
+	ret += sprintf(buf+ret, "_PR: %d\n", ts->packrat_number);
+
+	return ret;
+}
+
+static DEVICE_ATTR(vendor, S_IRUGO, touch_vendor_show, NULL);
+
+static ssize_t gpio_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	int ret = 0;
+	struct synaptics_ts_data *ts;
+
+	ts = gl_ts;
+
+	ret = gpio_get_value(ts->gpio_irq);
+	printk(KERN_DEBUG "[TP] GPIO_TP_INT_N=%d\n", ret);
+	sprintf(buf, "GPIO_TP_INT_N=%d\n", ret);
+	ret = strlen(buf) + 1;
+
+	return ret;
+}
+
+static DEVICE_ATTR(gpio, S_IRUGO, gpio_show, NULL);
+
+static uint16_t syn_reg_addr;
+
+static ssize_t register_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	int ret = 0;
+	uint8_t data = 0;
+	struct synaptics_ts_data *ts;
+	ts = gl_ts;
+
+	ret = i2c_syn_read(ts->client, syn_reg_addr, &data, 1);
+	if (ret < 0) {
+		i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "r", __func__);
+		ret += sprintf(buf, "addr: 0x , data: 0x \n");
+	} else {
+		ret += sprintf(buf, "addr: 0x%X, data: 0x%X\n", syn_reg_addr, data);
+	}
+	return ret;
+}
+
+static ssize_t register_store(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t count)
+{
+	int ret = 0;
+	struct synaptics_ts_data *ts;
+	char buf_tmp[4];
+	uint8_t write_da;
+	unsigned long addr;
+
+	ts = gl_ts;
+	memset(buf_tmp, 0x0, sizeof(buf_tmp));
+	if ((buf[0] == 'r' || buf[0] == 'w') && buf[1] == ':' &&
+		(buf[5] == ':' || buf[5] == '\n')) {
+		memcpy(buf_tmp, buf + 2, 3);
+		ret = strict_strtoul(buf_tmp, 16, &addr);
+		syn_reg_addr = addr;
+		printk(KERN_DEBUG "[TP] %s: set syn_reg_addr is: 0x%X\n",
+						__func__, syn_reg_addr);
+		if (buf[0] == 'w' && buf[5] == ':' && buf[9] == '\n') {
+			memcpy(buf_tmp, buf + 6, 3);
+			ret = strict_strtoul(buf_tmp, 16, &addr);
+			write_da = addr;
+			printk(KERN_DEBUG "[TP] write addr: 0x%X, data: 0x%X\n",
+						syn_reg_addr, write_da);
+			ret = i2c_syn_write_byte_data(ts->client,
+					syn_reg_addr, write_da);
+			if (ret < 0) {
+				i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "w", __func__);
+			}
+		}
+	}
+
+	return count;
+}
+
+static DEVICE_ATTR(register, (S_IWUSR|S_IRUGO),
+	register_show, register_store);
+
+static ssize_t debug_level_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct synaptics_ts_data *ts = gl_ts;
+
+	return sprintf(buf, "%d\n", ts->debug_log_level);
+}
+
+static ssize_t debug_level_store(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t count)
+{
+	struct synaptics_ts_data *ts = gl_ts;
+	int i;
+
+	ts->debug_log_level = 0;
+	for(i=0; i<count-1; i++)
+	{
+		if( buf[i]>='0' && buf[i]<='9' )
+			ts->debug_log_level |= (buf[i]-'0');
+		else if( buf[i]>='A' && buf[i]<='F' )
+			ts->debug_log_level |= (buf[i]-'A'+10);
+		else if( buf[i]>='a' && buf[i]<='f' )
+			ts->debug_log_level |= (buf[i]-'a'+10);
+
+		if(i!=count-2)
+			ts->debug_log_level <<= 4;
+	}
+
+	return count;
+}
+
+static DEVICE_ATTR(debug_level, (S_IWUSR|S_IRUGO),
+	debug_level_show, debug_level_store);
+
+static ssize_t syn_diag_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct synaptics_ts_data *ts = gl_ts;
+	size_t count = 0;
+	uint16_t i, j;
+	int ret;
+
+	ret = i2c_syn_write_byte_data(ts->client,
+		get_address_base(ts, 0x54, DATA_BASE), ts->diag_command);
+	if (ret < 0) {
+		i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "w:1", __func__);
+		count += sprintf(buf, "[TP] TOUCH_ERR: %s: i2c write fail(%d)\n", __func__, ret);
+		return count;
+	}
+
+	atomic_set(&ts->data_ready, 0);
+
+	ret = i2c_syn_write_byte_data(ts->client,
+		get_address_base(ts, 0x54, COMMAND_BASE), 0x01);
+	if (ret < 0) {
+		atomic_set(&ts->data_ready, 1);
+		i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "w:2", __func__);
+		count += sprintf(buf, "[TP] TOUCH_ERR: %s: i2c write fail(%d)\n", __func__, ret);
+		return count;
+	}
+
+	wait_event_interruptible_timeout(syn_data_ready_wq,
+					 atomic_read(&ts->data_ready), 50);
+
+	for (i = 0; i < ts->y_channel; i++) {
+		for (j = 0; j < ts->x_channel; j++) {
+			if(ts->package_id == 3201)
+				count += sprintf(buf + count, "%5d", ts->report_data[i*ts->x_channel + j]);
+			else
+				count += sprintf(buf + count, "%5d", ts->report_data[i + j*ts->y_channel]);
+		}
+		count += sprintf(buf + count, "\n");
+	}
+
+	return count;
+}
+
+static ssize_t syn_diag_store(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t count)
+{
+	struct synaptics_ts_data *ts;
+	ts = gl_ts;
+	if (buf[0] == '1')
+		ts->diag_command = 2;
+	else if (buf[0] == '2')
+		ts->diag_command = 3;
+
+	return count;
+}
+
+static DEVICE_ATTR(diag, (S_IWUSR|S_IRUGO),
+	syn_diag_show, syn_diag_store);
+
+static ssize_t syn_unlock_store(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t count)
+{
+	struct synaptics_ts_data *ts;
+	int unlock = -1;
+	int ret;
+
+	ts = gl_ts;
+
+	if (buf[0] >= '0' && buf[0] <= '9' && buf[1] == '\n')
+		unlock = buf[0] - '0';
+
+	printk(KERN_INFO "[TP] Touch: unlock change to %d\n", unlock);
+
+	if (unlock == 2 && ts->first_pressed && ts->pre_finger_data[0][0] < 2) {
+		ts->pre_finger_data[0][0] = 2;
+		if(ts->psensor_detection) {
+			if(ts->psensor_resume_enable == 1) {
+				printk(KERN_INFO "[TP] %s: Disable P-sensor by Touch\n", __func__);
+				psensor_enable_by_touch_driver(0);
+				ts->psensor_resume_enable = 0;
+			}
+			else if(ts->psensor_resume_enable == 2) {
+				ts->psensor_resume_enable = 0;
+			}
+		}
+		if (ts->packrat_number < SYNAPTICS_FW_NOCAL_PACKRAT) {
+#ifdef SYN_CALIBRATION_CONTROL
+			ret = i2c_syn_write_byte_data(ts->client,
+				get_address_base(ts, 0x54, CONTROL_BASE) + 0x10, 0x0);
+			if (ret < 0)
+				return i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "w:1", __func__);
+
+			if (ts->energy_ratio_relaxation) {
+				ret = i2c_syn_write_byte_data(ts->client,
+					get_address_base(ts, 0x54, CONTROL_BASE), 0x0);
+				if (ret < 0)
+					return i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "w:2", __func__);
+			}
+
+			if (ts->saturation_bef_unlock) {
+				ret = i2c_syn_write_byte_data(ts->client,
+					get_address_base(ts, 0x54, CONTROL_BASE) + 0x02, ts->saturation_aft_unlock & 0xFF);
+				if (ret < 0)
+					return i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "w:3", __func__);
+				ret = i2c_syn_write_byte_data(ts->client,
+					get_address_base(ts, 0x54, CONTROL_BASE) + 0x03, (ts->saturation_aft_unlock & 0xFF00) >> 8);
+				if (ret < 0)
+					return i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "w:4", __func__);
+				printk(KERN_INFO "[TP] %s: unlock confirmed. set saturation: %x\n"
+					, __func__, ts->saturation_aft_unlock);
+			}
+
+			if ( ts->PixelTouchThreshold_bef_unlock ) {
+				ret = i2c_syn_write_byte_data(ts->client,
+					get_address_base(ts, 0x54, CONTROL_BASE) + 0x04, ts->PixelTouchThreshold_aft_unlock);
+				if (ret < 0)
+					return i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "F54_ANALOG_CTRL03 Pixel Touch Threshold", __func__);
+				printk(KERN_INFO "[TP] %s: set F54_ANALOG_CTRL03 Pixel Touch Threshold: %x\n", __func__, ts->PixelTouchThreshold_aft_unlock);
+			}
+
+
+			ret = i2c_syn_write_byte_data(ts->client,
+				get_address_base(ts, 0x54, COMMAND_BASE), 0x04);
+			if (ret < 0)
+				return i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "w:5", __func__);
+
+			if (ts->multitouch_calibration) {
+				ret = i2c_syn_write_byte_data(ts->client,
+					get_address_base(ts, 0x11, COMMAND_BASE), 0x01);
+				if (ret < 0)
+					return i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "w:6", __func__);
+				printk(KERN_INFO "[TP] %s: Touch Calibration Confirmed, rezero\n", __func__);
+			}
+#endif
+			if (ts->large_obj_check) {
+				if (ts->package_id == 2200) {
+					ret = i2c_syn_write_byte_data(ts->client,
+						get_address_base(ts, 0x11, CONTROL_BASE) + 0x26, ts->default_large_obj);
+
+				} else {
+					ret = i2c_syn_write_byte_data(ts->client,
+						get_address_base(ts, 0x11, CONTROL_BASE) + 0x29, ts->default_large_obj);
+				}
+				if (ret < 0)
+					return i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "w:7", __func__);
+				printk(KERN_INFO "[TP] %s: unlock confirmed. set large obj suppression: %x\n"
+					, __func__, ts->default_large_obj);
+			}
+
+			if (ts->segmentation_bef_unlock) {
+				if (ts->package_id == 2200) {
+					ret = i2c_syn_write_byte_data(ts->client,
+						get_address_base(ts, 0x11, CONTROL_BASE) + 0x25, ts->segmentation_aft_unlock);
+
+				} else {
+					ret = i2c_syn_write_byte_data(ts->client,
+						get_address_base(ts, 0x11, CONTROL_BASE) + 0x22, ts->segmentation_aft_unlock);
+				}
+				if (ret < 0)
+					return i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "w:8", __func__);
+				printk(KERN_INFO "[TP] %s: unlock confirmed. set segmentation aggressiveness: %x\n"
+					, __func__, ts->segmentation_aft_unlock);
+			}
+
+			if (ts->threshold_bef_unlock) {
+				if (ts->package_id == 2200) {
+					ret = i2c_syn_write_byte_data(ts->client,
+						get_address_base(ts, 0x11, CONTROL_BASE) + 0x0A, ts->threshold_aft_unlock);
+				} else {
+					ret = i2c_syn_write_byte_data(ts->client,
+						get_address_base(ts, 0x11, CONTROL_BASE) + 0x0C, ts->threshold_aft_unlock);
+				}
+				if (ret < 0)
+					return i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "w:9", __func__);
+				printk(KERN_INFO "[TP] %s: unlock confirmed. set Z Touch threshold: %x\n"
+					, __func__, ts->threshold_aft_unlock);
+			}
+		}
+	}
+
+	return count;
+}
+
+static DEVICE_ATTR(unlock, (S_IWUSR|S_IRUGO),
+	NULL, syn_unlock_store);
+
+static ssize_t syn_config_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct synaptics_ts_data *ts = gl_ts;
+	uint16_t i, length = 0;
+	uint8_t j, temp_func_cmd = 0, temp_func_query = 0, size = 0;
+	size_t count = 0;
+	int ret;
+
+	printk(KERN_INFO "[TP] ts->num_function: %d\n", ts->num_function);
+	for (i = 0; i < SYN_MAX_PAGE; i++) {
+		for (j = 0; j < ts->num_function; j++) {
+			if (((ts->address_table[j].control_base >> 8) & 0xFF) == i) {
+				temp_func_query = 0;
+				for (temp_func_cmd = j; temp_func_cmd < ts->num_function; temp_func_cmd++) {
+					uint16_t max_addr = (i << 8) | 0xFF;
+					uint16_t min_addr = (i << 8) | 0;
+					if ((ts->address_table[temp_func_cmd].command_base > min_addr) &&
+						(ts->address_table[temp_func_cmd].command_base <= max_addr))
+						break;
+					if ((ts->address_table[temp_func_cmd].query_base > min_addr) &&
+						(ts->address_table[temp_func_cmd].query_base <= max_addr)
+						&& temp_func_query == 0)
+						temp_func_query = temp_func_cmd;
+				}
+
+				if (temp_func_cmd != ts->num_function) {
+					size = ts->address_table[temp_func_cmd].command_base -
+						ts->address_table[j].control_base;
+					printk(KERN_INFO "[TP] page%d has command function, function: %X\n"
+						, i, ts->address_table[temp_func_cmd].function_type);
+				} else {
+					size = ts->address_table[temp_func_query].query_base -
+						ts->address_table[j].control_base;
+					printk(KERN_INFO "[TP] page%d has no command function, use query function, function: %X\n"
+						, i, ts->address_table[temp_func_query].function_type);
+				}
+
+				ret = i2c_syn_read(ts->client, ts->address_table[j].control_base,
+					&ts->config_table[length], size);
+				if (ret < 0) {
+					i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "w", __func__);
+					count += sprintf(buf, "[TP] TOUCH_ERR: %s: i2c write fail(%d)\n", __func__, ret);
+					return count;
+				}
+
+				length += size;
+				printk(KERN_INFO "[TP] Size: %x, Length: %x\n", size, length);
+				break;
+			}
+		}
+	}
+	if(length > SYN_CONFIG_SIZE)
+		length = SYN_CONFIG_SIZE;
+
+	printk(KERN_INFO "");
+	for (i = 0; i < length; i++) {
+		printk(KERN_INFO "%2.2X ", ts->config_table[i]);
+		if ((i % 16) == 15)
+			printk(KERN_INFO "\n");
+	}
+
+	for (i = 0; i < length; i++) {
+		count += sprintf(buf + count, "%2.2X ", ts->config_table[i]);
+		if ((i % 16) == (16 - 1))
+			count += sprintf(buf + count, "\n");
+	}
+	count += sprintf(buf + count, "\n");
+
+	return count;
+}
+
+static ssize_t syn_config_store(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t count)
+{
+	struct synaptics_ts_data *ts = gl_ts;
+	uint8_t i, j, k = 0, length = 0;
+	printk(KERN_INFO "[TP] ts->num_function: %d\n", ts->num_function);
+	for (i = 0; i < SYN_MAX_PAGE; i++) {
+		for (j = 0; j < ts->num_function; j++) {
+			if (((ts->address_table[j].control_base >> 8) & 0xFF) == i) {
+				for (k = j; k < ts->num_function; k++)
+					if (ts->address_table[k].command_base != 0)
+						break;
+				length += ts->address_table[k].command_base -
+					ts->address_table[j].control_base;
+				printk(KERN_INFO "[%d]Length: %x\n", i, length);
+				break;
+			}
+		}
+	}
+
+	return count;
+}
+
+static DEVICE_ATTR(config, (S_IWUSR|S_IRUGO),
+	syn_config_show, syn_config_store);
+
+
+static ssize_t syn_layout_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct synaptics_ts_data *ts = gl_ts;
+	uint8_t i;
+	size_t count = 0;
+	for (i = 0; i < 4; i++)
+		count += sprintf(buf + count, "%d ", ts->layout[i]);
+	count += sprintf(buf + count, "\n");
+
+	return count;
+}
+
+static ssize_t syn_layout_store(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t count)
+{
+	struct synaptics_ts_data *ts = gl_ts;
+	char buf_tmp[5];
+	int i = 0, j = 0, k = 0, ret;
+	unsigned long value;
+	int layout[4] = {0};
+
+	for (i = 0; i < 20; i++) {
+		if (buf[i] == ',' || buf[i] == '\n') {
+			memset(buf_tmp, 0x0, sizeof(buf_tmp));
+			if (i - j <= 5)
+				memcpy(buf_tmp, buf + j, i - j);
+			else {
+				printk(KERN_INFO "[TP] buffer size is over 5 char\n");
+				return count;
+			}
+			j = i + 1;
+			if (k < 4) {
+				ret = strict_strtol(buf_tmp, 10, &value);
+				layout[k++] = value;
+			}
+		}
+	}
+	if (k == 4) {
+		memcpy(ts->layout, layout, sizeof(layout));
+		printk(KERN_INFO "[TP] %d, %d, %d, %d\n",
+			ts->layout[0], ts->layout[1], ts->layout[2], ts->layout[3]);
+		input_unregister_device(ts->input_dev);
+		synaptics_input_register(ts);
+	} else
+		printk(KERN_INFO "[TP] ERR@%d, %d, %d, %d\n",
+			ts->layout[0], ts->layout[1], ts->layout[2], ts->layout[3]);
+	return count;
+
+}
+
+static DEVICE_ATTR(layout, (S_IWUSR|S_IRUGO),
+	syn_layout_show, syn_layout_store);
+
+
+static ssize_t syn_pdt_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct synaptics_ts_data *ts = gl_ts;
+	uint8_t i;
+	size_t count = 0;
+	for (i = 0; i < ts->num_function; i++) {
+		count += sprintf(buf + count,
+			"Funtion: %2X, Query: %3X, Command: %3X, "
+			"Control: %3X, Data: %3X, INTR: %2X\n",
+			ts->address_table[i].function_type, ts->address_table[i].query_base ,
+			ts->address_table[i].command_base, ts->address_table[i].control_base,
+			ts->address_table[i].data_base, ts->address_table[i].interrupt_source);
+	}
+	return count;
+}
+
+static DEVICE_ATTR(pdt, S_IRUGO, syn_pdt_show, NULL);
+
+static ssize_t syn_htc_event_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct synaptics_ts_data *ts = gl_ts;
+
+	return sprintf(buf, "%d\n", ts->htc_event);
+}
+
+static ssize_t syn_htc_event_store(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t count)
+{
+	struct synaptics_ts_data *ts = gl_ts;
+
+	if (buf[0] >= '0' && buf[0] <= '9' && buf[1] == '\n')
+		ts->htc_event = buf[0] - '0';
+
+	return count;
+}
+
+static DEVICE_ATTR(htc_event, (S_IWUSR|S_IRUGO),
+	syn_htc_event_show, syn_htc_event_store);
+
+#ifdef SYN_WIRELESS_DEBUG
+static ssize_t syn_int_status_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct synaptics_ts_data *ts = gl_ts;
+	size_t count = 0;
+
+	count += sprintf(buf + count, "%d ", ts->irq_enabled);
+	count += sprintf(buf + count, "\n");
+
+	return count;
+}
+
+static ssize_t syn_int_status_store(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t count)
+{
+	struct synaptics_ts_data *ts = gl_ts;
+	int value, ret=0;
+
+	if (sysfs_streq(buf, "0"))
+		value = false;
+	else if (sysfs_streq(buf, "1"))
+		value = true;
+	else
+		return -EINVAL;
+
+	if (value) {
+		ret = request_threaded_irq(ts->client->irq, NULL, synaptics_irq_thread,
+			IRQF_TRIGGER_LOW | IRQF_ONESHOT, ts->client->name, ts);
+		if (ret == 0) {
+			ts->irq_enabled = 1;
+			ret = i2c_syn_read(ts->client,
+				get_address_base(ts, 0x01, CONTROL_BASE) + 1, &ts->intr_bit, 1);
+			printk(KERN_INFO "[TP] %s: interrupt enable: %x\n", __func__, ts->intr_bit);
+			if (ret)
+				free_irq(ts->client->irq, ts);
+		}
+	} else {
+		disable_irq(ts->client->irq);
+		free_irq(ts->client->irq, ts);
+		ts->irq_enabled = 0;
+	}
+
+	return count;
+}
+
+static DEVICE_ATTR(enabled, (S_IWUSR|S_IRUGO),
+	syn_int_status_show, syn_int_status_store);
+
+static ssize_t syn_reset(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t count)
+{
+	struct synaptics_ts_data *ts = gl_ts;
+
+	if (buf[0] == '1' && ts->gpio_reset) {
+		gpio_direction_output(ts->gpio_reset, 0);
+		msleep(1);
+		gpio_direction_output(ts->gpio_reset, 1);
+		printk(KERN_INFO "[TP] %s: synaptics touch chip reseted.\n", __func__);
+	}
+
+	return count;
+}
+
+static DEVICE_ATTR(reset, (S_IWUSR),
+	0, syn_reset);
+
+#endif
+
+enum SR_REG_STATE{
+	ALLOCATE_DEV_FAIL = -2,
+	REGISTER_DEV_FAIL,
+	SUCCESS,
+};
+
+static char *vk_name = "virtualkeys.sr_touchscreen";
+static struct kobj_attribute vk_dev;
+
+static int register_sr_touch_device(void)
+{
+	struct synaptics_ts_data *ts = gl_ts;
+	struct synaptics_i2c_rmi_platform_data *pdata = ts->client->dev.platform_data;
+	int ret = 0;
+
+	ts->sr_input_dev = input_allocate_device();
+
+	if (ts->sr_input_dev == NULL) {
+		printk(KERN_ERR "[TP][TOUCH_ERR]%s: Failed to allocate SR input device\n", __func__);
+		return ALLOCATE_DEV_FAIL;
+	}
+
+	if (pdata->vk_obj) {
+		memcpy(&vk_dev, pdata->vk2Use, sizeof(struct kobj_attribute));
+		vk_dev.attr.name = vk_name;
+		ret = sysfs_create_file(pdata->vk_obj, &(vk_dev.attr));
+	}
+
+	ts->sr_input_dev->name = "sr_touchscreen";
+	set_bit(EV_SYN, ts->sr_input_dev->evbit);
+	set_bit(EV_ABS, ts->sr_input_dev->evbit);
+	set_bit(EV_KEY, ts->sr_input_dev->evbit);
+
+	set_bit(KEY_BACK, ts->sr_input_dev->keybit);
+	set_bit(KEY_HOME, ts->sr_input_dev->keybit);
+	set_bit(KEY_MENU, ts->sr_input_dev->keybit);
+	set_bit(KEY_SEARCH, ts->sr_input_dev->keybit);
+	set_bit(BTN_TOUCH, ts->sr_input_dev->keybit);
+	set_bit(KEY_APP_SWITCH, ts->sr_input_dev->keybit);
+	set_bit(INPUT_PROP_DIRECT, ts->sr_input_dev->propbit);
+	ts->sr_input_dev->mtsize = ts->finger_support;
+	input_set_abs_params(ts->sr_input_dev, ABS_MT_TRACKING_ID,
+		0, ts->finger_support - 1, 0, 0);
+	printk(KERN_INFO "[TP][SR]input_set_abs_params: mix_x %d, max_x %d,"
+		" min_y %d, max_y %d\n", ts->layout[0],
+		 ts->layout[1], ts->layout[2], ts->layout[3]);
+
+	input_set_abs_params(ts->sr_input_dev, ABS_MT_POSITION_X,
+		ts->layout[0], ts->layout[1], 0, 0);
+	input_set_abs_params(ts->sr_input_dev, ABS_MT_POSITION_Y,
+		ts->layout[2], ts->layout[3], 0, 0);
+	input_set_abs_params(ts->sr_input_dev, ABS_MT_TOUCH_MAJOR,
+		0, 255, 0, 0);
+	input_set_abs_params(ts->sr_input_dev, ABS_MT_PRESSURE,
+		0, 30, 0, 0);
+	input_set_abs_params(ts->sr_input_dev, ABS_MT_WIDTH_MAJOR,
+		0, 30, 0, 0);
+
+	if (input_register_device(ts->sr_input_dev)) {
+		input_free_device(ts->sr_input_dev);
+		printk(KERN_ERR "[TP][SR][TOUCH_ERR]%s: Unable to register %s input device\n",
+			__func__, ts->sr_input_dev->name);
+		return REGISTER_DEV_FAIL;
+	}
+	return SUCCESS;
+}
+
+static ssize_t set_en_sr(struct device *dev, struct device_attribute *attr,
+						const char *buf, size_t count)
+{
+	struct synaptics_ts_data *ts = gl_ts;
+	if (buf[0]) {
+		if (ts->sr_input_dev)
+			printk(KERN_INFO "[TP]%s: SR device already exist!\n", __func__);
+		else
+			printk(KERN_INFO "[TP]%s: SR touch device enable result:%X\n", __func__, register_sr_touch_device());
+	}
+	return count;
+}
+
+static DEVICE_ATTR(sr_en, S_IWUSR, 0, set_en_sr);
+
+static struct kobject *android_touch_kobj;
+
+static int synaptics_touch_sysfs_init(void)
+{
+	int ret;
+#ifdef SYN_WIRELESS_DEBUG
+	struct synaptics_ts_data *ts = gl_ts;
+#endif
+
+	android_touch_kobj = kobject_create_and_add("android_touch", NULL);
+	if (android_touch_kobj == NULL) {
+		printk(KERN_ERR "[TP] TOUCH_ERR: %s: subsystem_register failed\n", __func__);
+		ret = -ENOMEM;
+		return ret;
+	}
+	syn_reg_addr = 0;
+	if (sysfs_create_file(android_touch_kobj, &dev_attr_vendor.attr) ||
+		sysfs_create_file(android_touch_kobj, &dev_attr_gpio.attr) ||
+		sysfs_create_file(android_touch_kobj, &dev_attr_debug_level.attr) ||
+		sysfs_create_file(android_touch_kobj, &dev_attr_register.attr) ||
+		sysfs_create_file(android_touch_kobj, &dev_attr_unlock.attr) ||
+		sysfs_create_file(android_touch_kobj, &dev_attr_config.attr) ||
+		sysfs_create_file(android_touch_kobj, &dev_attr_layout.attr) ||
+		sysfs_create_file(android_touch_kobj, &dev_attr_pdt.attr) ||
+		sysfs_create_file(android_touch_kobj, &dev_attr_htc_event.attr) ||
+		sysfs_create_file(android_touch_kobj, &dev_attr_reset.attr) ||
+		sysfs_create_file(android_touch_kobj, &dev_attr_sr_en.attr)
+#ifdef SYN_WIRELESS_DEBUG
+		|| sysfs_create_file(android_touch_kobj, &dev_attr_enabled.attr)
+#endif
+		)
+		return -ENOMEM;
+	if (get_address_base(gl_ts, 0x54, FUNCTION))
+		if (sysfs_create_file(android_touch_kobj, &dev_attr_diag.attr))
+			return -ENOMEM;
+
+#ifdef SYN_WIRELESS_DEBUG
+	ret= gpio_request(ts->gpio_irq, "synaptics_attn");
+	if (ret) {
+		printk(KERN_INFO "[TP]%s: Failed to obtain touchpad IRQ %d. Code: %d.", __func__, ts->gpio_irq, ret);
+		return ret;
+	}
+	if (ts->gpio_reset) {
+		ret = gpio_request(ts->gpio_reset, "synaptics_reset");
+		if (ret)
+			printk(KERN_INFO "[TP]%s: Failed to obtain reset pin: %d. Code: %d.", __func__, ts->gpio_reset, ret);
+	}
+	ret = gpio_export(ts->gpio_irq, true);
+	if (ret) {
+		printk(KERN_INFO "[TP]%s: Failed to "
+			"export ATTN gpio!\n", __func__);
+		ret = 0;
+	} else {
+		ret = gpio_export_link(&(ts->input_dev->dev), "attn",
+			ts->gpio_irq);
+		if (ret) {
+			printk(KERN_INFO "[TP]%s: Failed to "
+				"symlink ATTN gpio!\n", __func__);
+			ret = 0;
+		} else {
+			printk(KERN_INFO "[TP]%s: Exported GPIO %d.", __func__, ts->gpio_irq);
+		}
+	}
+#endif
+	return 0;
+}
+
+static void synaptics_touch_sysfs_remove(void)
+{
+	sysfs_remove_file(android_touch_kobj, &dev_attr_vendor.attr);
+	sysfs_remove_file(android_touch_kobj, &dev_attr_gpio.attr);
+	sysfs_remove_file(android_touch_kobj, &dev_attr_debug_level.attr);
+	if (get_address_base(gl_ts, 0x54, FUNCTION))
+		sysfs_remove_file(android_touch_kobj, &dev_attr_diag.attr);
+	sysfs_remove_file(android_touch_kobj, &dev_attr_register.attr);
+	sysfs_remove_file(android_touch_kobj, &dev_attr_unlock.attr);
+	sysfs_remove_file(android_touch_kobj, &dev_attr_config.attr);
+	sysfs_remove_file(android_touch_kobj, &dev_attr_layout.attr);
+	sysfs_remove_file(android_touch_kobj, &dev_attr_pdt.attr);
+	sysfs_remove_file(android_touch_kobj, &dev_attr_htc_event.attr);
+	sysfs_remove_file(android_touch_kobj, &dev_attr_reset.attr);
+	sysfs_remove_file(android_touch_kobj, &dev_attr_sr_en.attr);
+#ifdef SYN_WIRELESS_DEBUG
+	sysfs_remove_file(android_touch_kobj, &dev_attr_enabled.attr);
+#endif
+	kobject_del(android_touch_kobj);
+}
+
+static int synaptics_init_panel(struct synaptics_ts_data *ts)
+{
+	int ret = 0;
+
+	
+	ret = i2c_syn_write_byte_data(ts->client,
+			get_address_base(ts, 0x01, CONTROL_BASE), 0x80);
+	if (ret < 0)
+		return i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "w:1", __func__);
+	if (ts->pre_finger_data[0][0] < 2) {
+		if (ts->large_obj_check) {
+			if (ts->package_id == 2200) {
+				ret = i2c_syn_write_byte_data(ts->client,
+					get_address_base(ts, 0x11, CONTROL_BASE) + 0x26, ts->default_large_obj & 0x7F);
+			} else {
+				ret = i2c_syn_write_byte_data(ts->client,
+					get_address_base(ts, 0x11, CONTROL_BASE) + 0x29, ts->default_large_obj & 0x7F);
+			}
+			if (ret < 0)
+				return i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "w:2", __func__);
+			printk(KERN_INFO "[TP] %s: set large obj suppression register to: %x\n", __func__, ts->default_large_obj & 0x7F);
+		}
+
+		if (ts->segmentation_bef_unlock) {
+			if (ts->package_id == 2200) {
+				ret = i2c_syn_write_byte_data(ts->client,
+					get_address_base(ts, 0x11, CONTROL_BASE) + 0x25, ts->segmentation_bef_unlock);
+			} else {
+				ret = i2c_syn_write_byte_data(ts->client,
+					get_address_base(ts, 0x11, CONTROL_BASE) + 0x22, ts->segmentation_bef_unlock);
+			}
+			if (ret < 0)
+				return i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "w:3", __func__);
+			printk(KERN_INFO "[TP] %s: set segmentation aggressiveness to: %x\n", __func__, ts->segmentation_bef_unlock);
+		}
+
+		if (ts->threshold_bef_unlock) {
+			if (ts->package_id == 2200) {
+				ret = i2c_syn_write_byte_data(ts->client,
+					get_address_base(ts, 0x11, CONTROL_BASE) + 0x0A, ts->threshold_bef_unlock);
+			} else {
+				ret = i2c_syn_write_byte_data(ts->client,
+					get_address_base(ts, 0x11, CONTROL_BASE) + 0x0C, ts->threshold_bef_unlock);
+			}
+			if (ret < 0)
+				return i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "w:4", __func__);
+			printk(KERN_INFO "[TP] %s: set Z Touch threshold to: %x\n", __func__, ts->threshold_bef_unlock);
+		}
+
+		if (ts->saturation_bef_unlock) {
+			ret = i2c_syn_write_byte_data(ts->client,
+				get_address_base(ts, 0x54, CONTROL_BASE) + 0x02, ts->saturation_bef_unlock & 0xFF);
+			if (ret < 0)
+				return i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "saturation capacitance", __func__);
+			ret = i2c_syn_write_byte_data(ts->client,
+				get_address_base(ts, 0x54, CONTROL_BASE) + 0x03, (ts->saturation_bef_unlock & 0xFF00) >> 8);
+			if (ret < 0)
+				return i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "saturation capacitance", __func__);
+			printk(KERN_INFO "[TP] %s: set saturation to: %x\n", __func__, ts->saturation_bef_unlock);
+			ret = i2c_syn_write_byte_data(ts->client,
+				get_address_base(ts, 0x54, COMMAND_BASE), 0x04);
+			if (ret < 0)
+				return i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "w:5", __func__);
+		}
+
+		if ( ts->PixelTouchThreshold_bef_unlock ) {
+			ret = i2c_syn_write_byte_data(ts->client,
+				get_address_base(ts, 0x54, CONTROL_BASE) + 0x04, ts->PixelTouchThreshold_bef_unlock );
+			if (ret < 0)
+				return i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "F54_ANALOG_CTRL03 Pixel Touch Threshold", __func__);
+			printk(KERN_INFO "[TP] %s: set F54_ANALOG_CTRL03 Pixel Touch Threshold: %x\n", __func__, ts->PixelTouchThreshold_bef_unlock);
+			ret = i2c_syn_write_byte_data(ts->client,
+				get_address_base(ts, 0x54, COMMAND_BASE), 0x04);
+			if (ret < 0)
+				return i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "w:6", __func__);
+		}
+	}
+
+#ifdef SYN_CALIBRATION_CONTROL
+	if (ts->packrat_number < SYNAPTICS_FW_NOCAL_PACKRAT) {
+		if (ts->pre_finger_data[0][0] >= 2 || ts->mfg_flag == 1) {
+			ret = i2c_syn_write_byte_data(ts->client,
+				get_address_base(ts, 0x54, CONTROL_BASE) + 0x10, 0x0);
+			if (ret < 0)
+				return i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "w:6", __func__);
+
+			ret = i2c_syn_write_byte_data(ts->client,
+				get_address_base(ts, 0x54, COMMAND_BASE), 0x04);
+			if (ret < 0)
+				return i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "w:7", __func__);
+
+			printk(KERN_INFO "[TP] %s: Touch init: set fast relaxation to 0x0\n", __func__);
+		}
+	}
+#endif
+
+	return ret;
+}
+
+static void synaptics_ts_finger_func(struct synaptics_ts_data *ts)
+{
+	int ret;
+	uint8_t buf[((ts->finger_support * 21 + 3) / 4)];
+
+	memset(buf, 0x0, sizeof(buf));
+	ret = i2c_syn_read(ts->client,
+		get_address_base(ts, 0x11, DATA_BASE), buf, sizeof(buf));
+	if (ret < 0) {
+		i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "r:1", __func__);
+	} else {
+		int finger_data[ts->finger_support][4];
+		int base = (ts->finger_support + 3) / 4;
+		uint8_t i, j;
+		uint16_t finger_press_changed = 0, finger_release_changed = 0, finger_pressed = 0;
+
+		ts->finger_count = 0;
+		if (ts->debug_log_level & BIT(0)) {
+			printk(KERN_INFO "[TP] Touch:");
+			for (i = 0; i < sizeof(buf); i++)
+				printk(KERN_INFO " %2x", buf[i]);
+			printk(KERN_INFO "\n");
+		}
+		for (i = 0; i < ts->finger_support; i++) {
+			uint8_t finger_state = buf[(i / 4)] >> ((i * 2) % 8);
+			if (finger_state & 0x03) {
+				finger_pressed |= BIT(i);
+				ts->finger_count++;
+				if (finger_state == 0x02)
+					printk(KERN_INFO "[TP] Finger state[%d] = 0x02\n", i);
+				else if (finger_state == 0x03)
+					printk(KERN_INFO "[TP] Finger state[%d] = 0x03\n", i);
+			}
+#ifdef SYN_FILTER_CONTROL
+			else if ((ts->grip_suppression | ts->grip_b_suppression) & BIT(i)) {
+				ts->grip_suppression &= ~BIT(i);
+				ts->grip_b_suppression &= ~BIT(i);
+			}
+#endif
+		}
+		if (ts->finger_pressed != finger_pressed
+			) {
+			finger_press_changed = ts->finger_pressed ^ finger_pressed;
+			finger_release_changed = finger_press_changed & ts->finger_pressed;
+			finger_press_changed &= finger_pressed;
+			ts->finger_pressed = finger_pressed;
+		}
+
+		if(ts->debug_log_level & BIT(3)) {
+			for(i = 0; i < ts->finger_support; i++) {
+				if (finger_release_changed & BIT(i) ) {
+					uint32_t flip_flag = SYNAPTICS_FLIP_X;
+					uint8_t pos_mask = 0x0f;
+					for (j = 0; j < 2; j++) {
+						finger_data[i][j]
+							= (buf[base+2] & pos_mask) >> (j * 4) |
+							(uint16_t)buf[base + j] << 4;
+						if (ts->flags & flip_flag)
+							finger_data[i][j] = ts->max[j] - finger_data[i][j];
+						flip_flag <<= 1;
+						pos_mask <<= 4;
+					}
+					finger_data[i][2] = (buf[base+3] >> 4 & 0x0F) + (buf[base+3] & 0x0F);
+					finger_data[i][3] = buf[base+4];
+
+					if (ts->flags & SYNAPTICS_SWAP_XY)
+						swap(finger_data[i][0], finger_data[i][1]);
+
+					if (ts->layout[1] < finger_data[i][0])
+						finger_data[i][0] = ts->layout[1];
+					if(ts->width_factor && ts->height_factor){
+						printk(KERN_INFO
+							"[TP] Screen:F[%02d]:Up, X=%d, Y=%d, W=%d, Z=%d\n",
+							i+1, (finger_data[i][0]*ts->width_factor)>>SHIFT_BITS,
+							(finger_data[i][1]*ts->height_factor)>>SHIFT_BITS,
+							finger_data[i][2], finger_data[i][3]);
+					} else {
+						printk(KERN_INFO
+							"[TP] Raw:F[%02d]:Up, X=%d, Y=%d, W=%d, Z=%d\n",
+							i+1, finger_data[i][0], finger_data[i][1],
+							finger_data[i][2], finger_data[i][3]);
+					}
+				}
+				base += 5;
+			}
+		}
+
+		if (ts->htc_event == SYN_AND_REPORT_TYPE_B && finger_release_changed) {
+			for (i = 0; i < ts->finger_support; i++) {
+				if (finger_release_changed & BIT(i)) {
+					input_mt_slot(ts->input_dev, i);
+					input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, 0);
+					ts->tap_suppression &= ~BIT(i);
+				}
+			}
+		}
+
+		if (finger_pressed == 0 
+) {
+			if (ts->htc_event == SYN_AND_REPORT_TYPE_A) {
+				
+				if (ts->support_htc_event) {
+					input_report_abs(ts->input_dev, ABS_MT_AMPLITUDE, 0);
+					input_report_abs(ts->input_dev, ABS_MT_POSITION, 1 << 31);
+				}
+				input_mt_sync(ts->input_dev);
+			}
+			else if (ts->htc_event == SYN_AND_REPORT_TYPE_HTC) {
+				input_report_abs(ts->input_dev, ABS_MT_AMPLITUDE, 0);
+				input_report_abs(ts->input_dev, ABS_MT_POSITION, 1 << 31);
+			}
+
+#ifdef SYN_FILTER_CONTROL
+			if (ts->filter_level[0])
+				ts->ambiguous_state = 0;
+			ts->grip_b_suppression = 0;
+#endif
+			if (ts->reduce_report_level[0])
+				ts->tap_suppression = 0;
+			if (ts->debug_log_level & BIT(1))
+				printk(KERN_INFO "[TP] Finger leave\n");
+		}
+
+		if (ts->pre_finger_data[0][0] < 2 || finger_pressed) {
+			base = (ts->finger_support + 3) / 4;
+			for (i = 0; i < ts->finger_support; i++) {
+				uint32_t flip_flag = SYNAPTICS_FLIP_X;
+				if ((finger_pressed | finger_release_changed) & BIT(i)) {
+					uint8_t pos_mask = 0x0f;
+					for (j = 0; j < 2; j++) {
+						finger_data[i][j]
+							= (buf[base+2] & pos_mask) >> (j * 4) |
+							(uint16_t)buf[base + j] << 4;
+						if (ts->flags & flip_flag)
+							finger_data[i][j] = ts->max[j] - finger_data[i][j];
+						flip_flag <<= 1;
+						pos_mask <<= 4;
+					}
+					finger_data[i][2] = (buf[base+3] >> 4 & 0x0F) + (buf[base+3] & 0x0F);
+					finger_data[i][3] = buf[base+4];
+
+					if (ts->flags & SYNAPTICS_SWAP_XY)
+						swap(finger_data[i][0], finger_data[i][1]);
+
+					if (ts->layout[1] < finger_data[i][0])
+						finger_data[i][0] = ts->layout[1];
+
+					if ((finger_release_changed & BIT(i)) && ts->pre_finger_data[0][0] < 2) {
+						if (!ts->first_pressed) {
+							if (ts->finger_count == 0)
+								ts->first_pressed = 1;
+							printk(KERN_INFO "[TP] E%d@%d, %d\n", i + 1,
+							finger_data[i][0], finger_data[i][1]);
+						}
+					}
+#ifdef SYN_FILTER_CONTROL
+					if (abs((buf[base+3] >> 4 & 0x0F) - (buf[base+3] & 0x0F)) >= 10)
+						ts->grip_b_suppression |= BIT(i);
+
+					if (ts->filter_level[0] &&
+						((finger_press_changed | ts->grip_suppression) & BIT(i))) {
+						if ((finger_data[i][0] < (ts->filter_level[0] + ts->ambiguous_state * 20) ||
+							finger_data[i][0] > (ts->filter_level[3] - ts->ambiguous_state * 20)) &&
+							!(ts->grip_suppression & BIT(i))) {
+							ts->grip_suppression |= BIT(i);
+						} else if ((finger_data[i][0] < (ts->filter_level[1] + ts->ambiguous_state * 20) ||
+							finger_data[i][0] > (ts->filter_level[2] - ts->ambiguous_state * 20)) &&
+							(ts->grip_suppression & BIT(i)))
+							ts->grip_suppression |= BIT(i);
+						else if (finger_data[i][0] > (ts->filter_level[1] + ts->ambiguous_state * 20) &&
+							finger_data[i][0] < (ts->filter_level[2] - ts->ambiguous_state * 20)) {
+							ts->grip_suppression &= ~BIT(i);
+						}
+					}
+					if ((ts->grip_suppression | ts->grip_b_suppression) & BIT(i)) {
+						finger_pressed &= ~BIT(i);
+					} else
+#endif
+
+					if (ts->htc_event == SYN_AND_REPORT_TYPE_B && ts->reduce_report_level[0]) {
+						if (ts->tap_suppression & BIT(i) && finger_pressed & BIT(i)) {
+							int dx, dy = 0;
+							dx = abs(ts->pre_finger_data[i + 1][2] - finger_data[i][0]);
+							dy = abs(ts->pre_finger_data[i + 1][3] - finger_data[i][1]);
+							if (dx > ts->reduce_report_level[TAP_DX_OUTER] || dy > ts->reduce_report_level[TAP_DY_OUTER]) {
+								ts->tap_suppression &= ~BIT(i);
+							} else if (ts->reduce_report_level[TAP_TIMEOUT] && time_after(jiffies, ts->tap_timeout[i]) && (dx > ts->reduce_report_level[TAP_DX_INTER] || dy > ts->reduce_report_level[TAP_DY_INTER])) {
+								ts->tap_suppression &= ~BIT(i);
+							} else {
+								finger_pressed &= ~BIT(i);
+								if (ts->debug_log_level & (BIT(1) | BIT(3)))
+									printk(KERN_INFO
+										"[TP] Filtered Finger %d=> X:%d, Y:%d w:%d, z:%d\n",
+										i + 1, finger_data[i][0], finger_data[i][1],
+										finger_data[i][2], finger_data[i][3]);
+							}
+						}
+					}
+
+					if ((finger_pressed & BIT(i)) == BIT(i)) {
+						finger_pressed &= ~BIT(i);
+
+						if (ts->htc_event == SYN_AND_REPORT_TYPE_A) {
+							if (ts->support_htc_event) {
+								input_report_abs(ts->input_dev, ABS_MT_AMPLITUDE,
+									finger_data[i][3] << 16 | finger_data[i][2]);
+								input_report_abs(ts->input_dev, ABS_MT_POSITION,
+									(finger_pressed == 0) << 31 |
+									finger_data[i][0] << 16 | finger_data[i][1]);
+							}
+							input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID, i);
+							input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR,
+								finger_data[i][3]);
+							input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR,
+								finger_data[i][2]);
+							input_report_abs(ts->input_dev, ABS_MT_PRESSURE,
+								finger_data[i][2]);
+							input_report_abs(ts->input_dev, ABS_MT_POSITION_X,
+								finger_data[i][0]);
+							input_report_abs(ts->input_dev, ABS_MT_POSITION_Y,
+								finger_data[i][1]);
+							input_mt_sync(ts->input_dev);
+						} else if (ts->htc_event == SYN_AND_REPORT_TYPE_B) {
+							if (ts->support_htc_event) {
+								input_report_abs(ts->input_dev, ABS_MT_AMPLITUDE,
+									finger_data[i][3] << 16 | finger_data[i][2]);
+								input_report_abs(ts->input_dev, ABS_MT_POSITION,
+									(finger_pressed == 0) << 31 |
+									finger_data[i][0] << 16 | finger_data[i][1]);
+							}
+							input_mt_slot(ts->input_dev, i);
+							input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER,
+							1);
+							input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR,
+								finger_data[i][3]);
+							input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR,
+								finger_data[i][2]);
+							input_report_abs(ts->input_dev, ABS_MT_PRESSURE,
+								finger_data[i][2]);
+							input_report_abs(ts->input_dev, ABS_MT_POSITION_X,
+								finger_data[i][0]);
+							input_report_abs(ts->input_dev, ABS_MT_POSITION_Y,
+								finger_data[i][1]);
+						} else if (ts->htc_event == SYN_AND_REPORT_TYPE_HTC) {
+							input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID, i);
+							input_report_abs(ts->input_dev, ABS_MT_AMPLITUDE,
+								finger_data[i][3] << 16 | finger_data[i][2]);
+							input_report_abs(ts->input_dev, ABS_MT_POSITION,
+								(finger_pressed == 0) << 31 |
+								finger_data[i][0] << 16 | finger_data[i][1]);
+						}
+
+						if ((finger_press_changed & BIT(i)) && ts->debug_log_level & BIT(3)) {
+							if(ts->width_factor && ts->height_factor){
+								printk(KERN_INFO
+									"[TP] Screen:F[%02d]:Down, X=%d, Y=%d, W=%d, Z=%d\n",
+									i+1, (finger_data[i][0]*ts->width_factor)>>SHIFT_BITS,
+									(finger_data[i][1]*ts->height_factor)>>SHIFT_BITS,
+									finger_data[i][2], finger_data[i][3]);
+							} else {
+								printk(KERN_INFO
+									"[TP] Raw:F[%02d]:Down, X=%d, Y=%d, W=%d, Z=%d\n",
+									i+1, finger_data[i][0], finger_data[i][1],
+									finger_data[i][2], finger_data[i][3]);
+							}
+						}
+
+						if (ts->pre_finger_data[0][0] < 2) {
+							if (finger_press_changed & BIT(i)) {
+								ts->pre_finger_data[i + 1][0] = finger_data[i][0];
+								ts->pre_finger_data[i + 1][1] = finger_data[i][1];
+
+								if (!ts->first_pressed)
+									printk(KERN_INFO "[TP] S%d@%d, %d\n", i + 1,
+										finger_data[i][0], finger_data[i][1]);
+								if (ts->packrat_number < SYNAPTICS_FW_NOCAL_PACKRAT) {
+#ifdef SYN_CALIBRATION_CONTROL
+									if (ts->multitouch_calibration) {
+										if (ts->finger_count == ts->finger_support) {
+											ret = i2c_syn_write_byte_data(ts->client,
+												get_address_base(ts, 0x11, COMMAND_BASE), 0x01);
+											if (ret < 0)
+												i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "w:Rezero_1", __func__);
+											printk(KERN_INFO "[TP] %s: Touch Calibration Confirmed, rezero\n", __func__);
+										} else if (!ts->pre_finger_data[0][0] && ts->finger_count > 1)
+											ts->pre_finger_data[0][0] = 1;
+									}
+#endif
+								}
+							}
+						}
+
+						if (ts->htc_event == SYN_AND_REPORT_TYPE_B && ts->reduce_report_level[TAP_DX_OUTER]) {
+							if (finger_press_changed & BIT(i)) {
+								ts->tap_suppression &= ~BIT(i);
+								ts->tap_suppression |= BIT(i);
+								ts->pre_finger_data[i + 1][2] = finger_data[i][0];
+								ts->pre_finger_data[i + 1][3] = finger_data[i][1];
+								if (ts->reduce_report_level[TAP_TIMEOUT] && (ts->tap_suppression))
+									ts->tap_timeout[i] = jiffies + msecs_to_jiffies(ts->reduce_report_level[TAP_TIMEOUT]);
+							}
+						}
+
+						if (ts->debug_log_level & BIT(1))
+							printk(KERN_INFO
+								"[TP] Finger %d=> X:%d, Y:%d w:%d, z:%d\n",
+								i + 1, finger_data[i][0], finger_data[i][1],
+								finger_data[i][2], finger_data[i][3]);
+					}
+					if (ts->packrat_number < SYNAPTICS_FW_NOCAL_PACKRAT) {
+#ifdef SYN_CALIBRATION_CONTROL
+						if (ts->multitouch_calibration) {
+							if ((finger_release_changed & BIT(i)) && ts->pre_finger_data[0][0] == 1) {
+								ret = i2c_syn_write_byte_data(ts->client,
+									get_address_base(ts, 0x11, COMMAND_BASE), 0x01);
+								if (ret < 0)
+									i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "w:Rezero_2", __func__);
+								printk(KERN_INFO "[TP] %s: Touch Calibration Confirmed, rezero\n", __func__);
+							}
+						}
+#endif
+					}
+					if (!ts->finger_count)
+						ts->pre_finger_data[0][0] = 0;
+				}
+				base += 5;
+			}
+#ifdef SYN_FILTER_CONTROL
+			if (ts->filter_level[0] && ts->grip_suppression) {
+				ts->ambiguous_state = 0;
+				for (i = 0; i < ts->finger_support; i++)
+					if (ts->grip_suppression & BIT(i))
+						ts->ambiguous_state++;
+			}
+			if (ts->debug_log_level & BIT(16))
+				printk(KERN_INFO "[TP] ts->grip_suppression: %x, ts->ambiguous_state: %x\n",
+					ts->grip_suppression, ts->ambiguous_state);
+#endif
+		}
+	}
+	input_sync(ts->input_dev);
+
+}
+
+static void synaptics_ts_report_func(struct synaptics_ts_data *ts)
+{
+	int ret;
+	uint8_t data[2] = {0};
+
+	ret = i2c_syn_write(ts->client,
+		get_address_base(ts, 0x54, DATA_BASE) + 1, &data[0], 2);
+
+	if (ret < 0)
+		i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "w:1", __func__);
+	else {
+		ret = i2c_syn_read(ts->client,
+			get_address_base(ts, 0x54, DATA_BASE) + 3, ts->temp_report_data,
+			ts->x_channel * ts->y_channel * 2);
+		if (ret >= 0)
+			memcpy(&ts->report_data[0], &ts->temp_report_data[0], ts->x_channel * ts->y_channel * 2);
+		else {
+			memset(&ts->report_data[0], 0x0, sizeof(ts->report_data));
+			i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "r:2", __func__);
+		}
+	}
+	atomic_set(&ts->data_ready, 1);
+	wake_up(&syn_data_ready_wq);
+
+}
+
+static void synaptics_ts_button_func(struct synaptics_ts_data *ts)
+{
+	int ret;
+	uint8_t data = 0;
+	uint16_t x_position = 0, y_position = 0;
+
+	ret = i2c_syn_read(ts->client,
+		get_address_base(ts, 0x1A, DATA_BASE), &data, 1);
+	if (data) {
+		if (data & 0x01) {
+			printk("[TP] back key pressed\n");
+			vk_press = 1;
+			if (ts->button) {
+				if (ts->button[0].index) {
+					x_position = (ts->button[0].x_range_min + ts->button[0].x_range_max) / 2;
+					y_position = (ts->button[0].y_range_min + ts->button[0].y_range_max) / 2;
+				}
+			}
+			if (ts->htc_event == SYN_AND_REPORT_TYPE_A) {
+				input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID, 0);
+				input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR,
+					100);
+				input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR,
+					100);
+				input_report_abs(ts->input_dev, ABS_MT_PRESSURE,
+					100);
+				input_report_abs(ts->input_dev, ABS_MT_POSITION_X,
+					x_position);
+				input_report_abs(ts->input_dev, ABS_MT_POSITION_Y,
+					y_position);
+				input_mt_sync(ts->input_dev);
+			} else if (ts->htc_event == SYN_AND_REPORT_TYPE_B) {
+				input_mt_slot(ts->input_dev, 0);
+				input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER,
+				1);
+				input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR,
+					100);
+				input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR,
+					100);
+				input_report_abs(ts->input_dev, ABS_MT_PRESSURE,
+					100);
+				input_report_abs(ts->input_dev, ABS_MT_POSITION_X,
+					x_position);
+				input_report_abs(ts->input_dev, ABS_MT_POSITION_Y,
+					y_position);
+			}
+		}
+		else if (data & 0x02) {
+			printk("[TP] home key pressed\n");
+			vk_press = 1;
+			if (ts->button) {
+				if (ts->button[1].index) {
+					x_position = (ts->button[1].x_range_min + ts->button[1].x_range_max) / 2;
+					y_position = (ts->button[1].y_range_min + ts->button[1].y_range_max) / 2;
+				}
+			}
+			if (ts->htc_event == SYN_AND_REPORT_TYPE_A) {
+				input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID, 0);
+				input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR,
+					100);
+				input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR,
+					100);
+				input_report_abs(ts->input_dev, ABS_MT_PRESSURE,
+					100);
+				input_report_abs(ts->input_dev, ABS_MT_POSITION_X,
+					x_position);
+				input_report_abs(ts->input_dev, ABS_MT_POSITION_Y,
+					y_position);
+				input_mt_sync(ts->input_dev);
+			} else if (ts->htc_event == SYN_AND_REPORT_TYPE_B) {
+				input_mt_slot(ts->input_dev, 0);
+				input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER,
+				1);
+				input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR,
+					100);
+				input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR,
+					100);
+				input_report_abs(ts->input_dev, ABS_MT_PRESSURE,
+					100);
+				input_report_abs(ts->input_dev, ABS_MT_POSITION_X,
+					x_position);
+				input_report_abs(ts->input_dev, ABS_MT_POSITION_Y,
+					y_position);
+			}
+		}
+	}else {
+		printk("[TP] virtual key released\n");
+		vk_press = 0;
+		if (ts->htc_event == SYN_AND_REPORT_TYPE_A) {
+			if (ts->support_htc_event) {
+				input_report_abs(ts->input_dev, ABS_MT_AMPLITUDE, 0);
+				input_report_abs(ts->input_dev, ABS_MT_POSITION, 1 << 31);
+			}
+			input_mt_sync(ts->input_dev);
+		}
+		else if (ts->htc_event == SYN_AND_REPORT_TYPE_B) {
+			input_mt_slot(ts->input_dev, 0);
+			input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, 0);
+		}
+	}
+	input_sync(ts->input_dev);
+}
+
+static void synaptics_ts_status_func(struct synaptics_ts_data *ts)
+{
+	int ret;
+	uint8_t data = 0;
+
+	ret = i2c_syn_read(ts->client, get_address_base(ts, 0x01, DATA_BASE), &data, 1);
+	if (ret < 0) {
+		i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "r", __func__);
+	} else {
+		data &= 0x0F;
+		printk(KERN_INFO "[TP] Device Status = %x\n", data);
+		if (data == 1) {
+			mutex_lock(&syn_mutex);
+			ts->page_select = 0;
+			mutex_unlock(&syn_mutex);
+			printk(KERN_INFO "[TP] TOUCH: Page Select: %s: %d\n", __func__, ts->page_select);
+			ret = synaptics_init_panel(ts);
+			if (ret < 0)
+				printk(KERN_INFO "[TP]%s: synaptics_init_panel fail\n", __func__);
+		}
+	}
+
+}
+
+static void synaptics_ts_work_func(struct work_struct *work)
+{
+	struct synaptics_ts_data *ts = container_of(work, struct synaptics_ts_data, work);
+	int ret;
+	uint8_t buf = 0;
+	ret = i2c_syn_read(ts->client, get_address_base(ts, 0x01, DATA_BASE) + 1, &buf, 1);
+
+	if (ret < 0) {
+		i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "r", __func__);
+	} else {
+		if (buf & get_address_base(ts, 0x11, INTR_SOURCE))
+			synaptics_ts_finger_func(ts);
+		if (buf & get_address_base(ts, 0x01, INTR_SOURCE))
+			synaptics_ts_status_func(ts);
+		if (buf & get_address_base(ts, 0x54, INTR_SOURCE))
+			synaptics_ts_report_func(ts);
+	}
+
+}
+
+static irqreturn_t synaptics_irq_thread(int irq, void *ptr)
+{
+	struct synaptics_ts_data *ts = ptr;
+	int ret;
+	uint8_t buf = 0;
+	struct timespec timeStart, timeEnd, timeDelta;
+
+	if (ts->debug_log_level & BIT(2)) {
+			getnstimeofday(&timeStart);
+	}
+
+	ret = i2c_syn_read(ts->client, get_address_base(ts, 0x01, DATA_BASE) + 1, &buf, 1);
+
+	if (ret < 0) {
+		i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "r", __func__);
+	} else {
+		if (buf & get_address_base(ts, 0x1A, INTR_SOURCE)) {
+			if (!ts->finger_count)
+				synaptics_ts_button_func(ts);
+			else
+				printk("[TP] Ignore VK interrupt due to 2d points did not leave\n");
+		}
+		if (buf & get_address_base(ts, 0x11, INTR_SOURCE)) {
+			if (!vk_press) {
+				synaptics_ts_finger_func(ts);
+				if(ts->debug_log_level & BIT(2)) {
+					getnstimeofday(&timeEnd);
+					timeDelta.tv_nsec = (timeEnd.tv_sec*1000000000+timeEnd.tv_nsec)
+						-(timeStart.tv_sec*1000000000+timeStart.tv_nsec);
+					printk(KERN_INFO "[TP] Touch latency = %ld us\n", timeDelta.tv_nsec/1000);
+				}
+			}
+		}
+		if (buf & get_address_base(ts, 0x01, INTR_SOURCE))
+			synaptics_ts_status_func(ts);
+		if (buf & get_address_base(ts, 0x54, INTR_SOURCE))
+			synaptics_ts_report_func(ts);
+	}
+
+	return IRQ_HANDLED;
+}
+
+static enum hrtimer_restart synaptics_ts_timer_func(struct hrtimer *timer)
+{
+	struct synaptics_ts_data *ts = container_of(timer, struct synaptics_ts_data, timer);
+	queue_work(ts->syn_wq, &ts->work);
+	hrtimer_start(&ts->timer, ktime_set(0, 12500000), HRTIMER_MODE_REL);
+	return HRTIMER_NORESTART;
+}
+
+#ifdef SYN_CABLE_CONTROL
+static void cable_tp_status_handler_func(int connect_status)
+{
+	struct synaptics_ts_data *ts = gl_ts;
+	uint8_t data;
+	int ret;
+
+	printk(KERN_INFO "[TP] Touch: cable change to %d\n", connect_status);
+
+	if (connect_status)
+		connect_status = 1;
+	ret = i2c_syn_read(ts->client, get_address_base(ts, 0x01, CONTROL_BASE), &data, 1);
+	if (ret < 0) {
+		i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "r:1", __func__);
+	} else {
+		ts->cable_config = (data & 0xDF) | (connect_status << 5);
+		printk(KERN_INFO "[TP] %s: ts->cable_config: %x\n", __func__, ts->cable_config);
+		ret = i2c_syn_write_byte_data(ts->client,
+			get_address_base(ts, 0x01, CONTROL_BASE), ts->cable_config);
+		if (ret < 0) {
+			i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "w:2", __func__);
+		}
+	}
+}
+static struct t_usb_status_notifier cable_status_handler = {
+	.name = "usb_tp_connected",
+	.func = cable_tp_status_handler_func,
+};
+#endif
+
+static void synaptics_ts_close_psensor_func(struct work_struct *work)
+{
+	struct synaptics_ts_data *ts = container_of(work, struct synaptics_ts_data, psensor_work);
+	if(ts->psensor_resume_enable == 1) {
+		printk(KERN_INFO "[TP] %s: Disable P-sensor by Touch\n", __func__);
+		psensor_enable_by_touch_driver(0);
+		ts->psensor_resume_enable = 0;
+	}
+}
+
+static int psensor_tp_status_handler_func(struct notifier_block *this,
+	unsigned long status, void *unused)
+{
+	struct synaptics_ts_data *ts = gl_ts;
+	int ret;
+
+	printk(KERN_INFO "[TP] psensor status %d -> %lu\n",
+		ts->psensor_status, status);
+
+	if(ts->psensor_detection) {
+		if(status == 3 && ts->psensor_resume_enable >= 1) {
+			if(!(ts->psensor_status==1 && ts->psensor_resume_enable==1)) {
+				ret = i2c_syn_write_byte_data(ts->client, get_address_base(ts, 0x11, COMMAND_BASE), 0x01);
+				if (ret < 0)
+					i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "w:Rezero_1", __func__);
+				printk(KERN_INFO "[TP] %s: Touch Calibration Confirmed, rezero\n", __func__);
+			}
+
+			if(ts->psensor_resume_enable == 1)
+				queue_work(ts->syn_psensor_wq, &ts->psensor_work);
+			else
+				ts->psensor_resume_enable = 0;
+		}
+	}
+
+	if (ts->psensor_status == 0) {
+		if (status == 1)
+			ts->psensor_status = status;
+		else
+			ts->psensor_status = 0;
+	} else
+		ts->psensor_status = status;
+
+	if(ts->psensor_detection) {
+		if(ts->psensor_status == 0) {
+			ts->psensor_resume_enable = 0;
+			ts->psensor_phone_enable = 0;
+		}
+	}
+
+	return NOTIFY_OK;
+}
+
+static struct notifier_block psensor_status_handler = {
+	.notifier_call = psensor_tp_status_handler_func,
+};
+
+static int syn_pdt_scan(struct synaptics_ts_data *ts, int num_page)
+{
+	uint8_t intr_count = 0, data[6] = {0}, num_function[SYN_MAX_PAGE] = {0};
+	uint16_t i, j, k = 0;
+	int ret = 0;
+	ts->num_function = 0;
+
+	for (i = 0; i < num_page; i++) {
+		for (j = (0xEE | (i << 8)); j >= (0xBE | (i << 8)); j -= 6) {
+			ret = i2c_syn_read(ts->client, j, data, 1);
+			if (ret < 0)
+				return i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "r1", __func__);
+			if (data[0] == 0)
+				break;
+			else
+				num_function[i]++;
+		}
+		ts->num_function += num_function[i];
+	}
+
+	if (ts->address_table == NULL) {
+		ts->address_table = kzalloc(sizeof(struct function_t) * ts->num_function, GFP_KERNEL);
+		if (ts->address_table == NULL) {
+			printk(KERN_INFO "[TP] syn_pdt_scan: memory allocate fail\n");
+			return -ENOMEM;
+		}
+		printk(KERN_INFO "[TP] syn_pdt_scan: memory allocate success. ptr: %p\n", ts->address_table);
+	}
+
+	printk(KERN_INFO "[TP] synaptics: %d function supported\n", ts->num_function);
+	for (i = 0; i < num_page; i++) {
+		for (j = 0; j < num_function[i]; j++) {
+			ret = i2c_syn_read(ts->client, i << 8 | (0xE9 - 6*j), data, 6);
+			if (ret < 0)
+				return i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "r:2", __func__);
+			ts->address_table[j + k].query_base = i << 8 | data[0];
+			ts->address_table[j + k].command_base = i << 8 | data[1];
+			ts->address_table[j + k].control_base = i << 8 | data[2];
+			ts->address_table[j + k].data_base = i << 8 | data[3];
+			if (data[4] & 0x07) {
+				ts->address_table[j + k].interrupt_source =
+					get_int_mask(data[4] & 0x07, intr_count);
+				intr_count += (data[4] & 0x07);
+			}
+			ts->address_table[j + k].function_type = data[5];
+			printk(KERN_INFO
+				"Query: %2.2X, Command: %4.4X, Control: %2X, Data: %2X, INTR: %2X, Funtion: %2X\n",
+				ts->address_table[j + k].query_base , ts->address_table[j + k].command_base,
+				ts->address_table[j + k].control_base, ts->address_table[j + k].data_base,
+				ts->address_table[j + k].interrupt_source, ts->address_table[j + k].function_type);
+		}
+		k += num_function[i];
+	}
+	return ts->num_function;
+}
+static int syn_get_version(struct synaptics_ts_data *ts)
+{
+	uint8_t data[16] = {0};
+	int ret = 0;
+	ret = i2c_syn_read(ts->client, get_address_base(ts, 0x01, QUERY_BASE) + 17, data, 4);
+	if (ret < 0)
+		return i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "r:1", __func__);
+	ts->package_id = data[1] << 8 | data[0];
+	printk(KERN_INFO "[TP] %s: package_id: %d\n", __func__, ts->package_id);
+
+	ret = i2c_syn_read(ts->client, get_address_base(ts, 0x01, QUERY_BASE) + 18, data, 3);
+	if (ret < 0)
+		return i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "r:3", __func__);
+	ts->packrat_number = data[2] << 16 | data[1] << 8 | data[0];
+	printk(KERN_INFO "[TP] %s: packrat_number: %d\n", __func__, ts->packrat_number);
+
+	if (ts->packrat_number < SYNAPTICS_FW_3_2_PACKRAT) {
+
+		ret = i2c_syn_read(ts->client, get_address_base(ts, 0x01, QUERY_BASE) + 16, data, 3);
+		if (ret < 0)
+			return i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "r:2", __func__);
+		syn_panel_version = data[0] << 8 | data[2];
+		printk(KERN_INFO "[TP] %s: panel_version: %x\n", __func__, syn_panel_version);
+
+	} else {
+
+		ret = i2c_syn_read(ts->client, get_address_base(ts, 0x01, QUERY_BASE) + 28, data, 16);
+		if (ret < 0)
+			return i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "r:2", __func__);
+		syn_panel_version = data[5] << 8 | data[7];
+		printk(KERN_INFO "[TP] %s: panel_version: %x\n", __func__, syn_panel_version);
+	}
+
+	ret = i2c_syn_read(ts->client, get_address_base(ts, 0x34, CONTROL_BASE), data, 4);
+	if (ret < 0)
+		return i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "r:4", __func__);
+	ts->config_version = data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3];
+	printk(KERN_INFO "[TP] %s: config version: %x\n", __func__, ts->config_version);
+
+	return 0;
+}
+
+static int syn_get_information(struct synaptics_ts_data *ts)
+{
+	uint8_t data[4] = {0}, i, num_channel, *buf;
+	int ret = 0;
+	ret = i2c_syn_read(ts->client, get_address_base(ts, 0x11, QUERY_BASE) + 1, data, 1);
+	if (ret < 0)
+		return i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "r:1", __func__);
+	if ((data[0] & 0x07) == 5)
+		ts->finger_support = 10;
+	else if ((data[0] & 0x07) < 5)
+		ts->finger_support = (data[0] & 0x07) + 1;
+	else {
+		printk(KERN_INFO "[TP] %s: number of fingers not define: %x\n",
+			__func__, data[0] & 0x07);
+		return SYN_PROCESS_ERR;
+	}
+
+	printk(KERN_INFO "[TP] %s: finger_support: %d\n", __func__, ts->finger_support);
+
+	ret = i2c_syn_read(ts->client, get_address_base(ts, 0x11, CONTROL_BASE) + 6, data, 4);
+	if (ret < 0)
+		return i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "r:2", __func__);
+
+	ts->max[0] = data[0] | data[1] << 8;
+	ts->max[1] = data[2] | data[3] << 8;
+	printk(KERN_INFO "[TP] %s: max_x: %d, max_y: %d\n", __func__, ts->max[0], ts->max[1]);
+
+	if (get_address_base(ts, 0x54, FUNCTION)) {
+		ret = i2c_syn_read(ts->client, get_address_base(ts, 0x54, QUERY_BASE), data, 2);
+		if (ret < 0)
+			return i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "r:3", __func__);
+
+		ts->y_channel = data[0];
+		ts->x_channel = data[1];
+
+		num_channel = ts->y_channel + ts->x_channel;
+		buf = kzalloc(num_channel + 1, GFP_KERNEL);
+		if (buf == NULL) {
+			printk(KERN_INFO "[TP] %s: memory allocate fail\n", __func__);
+			return -ENOMEM;
+		}
+		if (ts->packrat_number < SYNAPTICS_FW_3_2_PACKRAT)
+			ret = i2c_syn_read(ts->client, get_address_base(ts, 0x54, CONTROL_BASE) + 17,
+				buf, num_channel + 1);
+		else
+			ret = i2c_syn_read(ts->client, get_address_base(ts, 0x55, CONTROL_BASE),
+				buf, num_channel + 1);
+		if (ret < 0) {
+			kfree(buf);
+			return i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "r:4", __func__);
+		}
+
+		for (i = 1; i < num_channel + 1; i++) {
+			if (buf[i] == 0xFF) {
+				if (i <= num_channel - ts->x_channel)
+					ts->y_channel--;
+				else
+					ts->x_channel--;
+			}
+		}
+
+		if (buf[0] & 0x01)
+			swap(ts->y_channel, ts->x_channel);
+		printk(KERN_INFO "[TP] %s: X: %d, Y: %d\n", __func__,
+			ts->x_channel, ts->y_channel);
+		kfree(buf);
+
+		ts->temp_report_data = kzalloc(2 * ts->x_channel * ts->y_channel, GFP_KERNEL);
+		ts->report_data = kzalloc(2 * ts->x_channel * ts->y_channel, GFP_KERNEL);
+		if(ts->temp_report_data == NULL || ts->report_data == NULL)
+			return -ENOMEM;
+
+		ret = i2c_syn_read(ts->client,
+			get_address_base(ts, 0x54, CONTROL_BASE) + 0x10, &ts->relaxation, 1);
+		if (ret < 0)
+			return i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "r:5", __func__);
+		printk(KERN_INFO "[TP] %s: ts->relaxation: %d\n", __func__, ts->relaxation);
+
+	}
+	if (ts->packrat_number < SYNAPTICS_FW_NOCAL_PACKRAT) {
+		if (ts->large_obj_check) {
+			if (ts->package_id == 2200) {
+				ret = i2c_syn_read(ts->client,
+					get_address_base(ts, 0x11, CONTROL_BASE) + 0x26, &ts->default_large_obj, 1);
+			} else {
+				ret = i2c_syn_read(ts->client,
+					get_address_base(ts, 0x11, CONTROL_BASE) + 0x29, &ts->default_large_obj, 1);
+			}
+			if (ret < 0)
+					return i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "r:6", __func__);
+			printk(KERN_INFO "[TP] %s: ts->default_large_obj: %x\n", __func__, ts->default_large_obj);
+		}
+
+		if (ts->segmentation_bef_unlock) {
+			if (ts->package_id == 2200) {
+				ret = i2c_syn_read(ts->client,
+					get_address_base(ts, 0x11, CONTROL_BASE) + 0x25, &ts->segmentation_aft_unlock, 1);
+
+			} else {
+				ret = i2c_syn_read(ts->client,
+					get_address_base(ts, 0x11, CONTROL_BASE) + 0x22, &ts->segmentation_aft_unlock, 1);
+			}
+			if (ret < 0)
+				return i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "r:7", __func__);
+			printk(KERN_INFO "[TP] %s: ts->segmentation_aft_unlock: %x\n", __func__, ts->segmentation_aft_unlock);
+		}
+
+		if (ts->threshold_bef_unlock) {
+			if (ts->package_id == 2200) {
+				ret = i2c_syn_read(ts->client,
+					get_address_base(ts, 0x11, CONTROL_BASE) + 0x0A, &ts->threshold_aft_unlock, 1);
+
+			} else {
+				ret = i2c_syn_read(ts->client,
+					get_address_base(ts, 0x11, CONTROL_BASE) + 0x0C, &ts->threshold_aft_unlock, 1);
+			}
+			if (ret < 0)
+				return i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "r:8", __func__);
+			printk(KERN_INFO "[TP] %s: ts->z_threshold_aft_unlock: %x\n", __func__, ts->threshold_aft_unlock);
+		}
+
+		if (ts->saturation_bef_unlock) {
+			ret = i2c_syn_read(ts->client,
+				get_address_base(ts, 0x54, CONTROL_BASE) + 0x02, data, 2);
+			if (ret < 0)
+				return i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "r:8", __func__);
+			ts->saturation_aft_unlock = (data[1] << 8) | data[0];
+			printk(KERN_INFO "[TP] %s: ts->saturation_aft_unlock: %x\n", __func__, ts->saturation_aft_unlock);
+		}
+
+		if (ts->PixelTouchThreshold_bef_unlock) {
+			ret = i2c_syn_read(ts->client,
+				get_address_base(ts, 0x54, CONTROL_BASE) + 0x04, &ts->PixelTouchThreshold_aft_unlock, 1);
+			if (ret < 0)
+				return i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "r:9", __func__);
+			printk(KERN_INFO "[TP] %s: ts->PixelTouchThreshold_aft_unlock: %x\n", __func__, ts->PixelTouchThreshold_aft_unlock);
+		}
+	}
+
+	return 0;
+}
+
+static int synaptics_ts_probe(
+	struct i2c_client *client, const struct i2c_device_id *id)
+{
+	struct synaptics_ts_data *ts;
+	uint8_t i;
+	int ret = 0;
+	struct synaptics_i2c_rmi_platform_data *pdata;
+	uint8_t data = 0;
+
+	printk(KERN_INFO "[TP] %s: enter", __func__);
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+		printk(KERN_ERR "[TP] TOUCH_ERR: synaptics_ts_probe: need I2C_FUNC_I2C\n");
+		ret = -ENODEV;
+		goto err_check_functionality_failed;
+	}
+
+	ts = kzalloc(sizeof(*ts), GFP_KERNEL);
+	if (ts == NULL) {
+		ret = -ENOMEM;
+		goto err_alloc_data_failed;
+	}
+	ts->client = client;
+	i2c_set_clientdata(client, ts);
+	pdata = client->dev.platform_data;
+
+	if (pdata == NULL) {
+		printk(KERN_INFO "[TP] pdata is NULL\n");
+		goto err_get_platform_data_fail;
+	}
+
+	ret = i2c_syn_read(ts->client, 0x00EE, &data, 1);
+	if (ret < 0) {
+		printk(KERN_INFO "[TP] No Synaptics chip\n");
+		goto err_detect_failed;
+	}
+
+	for (i = 0; i < 10; i++) {
+		ret = i2c_syn_read(ts->client, SYN_F01DATA_BASEADDR, &data, 1);
+		if (ret < 0) {
+			i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "read device status failed!", __func__);
+			goto err_detect_failed;
+		}
+		if (data & 0x44) {
+			msleep(20);
+#ifdef SYN_FLASH_PROGRAMMING_LOG
+			printk(KERN_INFO "[TP] synaptics probe: F01_data: %x touch controller stay in bootloader mode!\n", data);
+#endif
+		} else if (data & 0x40) {
+			printk(KERN_ERR "[TP] TOUCH_ERR: synaptics probe: F01_data: %x touch controller stay in bootloader mode!\n", data);
+			goto err_detect_failed;
+		} else
+			break;
+	}
+
+	if (i == 10) {
+		uint8_t num = 0;
+		printk(KERN_INFO "[TP] synaptics probe: touch controller doesn't enter UI mode! F01_data: %x\n", data);
+
+		if (syn_pdt_scan(ts, SYN_BL_PAGE) < 0) {
+			printk(KERN_ERR "[TP] TOUCH_ERR: PDT scan fail\n");
+			goto err_init_failed;
+		}
+
+		if (pdata) {
+			while (pdata->default_config != 1) {
+				if (pdata->default_config == 0) {
+					printk(KERN_ERR "[TP] TOUCH_ERR: touch controller stays in bootloader mode "
+						"and recovery method doesn't enable\n");
+					goto err_init_failed;
+				}
+				pdata++;
+				num++;
+			}
+			ts->config = pdata->config;
+
+			ret = syn_config_update(ts, pdata->gpio_irq);
+			if (ret < 0) {
+				printk(KERN_ERR "[TP] TOUCH_ERR: syn_config_update fail\n");
+				goto err_init_failed;
+			} else if (ret == 0)
+				printk(KERN_INFO "[TP] syn_config_update success\n");
+			else
+				printk(KERN_INFO "[TP] Warning: syn_config_update: the same "
+					"config version and CRC but touch controller always stay in bootloader mode\n");
+			pdata = pdata - num;
+		}
+
+		if (ts->address_table != NULL) {
+			kfree(ts->address_table);
+			ts->address_table = NULL;
+		}
+	}
+
+	if (syn_pdt_scan(ts, SYN_MAX_PAGE) < 0) {
+		printk(KERN_ERR "[TP] TOUCH_ERR: PDT scan fail\n");
+		goto err_init_failed;
+	}
+
+	if (syn_get_version(ts) < 0) {
+		printk(KERN_ERR "[TP] TOUCH_ERR: syn_get_version fail\n");
+		goto err_init_failed;
+	}
+
+	if (pdata) {
+		while (pdata->packrat_number && pdata->packrat_number > ts->packrat_number) {
+			pdata++;
+		}
+
+		if (pdata->tw_pin_mask) {
+			ts->tw_pin_mask = pdata->tw_pin_mask;
+			ret = syn_get_tw_vendor(ts, pdata->gpio_irq);
+			if (ret < 0) {
+				printk(KERN_ERR "[TP] TOUCH_ERR: syn_get_tw_vendor fail\n");
+				goto err_init_failed;
+			}
+		}
+
+		while (pdata->sensor_id > 0 && pdata->sensor_id != (SENSOR_ID_CHECKING_EN | ts->tw_vendor)) {
+			pdata++;
+		}
+
+		printk(KERN_INFO "[TP] synaptics_ts_probe: pdata->version = %x, pdata->packrat_number = %d,"
+				" pdata->sensor_id = %x\n", pdata->version, pdata->packrat_number, pdata->sensor_id);
+
+		if (!pdata->packrat_number) {
+			printk(KERN_ERR "[TP] TOUCH_ERR: get null platform data\n");
+				goto err_init_failed;
+		}
+
+		ts->power = pdata->power;
+		ts->flags = pdata->flags;
+		ts->htc_event = pdata->report_type;
+		ts->filter_level = pdata->filter_level;
+		ts->reduce_report_level = pdata->reduce_report_level;
+		ts->gpio_irq = pdata->gpio_irq;
+		ts->gpio_reset = pdata->gpio_reset;
+		ts->large_obj_check = pdata->large_obj_check;
+		ts->support_htc_event = pdata->support_htc_event;
+		ts->mfg_flag = pdata->mfg_flag;
+		ts->segmentation_bef_unlock = pdata->segmentation_bef_unlock;
+		ts->i2c_err_handler_en = pdata->i2c_err_handler_en;
+		ts->threshold_bef_unlock = pdata->threshold_bef_unlock;
+		ts->saturation_bef_unlock = pdata->saturation_bef_unlock;
+		ts->energy_ratio_relaxation = pdata->energy_ratio_relaxation;
+		ts->multitouch_calibration = pdata->multitouch_calibration;
+		ts->psensor_detection = pdata->psensor_detection;
+		ts->PixelTouchThreshold_bef_unlock = pdata->PixelTouchThreshold_bef_unlock;
+#ifdef SYN_CABLE_CONTROL
+		ts->cable_support = pdata->cable_support; 
+#endif
+		ts->config = pdata->config;
+		if (pdata->virtual_key)
+			ts->button = pdata->virtual_key;
+	}
+
+#ifndef SYN_DISABLE_CONFIG_UPDATE
+	ret = syn_config_update(ts, pdata->gpio_irq);
+	if (ret < 0) {
+		printk(KERN_ERR "[TP] TOUCH_ERR: syn_config_update fail\n");
+		goto err_init_failed;
+	} else if (ret == 0)
+		printk(KERN_INFO "[TP] syn_config_update success\n");
+	else
+		printk(KERN_INFO "[TP] syn_config_update: the same config version and CRC\n");
+#else
+	if (pdata->tw_pin_mask) {
+		ret = disable_flash_programming(ts, 0);
+		if (ret < 0) {
+			printk(KERN_ERR "[TP] TOUCH_ERR: disable_flash_programming fail\n");
+			goto err_init_failed;
+		}
+	}
+#endif
+	if (syn_pdt_scan(ts, SYN_MAX_PAGE) < 0) {
+		printk(KERN_ERR "[TP] TOUCH_ERR: PDT scan fail\n");
+		goto err_init_failed;
+	}
+
+#ifndef SYN_DISABLE_CONFIG_UPDATE
+	if (pdata->customer_register[CUS_REG_BASE]) {
+		ret = i2c_syn_write(ts->client, pdata->customer_register[CUS_REG_BASE],
+			&pdata->customer_register[CUS_BALLISTICS_CTRL], CUS_REG_SIZE - 1);
+		printk(KERN_INFO "[TP] Loads customer register\n");
+	}
+#endif
+
+	if (syn_get_information(ts) < 0) {
+		printk(KERN_ERR "[TP] TOUCH_ERR: syn_get_information fail\n");
+		goto err_syn_get_info_failed;
+	}
+
+	if (pdata->abs_x_max  == 0 && pdata->abs_y_max == 0) {
+		ts->layout[0] = ts->layout[2] = 0;
+		ts->layout[1] = ts->max[0];
+		ts->layout[3] = ts->max[1];
+	} else {
+		ts->layout[0] = pdata->abs_x_min;
+		ts->layout[1] = pdata->abs_x_max;
+		ts->layout[2] = pdata->abs_y_min;
+		ts->layout[3] = pdata->abs_y_max;
+	}
+
+	if(pdata->display_width && pdata->display_height){
+		printk(KERN_INFO "[TP] Load display resolution: %dx%d\n", pdata->display_width, pdata->display_height);
+		ts->width_factor = (pdata->display_width<<SHIFT_BITS)/(ts->layout[1]-ts->layout[0]);
+		ts->height_factor = (pdata->display_height<<SHIFT_BITS)/(ts->layout[3]-ts->layout[2]);
+	}
+
+	if(get_tamper_sf()==0) {
+		ts->debug_log_level |= BIT(3);
+		printk(KERN_INFO "[TP] Debug log level=0x%02X\n", ts->debug_log_level);
+	}
+
+	if (get_address_base(ts, 0x19, FUNCTION)) {
+		ret = i2c_syn_read(ts->client, get_address_base(ts, 0x19, QUERY_BASE) + 1,
+			&ts->key_number, 1);
+		if (ret < 0) {
+			i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "F19 Query fail", __func__);
+			goto err_F19_query_failed;
+		}
+		for (i = 0; i < ts->key_number; i++) {
+			ts->key_postion_x[i] =
+				(ts->layout[1] - ts->layout[0]) * (i * 2 + 1) / (ts->key_number * 2)
+				+ ts->layout[0];
+			printk(KERN_INFO "[TP] ts->key_postion_x[%d]: %d\n",
+				i, ts->key_postion_x[i]);
+		}
+		ts->key_postion_y = ts->layout[2] +
+			(21 * (ts->layout[3] - ts->layout[2]) / 20);
+		printk(KERN_INFO "[TP] ts->key_postion_y: %d\n", ts->key_postion_y);
+	}
+
+	ret = synaptics_init_panel(ts);
+	if (ret < 0) {
+		printk(KERN_ERR "[TP] TOUCH_ERR: synaptics_init_panel fail\n");
+		goto err_init_panel_failed;
+	}
+
+	init_waitqueue_head(&syn_data_ready_wq);
+
+	if(ts->psensor_detection) {
+		INIT_WORK(&ts->psensor_work, synaptics_ts_close_psensor_func);
+		ts->syn_psensor_wq = create_singlethread_workqueue("synaptics_psensor_wq");
+		if (!ts->syn_psensor_wq)
+			goto err_create_wq_failed;
+	}
+
+	ret = synaptics_input_register(ts);
+	if (ret) {
+		printk(KERN_ERR "[TP] TOUCH_ERR: synaptics_ts_probe: "
+				"Unable to register %s input device\n",
+				ts->input_dev->name);
+		goto err_input_register_device_failed;
+	}
+
+	gl_ts = ts;
+
+	ts->irq_enabled = 0;
+	if (client->irq) {
+		ts->use_irq = 1;
+		ret = request_threaded_irq(client->irq, NULL, synaptics_irq_thread,
+			IRQF_TRIGGER_LOW | IRQF_ONESHOT, client->name, ts);
+		if (ret == 0) {
+			ts->irq_enabled = 1;
+			ret = i2c_syn_read(ts->client,
+				get_address_base(ts, 0x01, CONTROL_BASE) + 1, &ts->intr_bit, 1);
+			if (ret < 0) {
+				free_irq(client->irq, ts);
+				i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "get interrupt bit failed", __func__);
+				goto err_get_intr_bit_failed;
+			}
+			printk(KERN_INFO "[TP] %s: interrupt enable: %x\n", __func__, ts->intr_bit);
+		} else {
+			dev_err(&client->dev, "[TP] TOUCH_ERR: request_irq failed\n");
+			ts->use_irq = 0;
+		}
+	}
+
+	if (!ts->use_irq) {
+
+		ts->syn_wq = create_singlethread_workqueue("synaptics_wq");
+		if (!ts->syn_wq)
+			goto err_create_wq_failed;
+
+		INIT_WORK(&ts->work, synaptics_ts_work_func);
+
+		hrtimer_init(&ts->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+		ts->timer.function = synaptics_ts_timer_func;
+		hrtimer_start(&ts->timer, ktime_set(1, 0), HRTIMER_MODE_REL);
+	}
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	ts->early_suspend.level = EARLY_SUSPEND_LEVEL_STOP_DRAWING - 1;
+	ts->early_suspend.suspend = synaptics_ts_early_suspend;
+	ts->early_suspend.resume = synaptics_ts_late_resume;
+	register_early_suspend(&ts->early_suspend);
+#endif
+
+#ifdef SYN_CABLE_CONTROL
+	if (ts->cable_support) {
+		usb_register_notifier(&cable_status_handler);
+		
+		ret = i2c_syn_read(ts->client,
+			get_address_base(ts, 0x11, CONTROL_BASE), &ts->cable_config, 1);
+		if (ret < 0) {
+			printk(KERN_ERR "[TP] TOUCH_ERR: get cable config failed\n");
+			goto err_get_cable_config_failed;
+		}
+		if (usb_get_connect_type())
+			cable_tp_status_handler_func(1);
+		printk(KERN_INFO "[TP] %s: ts->cable_config: %x\n", __func__, ts->cable_config);
+	}
+#endif
+	register_notifier_by_psensor(&psensor_status_handler);
+	synaptics_touch_sysfs_init();
+#ifdef SYN_WIRELESS_DEBUG
+	if (rmi_char_dev_register())
+		printk(KERN_INFO "[TP] %s: error register char device", __func__);
+#endif
+
+	printk(KERN_INFO "[TP] synaptics_ts_probe: Start touchscreen %s in %s mode\n", ts->input_dev->name, ts->use_irq ? "interrupt" : "polling");
+
+	return 0;
+
+#ifdef SYN_CABLE_CONTROL
+err_get_cable_config_failed:
+	if (ts->use_irq)
+		free_irq(client->irq, ts);
+	else
+		destroy_workqueue(ts->syn_wq);
+#endif
+
+err_create_wq_failed:
+
+err_get_intr_bit_failed:
+err_input_register_device_failed:
+	input_free_device(ts->input_dev);
+
+err_init_panel_failed:
+err_F19_query_failed:
+err_syn_get_info_failed:
+	if(ts->report_data != NULL)
+		kfree(ts->report_data);
+	if(ts->temp_report_data != NULL)
+		kfree(ts->temp_report_data);
+err_init_failed:
+	if(ts->address_table != NULL)
+		kfree(ts->address_table);
+err_detect_failed:
+err_get_platform_data_fail:
+	kfree(ts);
+
+err_alloc_data_failed:
+err_check_functionality_failed:
+	return ret;
+}
+
+static int synaptics_ts_remove(struct i2c_client *client)
+{
+	struct synaptics_ts_data *ts = i2c_get_clientdata(client);
+	unregister_early_suspend(&ts->early_suspend);
+	if (ts->use_irq)
+		free_irq(client->irq, ts);
+	else {
+		hrtimer_cancel(&ts->timer);
+		if (ts->syn_wq)
+			destroy_workqueue(ts->syn_wq);
+	}
+	if(ts->sr_input_dev != NULL)
+		input_unregister_device(ts->sr_input_dev);
+	input_unregister_device(ts->input_dev);
+
+	synaptics_touch_sysfs_remove();
+
+	if(ts->report_data != NULL)
+		kfree(ts->report_data);
+	if(ts->temp_report_data != NULL)
+		kfree(ts->temp_report_data);
+	if(ts->address_table != NULL)
+		kfree(ts->address_table);
+	kfree(ts);
+	return 0;
+}
+
+static int synaptics_ts_suspend(struct i2c_client *client, pm_message_t mesg)
+{
+	int ret;
+	struct synaptics_ts_data *ts = i2c_get_clientdata(client);
+	printk(KERN_INFO "[TP] %s: enter\n", __func__);
+
+	if (ts->use_irq) {
+		disable_irq(client->irq);
+		ts->irq_enabled = 0;
+	} else {
+		hrtimer_cancel(&ts->timer);
+		ret = cancel_work_sync(&ts->work);
+	}
+
+	if(ts->psensor_detection) {
+		if(ts->psensor_resume_enable == 1){
+			printk(KERN_INFO "[TP] %s: Disable P-sensor by Touch\n", __func__);
+			psensor_enable_by_touch_driver(0);
+			ts->psensor_resume_enable = 0;
+		}
+	}
+
+	if (ts->psensor_status == 0) {
+		ts->pre_finger_data[0][0] = 0;
+		if (ts->packrat_number < SYNAPTICS_FW_NOCAL_PACKRAT) {
+			ts->first_pressed = 0;
+#ifdef SYN_CALIBRATION_CONTROL
+			if (ts->mfg_flag != 1) {
+				ret = i2c_syn_write_byte_data(ts->client,
+					get_address_base(ts, 0x54, CONTROL_BASE) + 0x10, ts->relaxation);
+				if (ret < 0)
+					i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "fast relaxation", __func__);
+
+				if (ts->energy_ratio_relaxation) {
+					ret = i2c_syn_write_byte_data(ts->client,
+						get_address_base(ts, 0x54, CONTROL_BASE), 0x20);
+					if (ret < 0)
+						i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "energy ratio relaxation", __func__);
+				}
+
+				if (ts->saturation_bef_unlock) {
+					ret = i2c_syn_write_byte_data(ts->client,
+						get_address_base(ts, 0x54, CONTROL_BASE) + 0x02, ts->saturation_bef_unlock & 0xFF);
+					if (ret < 0)
+						return i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "saturation capacitance", __func__);
+					ret = i2c_syn_write_byte_data(ts->client,
+						get_address_base(ts, 0x54, CONTROL_BASE) + 0x03, (ts->saturation_bef_unlock & 0xFF00) >> 8);
+					if (ret < 0)
+						return i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "saturation capacitance", __func__);
+					printk(KERN_INFO "[TP] touch suspend, saturation capacitance: %x\n", ts->saturation_bef_unlock);
+				}
+
+				if ( ts->PixelTouchThreshold_bef_unlock ) {
+					ret = i2c_syn_write_byte_data(ts->client,
+						get_address_base(ts, 0x54, CONTROL_BASE) + 0x04, ts->PixelTouchThreshold_bef_unlock );
+					if (ret < 0)
+						return i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "F54_ANALOG_CTRL03 Pixel Touch Threshold", __func__);
+					printk(KERN_INFO "[TP] touch suspend, set F54_ANALOG_CTRL03 Pixel Touch Threshold: %x\n", ts->PixelTouchThreshold_bef_unlock);
+				}
+
+				ret = i2c_syn_write_byte_data(ts->client,
+					get_address_base(ts, 0x54, COMMAND_BASE), 0x04);
+				if (ret < 0)
+					i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "force update", __func__);
+				printk(KERN_INFO "[TP] touch suspend, fast relasxation: %x\n", ts->relaxation);
+			}
+#endif
+
+			if (ts->large_obj_check) {
+				if (ts->package_id == 2200) {
+					ret = i2c_syn_write_byte_data(ts->client,
+						get_address_base(ts, 0x11, CONTROL_BASE) + 0x26, ts->default_large_obj & 0x7F);
+
+				} else {
+					ret = i2c_syn_write_byte_data(ts->client,
+						get_address_base(ts, 0x11, CONTROL_BASE) + 0x29, ts->default_large_obj & 0x7F);
+				}
+				if (ret < 0)
+					i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "large obj suppression", __func__);
+				printk(KERN_INFO "[TP] touch suspend, set large obj suppression: %x\n", ts->default_large_obj & 0x7F);
+			}
+
+			if (ts->segmentation_bef_unlock) {
+				if (ts->package_id == 2200) {
+					ret = i2c_syn_write_byte_data(ts->client,
+						get_address_base(ts, 0x11, CONTROL_BASE) + 0x25, ts->segmentation_bef_unlock);
+				} else {
+					ret = i2c_syn_write_byte_data(ts->client,
+						get_address_base(ts, 0x11, CONTROL_BASE) + 0x22, ts->segmentation_bef_unlock);
+				}
+				if (ret < 0)
+					i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "segmentation aggressiveness", __func__);
+				printk(KERN_INFO "[TP] touch suspend, set segmentation aggressiveness: %x\n", ts->segmentation_bef_unlock);
+			}
+
+			if (ts->threshold_bef_unlock) {
+				if (ts->package_id == 2200) {
+					ret = i2c_syn_write_byte_data(ts->client,
+						get_address_base(ts, 0x11, CONTROL_BASE) + 0x0A, ts->threshold_bef_unlock);
+
+				} else {
+					ret = i2c_syn_write_byte_data(ts->client,
+						get_address_base(ts, 0x11, CONTROL_BASE) + 0x0C, ts->threshold_bef_unlock);
+				}
+				if (ret < 0)
+					i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "Z Touch threshold", __func__);
+				printk(KERN_INFO "[TP] touch suspend, set Z Touch threshold: %x\n", ts->threshold_bef_unlock);
+			}
+		}
+	}
+	else if(ts->psensor_detection)
+		ts->psensor_phone_enable = 1;
+
+	if (ts->packrat_number < SYNAPTICS_FW_NOCAL_PACKRAT)
+		printk(KERN_INFO "[TP][PWR][STATE] get power key state = %d\n", getPowerKeyState());
+
+	if (ts->power)
+		ts->power(0);
+	else {
+		if (ts->packrat_number >= SYNAPTICS_FW_NOCAL_PACKRAT) {
+			ret = i2c_syn_write_byte_data(client,
+					get_address_base(ts, 0x01, CONTROL_BASE), 0x01); 
+			if (ret < 0)
+				i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "sleep: 0x01", __func__);
+		} else {
+			if (ts->psensor_status > 0 && getPowerKeyState() == 0) {
+				ret = i2c_syn_write_byte_data(client,
+					get_address_base(ts, 0x01, CONTROL_BASE), 0x02); 
+				if (ret < 0)
+					i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "sleep: 0x02", __func__);
+			} else {
+				ret = i2c_syn_write_byte_data(client,
+					get_address_base(ts, 0x01, CONTROL_BASE), 0x01); 
+				if (ret < 0)
+					i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "sleep: 0x01", __func__);
+			}
+		}
+	}
+	return 0;
+}
+
+static int synaptics_ts_resume(struct i2c_client *client)
+{
+	int ret;
+	struct synaptics_ts_data *ts = i2c_get_clientdata(client);
+	printk(KERN_INFO "[TP] %s: enter\n", __func__);
+
+	if (ts->power) {
+		ts->power(1);
+		msleep(100);
+#ifdef SYN_CABLE_CONTROL
+		if (ts->cable_support) {
+			if (usb_get_connect_type())
+				cable_tp_status_handler_func(1);
+			printk(KERN_INFO "%s: ts->cable_config: %x\n", __func__, ts->cable_config);
+		}
+#endif
+	} else {
+		ret = i2c_syn_write_byte_data(client,
+			get_address_base(ts, 0x01, CONTROL_BASE), 0x00); 
+		if (ret < 0)
+			i2c_syn_error_handler(ts, ts->i2c_err_handler_en, "wake up", __func__);
+	}
+
+	if (ts->htc_event == SYN_AND_REPORT_TYPE_A) {
+		if (ts->support_htc_event) {
+			input_report_abs(ts->input_dev, ABS_MT_AMPLITUDE, 0);
+			input_report_abs(ts->input_dev, ABS_MT_POSITION, 1 << 31);
+			input_sync(ts->input_dev);
+		}
+		input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, 0);
+		input_sync(ts->input_dev);
+	} else if (ts->htc_event == SYN_AND_REPORT_TYPE_HTC) {
+		input_report_abs(ts->input_dev, ABS_MT_AMPLITUDE, 0);
+		input_report_abs(ts->input_dev, ABS_MT_POSITION, 1 << 31);
+	}
+	if (ts->psensor_detection) {
+		if(ts->psensor_status == 0) {
+			ts->psensor_resume_enable = 1;
+			printk(KERN_INFO "[TP] %s: Enable P-sensor by Touch\n", __func__);
+			psensor_enable_by_touch_driver(1);
+		}
+		else if(ts->psensor_phone_enable == 0) {
+			if(ts->psensor_status != 3)
+				ts->psensor_resume_enable = 2;
+
+			ts->psensor_phone_enable = 1;
+		}
+	}
+
+	if (ts->use_irq) {
+		enable_irq(client->irq);
+		ts->irq_enabled = 1;
+	}
+	else
+		hrtimer_start(&ts->timer, ktime_set(1, 0), HRTIMER_MODE_REL);
+
+	return 0;
+}
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+static void synaptics_ts_early_suspend(struct early_suspend *h)
+{
+	struct synaptics_ts_data *ts;
+	ts = container_of(h, struct synaptics_ts_data, early_suspend);
+	synaptics_ts_suspend(ts->client, PMSG_SUSPEND);
+}
+
+static void synaptics_ts_late_resume(struct early_suspend *h)
+{
+	struct synaptics_ts_data *ts;
+	ts = container_of(h, struct synaptics_ts_data, early_suspend);
+	synaptics_ts_resume(ts->client);
+}
+#endif
+
+static const struct i2c_device_id synaptics_ts_id[] = {
+	{ SYNAPTICS_3200_NAME, 0 },
+	{ }
+};
+
+static struct i2c_driver synaptics_ts_driver = {
+	.probe		= synaptics_ts_probe,
+	.remove		= synaptics_ts_remove,
+#ifndef CONFIG_HAS_EARLYSUSPEND
+	.suspend	= synaptics_ts_suspend,
+	.resume		= synaptics_ts_resume,
+#endif
+	.id_table	= synaptics_ts_id,
+	.driver = {
+		.name	= SYNAPTICS_3200_NAME,
+	},
+};
+
+static int __devinit synaptics_ts_init(void)
+{
+	return i2c_add_driver(&synaptics_ts_driver);
+}
+
+static void __exit synaptics_ts_exit(void)
+{
+	i2c_del_driver(&synaptics_ts_driver);
+}
+
+module_init(synaptics_ts_init);
+module_exit(synaptics_ts_exit);
+
+MODULE_DESCRIPTION("Synaptics Touchscreen Driver");
+MODULE_LICENSE("GPL");
diff --git a/include/linux/rmi.h b/include/linux/rmi.h
new file mode 100644
index 0000000..b84b10f
--- /dev/null
+++ b/include/linux/rmi.h
@@ -0,0 +1,424 @@
+/*
+ * Copyright (c) 2011 Synaptics Incorporated
+ * Copyright (c) 2011 Unixphere
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#ifndef _RMI_H
+#define _RMI_H
+#include <linux/kernel.h>
+#include <linux/lockdep.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/device.h>
+#include <linux/cdev.h>
+#include <linux/mutex.h>
+#include <linux/stat.h>
+#include <linux/wait.h>
+#include <linux/list.h>
+#include <linux/interrupt.h>
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+#include <linux/earlysuspend.h>
+#endif
+
+
+#define RMI_RO_ATTR S_IRUGO
+#define RMI_RW_ATTR (S_IRUGO | S_IWUGO)
+#define RMI_WO_ATTR S_IWUGO
+
+#define PDT_START_SCAN_LOCATION 0x00e9
+
+enum rmi_irq_polarity {
+	RMI_IRQ_ACTIVE_LOW = 0,
+	RMI_IRQ_ACTIVE_HIGH = 1
+};
+
+struct rmi_f11_2d_axis_alignment {
+	bool swap_axes;
+	bool flip_x;
+	bool flip_y;
+	int clip_X_low;
+	int clip_Y_low;
+	int clip_X_high;
+	int clip_Y_high;
+	int offset_X;
+	int offset_Y;
+	int rel_report_enabled;
+};
+
+union rmi_f11_2d_ctrl0 {
+	struct {
+		u8 reporting_mode:3;
+		u8 abs_pos_filt:1;
+		u8 rel_pos_filt:1;
+		u8 rel_ballistics:1;
+		u8 dribble:1;
+		u8 report_beyond_clip:1;
+	};
+	u8 reg;
+};
+
+union rmi_f11_2d_ctrl1 {
+	struct {
+		u8 palm_detect_thres:4;
+		u8 motion_sensitivity:2;
+		u8 man_track_en:1;
+		u8 man_tracked_finger:1;
+	};
+	u8 reg;
+};
+
+union rmi_f11_2d_ctrl2__3 {
+	struct {
+		u8 delta_x_threshold:8;
+		u8 delta_y_threshold:8;
+	};
+	u8 regs[2];
+};
+
+union rmi_f11_2d_ctrl4 {
+	struct {
+		u8 velocity:8;
+	};
+	u8 reg;
+};
+
+union rmi_f11_2d_ctrl5 {
+	struct {
+		u8 acceleration:8;
+	};
+	u8 reg;
+};
+
+union rmi_f11_2d_ctrl6__7 {
+	struct {
+		u16 sensor_max_x_pos:12;
+	};
+	u8 regs[2];
+};
+
+union rmi_f11_2d_ctrl8__9 {
+	struct {
+		u16 sensor_max_y_pos:12;
+	};
+	u8 regs[2];
+};
+
+union rmi_f11_2d_ctrl10 {
+	struct {
+		u8 single_tap_int_enable:1;
+		u8 tap_n_hold_int_enable:1;
+		u8 double_tap_int_enable:1;
+		u8 early_tap_int_enable:1;
+		u8 flick_int_enable:1;
+		u8 press_int_enable:1;
+		u8 pinch_int_enable:1;
+	};
+	u8 reg;
+};
+
+union rmi_f11_2d_ctrl11 {
+	struct {
+		u8 palm_detect_int_enable:1;
+		u8 rotate_int_enable:1;
+		u8 touch_shape_int_enable:1;
+		u8 scroll_zone_int_enable:1;
+		u8 multi_finger_scroll_int_enable:1;
+	};
+	u8 reg;
+};
+
+union rmi_f11_2d_ctrl12 {
+	struct {
+		u8 sensor_map:7;
+		u8 xy_sel:1;
+	};
+	u8 reg;
+};
+
+union rmi_f11_2d_ctrl14 {
+	struct {
+		u8 sens_adjustment:5;
+		u8 hyst_adjustment:3;
+	};
+	u8 reg;
+};
+
+struct  rmi_f11_2d_ctrl {
+	union rmi_f11_2d_ctrl0		*ctrl0;
+	union rmi_f11_2d_ctrl1		*ctrl1;
+	union rmi_f11_2d_ctrl2__3	*ctrl2__3;
+	union rmi_f11_2d_ctrl4		*ctrl4;
+	union rmi_f11_2d_ctrl5		*ctrl5;
+	union rmi_f11_2d_ctrl6__7	*ctrl6__7;
+	union rmi_f11_2d_ctrl8__9	*ctrl8__9;
+	union rmi_f11_2d_ctrl10		*ctrl10;
+	union rmi_f11_2d_ctrl11		*ctrl11;
+	union rmi_f11_2d_ctrl12		*ctrl12;
+	u8				ctrl12_size;
+	union rmi_f11_2d_ctrl14		*ctrl14;
+	u8				*ctrl15;
+	u8				*ctrl16;
+	u8				*ctrl17;
+	u8				*ctrl18;
+	u8				*ctrl19;
+};
+
+struct rmi_f19_button_map {
+	unsigned char nbuttons;
+	unsigned char *map;
+};
+
+struct rmi_device_platform_data_spi {
+	int block_delay_us;
+	int split_read_block_delay_us;
+	int byte_delay_us;
+	int split_read_byte_delay_us;
+	int pre_delay_us;
+	int post_delay_us;
+
+	void *cs_assert_data;
+	int (*cs_assert) (const void *cs_assert_data, const bool assert);
+};
+
+struct rmi_device_platform_data {
+	char *driver_name;
+
+	int irq_no;
+	int irq;
+	enum rmi_irq_polarity irq_polarity;
+	int (*gpio_config)(void);
+
+	struct rmi_device_platform_data_spi spi_v2;
+
+	
+	struct rmi_f11_2d_ctrl *f11_ctrl;
+	struct rmi_f11_2d_axis_alignment axis_align;
+	struct rmi_f19_button_map *button_map;
+
+#ifdef	CONFIG_PM
+	void *pm_data;
+	int (*pre_suspend) (const void *pm_data);
+	int (*post_resume) (const void *pm_data);
+#endif
+};
+
+struct rmi_function_descriptor {
+	u16 query_base_addr;
+	u16 command_base_addr;
+	u16 control_base_addr;
+	u16 data_base_addr;
+	u8 interrupt_source_count;
+	u8 function_number;
+	u8 function_version;
+};
+
+struct rmi_function_container;
+struct rmi_device;
+
+struct rmi_function_handler {
+	int func;
+	int (*init)(struct rmi_function_container *fc);
+	int (*attention)(struct rmi_function_container *fc, u8 *irq_bits);
+#ifdef CONFIG_PM
+	int (*suspend)(struct rmi_function_container *fc);
+	int (*resume)(struct rmi_function_container *fc);
+#endif
+	void (*remove)(struct rmi_function_container *fc);
+};
+
+struct rmi_function_device {
+	struct device dev;
+};
+
+struct rmi_function_container {
+	struct list_head list;
+
+	struct rmi_function_descriptor fd;
+	struct rmi_device *rmi_dev;
+	struct rmi_function_handler *fh;
+	struct device dev;
+
+	int num_of_irqs;
+	int irq_pos;
+	u8 *irq_mask;
+
+	void *data;
+};
+#define to_rmi_function_container(d) \
+		container_of(d, struct rmi_function_container, dev);
+#define to_rmi_function_device(d) \
+		container_of(d, struct rmi_function_device, dev);
+
+
+
+#define RMI_CHAR_DEV_TMPBUF_SZ 128
+#define RMI_REG_ADDR_PAGE_SELECT 0xFF
+
+struct rmi_char_dev {
+	
+	struct mutex mutex_file_op;
+	
+	struct cdev main_dev;
+
+	
+	
+
+	
+	
+	struct rmi_phys_device *phys;
+	
+	int ref_count;
+};
+
+int rmi_char_dev_register(void);
+void rmi_char_dev_unregister(struct rmi_phys_device *phys);
+
+
+
+
+struct rmi_driver {
+	struct device_driver driver;
+
+	int (*probe)(struct rmi_device *rmi_dev);
+	int (*remove)(struct rmi_device *rmi_dev);
+	void (*shutdown)(struct rmi_device *rmi_dev);
+	int (*irq_handler)(struct rmi_device *rmi_dev, int irq);
+	void (*fh_add)(struct rmi_device *rmi_dev,
+		       struct rmi_function_handler *fh);
+	void (*fh_remove)(struct rmi_device *rmi_dev,
+			  struct rmi_function_handler *fh);
+	u8* (*get_func_irq_mask)(struct rmi_device *rmi_dev,
+			    struct rmi_function_container *fc);
+	int (*store_irq_mask)(struct rmi_device *rmi_dev, u8* new_interupts);
+	int (*restore_irq_mask)(struct rmi_device *rmi_dev);
+	void *data;
+};
+#define to_rmi_driver(d) \
+	container_of(d, struct rmi_driver, driver);
+
+struct rmi_phys_info {
+	char *proto;
+	long tx_count;
+	long tx_bytes;
+	long tx_errs;
+	long rx_count;
+	long rx_bytes;
+	long rx_errs;
+	long attn_count;
+	long attn;
+};
+
+struct rmi_phys_device {
+	struct device *dev;
+	struct rmi_device *rmi_dev;
+
+	int (*write)(struct rmi_phys_device *phys, u16 addr, u8 data);
+	int (*write_block)(struct rmi_phys_device *phys, u16 addr, u8 *buf,
+			   int len);
+	int (*read)(struct rmi_phys_device *phys, u16 addr, u8 *buf);
+	int (*read_block)(struct rmi_phys_device *phys, u16 addr, u8 *buf,
+			  int len);
+
+	int (*enable_device) (struct rmi_phys_device *phys);
+	void (*disable_device) (struct rmi_phys_device *phys);
+
+	void *data;
+
+	struct rmi_phys_info info;
+
+	
+	struct rmi_char_dev *char_dev;
+	struct class *rmi_char_device_class;
+};
+
+struct rmi_device {
+	struct device dev;
+
+	struct rmi_driver *driver;
+	struct rmi_phys_device *phys;
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	struct early_suspend early_suspend_handler;
+#endif
+};
+#define to_rmi_device(d) container_of(d, struct rmi_device, dev);
+#define to_rmi_platform_data(d) ((d)->phys->dev->platform_data);
+
+int i2c_rmi_read(uint16_t addr, uint8_t *data, uint16_t length);
+int i2c_rmi_write(uint16_t addr, uint8_t *data, uint16_t length);
+
+static inline void rmi_set_driverdata(struct rmi_device *d, void *data)
+{
+	dev_set_drvdata(&d->dev, data);
+}
+
+static inline void *rmi_get_driverdata(struct rmi_device *d)
+{
+	return dev_get_drvdata(&d->dev);
+}
+
+static inline int rmi_read(struct rmi_device *d, u16 addr, u8 *buf)
+{
+	return d->phys->read(d->phys, addr, buf);
+}
+
+static inline int rmi_read_block(struct rmi_device *d, u16 addr, u8 *buf,
+				 int len)
+{
+	return d->phys->read_block(d->phys, addr, buf, len);
+}
+
+static inline int rmi_write(struct rmi_device *d, u16 addr, u8 data)
+{
+	return d->phys->write(d->phys, addr, data);
+}
+
+static inline int rmi_write_block(struct rmi_device *d, u16 addr, u8 *buf,
+				  int len)
+{
+	return d->phys->write_block(d->phys, addr, buf, len);
+}
+
+int rmi_register_driver(struct rmi_driver *driver);
+
+void rmi_unregister_driver(struct rmi_driver *driver);
+
+int rmi_register_phys_device(struct rmi_phys_device *phys);
+
+void rmi_unregister_phys_device(struct rmi_phys_device *phys);
+
+int rmi_register_function_driver(struct rmi_function_handler *fh);
+
+void rmi_unregister_function_driver(struct rmi_function_handler *fh);
+
+struct rmi_function_handler *rmi_get_function_handler(int id);
+
+ssize_t rmi_store_error(struct device *dev,
+			struct device_attribute *attr,
+			const char *buf, size_t count);
+
+ssize_t rmi_show_error(struct device *dev,
+		       struct device_attribute *attr,
+		       char *buf);
+
+void u8_set_bit(u8 *target, int pos);
+void u8_clear_bit(u8 *target, int pos);
+bool u8_is_set(u8 *target, int pos);
+bool u8_is_any_set(u8 *target, int size);
+void u8_or(u8 *dest, u8* target1, u8* target2, int size);
+void u8_and(u8 *dest, u8* target1, u8* target2, int size);
+#endif
diff --git a/include/linux/synaptics_i2c_rmi.h b/include/linux/synaptics_i2c_rmi.h
index 5539cc5..e66d982 100644
--- a/include/linux/synaptics_i2c_rmi.h
+++ b/include/linux/synaptics_i2c_rmi.h
@@ -18,6 +18,38 @@
 #define _LINUX_SYNAPTICS_I2C_RMI_H
 
 #define SYNAPTICS_I2C_RMI_NAME "synaptics-rmi-ts"
+#define SYNAPTICS_T1007_NAME "synaptics-t1007"
+#define SYNAPTICS_T1021_NAME "synaptics-t1021"
+#define SYNAPTICS_3K_NAME "synaptics-3k"
+#define SYNAPTICS_3K_INCELL_NAME "synaptics-3k-incell"
+#define SYNAPTICS_3200_NAME "synaptics-3200"
+#define SYNAPTICS_FW_3_2_PACKRAT 1115999
+#define SYNAPTICS_FW_NOCAL_PACKRAT 1293981
+
+
+#define SYN_CONFIG_SIZE 32 * 16
+#define SYN_MAX_PAGE 4
+#define SYN_BL_PAGE 1
+#define SYN_F01DATA_BASEADDR 0x0013
+#define SYN_PROCESS_ERR -1
+
+#define SYN_AND_REPORT_TYPE_A		0
+#define	SYN_AND_REPORT_TYPE_B		1
+#define SYN_AND_REPORT_TYPE_HTC		2
+
+#define TAP_DX_OUTER		0
+#define TAP_DY_OUTER		1
+#define TAP_TIMEOUT		2
+#define TAP_DX_INTER		3
+#define TAP_DY_INTER		4
+
+#define CUS_REG_SIZE		4
+#define CUS_REG_BASE		0
+#define CUS_BALLISTICS_CTRL	1
+#define CUS_LAND_CTRL		2
+#define CUS_LIFT_CTRL		3
+
+#define SENSOR_ID_CHECKING_EN	1 << 16
 
 enum {
 	SYNAPTICS_FLIP_X = 1UL << 0,
@@ -26,11 +58,37 @@
 	SYNAPTICS_SNAP_TO_INACTIVE_EDGE = 1UL << 3,
 };
 
+enum {
+	FINGER_1_REPORT = 1 << 0,
+	FINGER_2_REPORT = 1 << 1,
+};
+
+#ifdef CONFIG_TOUCHSCREEN_SYNAPTICS_3K
+struct synaptics_virtual_key {
+	int index;
+	int keycode;
+	int x_range_min;
+	int x_range_max;
+	int y_range_min;
+	int y_range_max;
+};
+#endif
+
 struct synaptics_i2c_rmi_platform_data {
 	uint32_t version;	/* Use this entry for panels with */
 				/* (major << 8 | minor) version or above. */
 				/* If non-zero another array entry follows */
 	int (*power)(int on);	/* Only valid in first array entry */
+#ifdef CONFIG_TOUCHSCREEN_SYNAPTICS_3K
+	struct synaptics_virtual_key *virtual_key;
+	uint8_t virtual_key_num;
+	struct kobject *vk_obj;
+	struct kobj_attribute *vk2Use;
+	uint8_t sensitivity;
+	uint8_t finger_support;
+	uint32_t gap_area;
+	uint32_t key_area;
+#endif
 	uint32_t flags;
 	unsigned long irqflags;
 	uint32_t inactive_left; /* 0x10000 = screen width */
@@ -47,9 +105,80 @@
 	uint32_t snap_bottom_off; /* 0x10000 = screen height */
 	uint32_t fuzz_x; /* 0x10000 = screen width */
 	uint32_t fuzz_y; /* 0x10000 = screen height */
+#ifdef CONFIG_TOUCHSCREEN_SYNAPTICS_3K
+	int abs_x_min;
+	int abs_x_max;
+	int abs_y_min;
+	int abs_y_max;
+#endif
 	int fuzz_p;
 	int fuzz_w;
+#ifdef CONFIG_TOUCHSCREEN_SYNAPTICS_3K
+	uint32_t display_width;
+	uint32_t display_height;
+#endif
 	int8_t sensitivity_adjust;
+#ifdef CONFIG_TOUCHSCREEN_SYNAPTICS_3K
+	uint32_t dup_threshold;
+	uint32_t margin_inactive_pixel[4];
+	uint16_t filter_level[4];
+	uint8_t reduce_report_level[5];
+	uint8_t noise_information;
+	uint8_t jumpfq_enable;
+	uint8_t cable_support;
+	uint8_t config[SYN_CONFIG_SIZE];
+	int gpio_irq;
+	int gpio_reset;
+	uint8_t default_config;
+	uint8_t report_type;
+	uint8_t large_obj_check;
+	uint16_t tw_pin_mask;
+	uint32_t sensor_id;
+	uint32_t packrat_number;
+	uint8_t support_htc_event;
+	uint8_t mfg_flag;
+	uint8_t customer_register[CUS_REG_SIZE];
+	uint8_t segmentation_bef_unlock;
+	uint8_t threshold_bef_unlock;
+	uint16_t saturation_bef_unlock;
+	uint8_t i2c_err_handler_en;
+	uint8_t energy_ratio_relaxation;
+	uint8_t multitouch_calibration;
+	uint8_t psensor_detection;
+	uint8_t PixelTouchThreshold_bef_unlock;
+#endif
 };
 
+#ifdef CONFIG_TOUCHSCREEN_SYNAPTICS_3K
+struct page_description {
+	uint8_t addr;
+	uint8_t value;
+};
+
+struct syn_finger_data {
+	int x;
+	int y;
+	int w;
+	int z;
+};
+
+struct function_t {
+	uint8_t function_type;
+	uint8_t interrupt_source;
+	uint16_t data_base;
+	uint16_t control_base;
+	uint16_t command_base;
+	uint16_t query_base;
+};
+enum {
+	QUERY_BASE,
+	COMMAND_BASE,
+	CONTROL_BASE,
+	DATA_BASE,
+	INTR_SOURCE,
+	FUNCTION
+};
+
+extern uint8_t getPowerKeyState(void);
+#endif /* CONFIG_TOUCHSCREEN_SYNAPTICS_3K */
 #endif /* _LINUX_SYNAPTICS_I2C_RMI_H */