mako: touch driver merge

- lge touch common driver
- synaptics touch driver integration with lge common driver

Change-Id: I72e53f8d16610155ab1a31a366e33910a41643be
diff --git a/drivers/input/touchscreen/touch_synaptics.c b/drivers/input/touchscreen/touch_synaptics.c
new file mode 100644
index 0000000..e708146
--- /dev/null
+++ b/drivers/input/touchscreen/touch_synaptics.c
@@ -0,0 +1,1134 @@
+/* Touch_synaptics.c
+ *
+ * Copyright (C) 2011 LGE.
+ *
+ * Author: yehan.ahn@lge.com, hyesung.shin@lge.com
+ *
+ * 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/err.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+
+#include <linux/gpio.h>
+
+#include <linux/earlysuspend.h>
+#include <linux/input/lge_touch_core.h>
+#include <linux/input/touch_synaptics.h>
+
+#if defined(CONFIG_TOUCH_REG_MAP_TM2000)
+#include "SynaImage.h"
+#elif defined(CONFIG_TOUCH_REG_MAP_TM2372)
+#include "SynaImage_Jp.h"
+#else
+#include "SynaImage.h"
+#endif
+
+#include <linux/regulator/machine.h>
+
+/* RMI4 spec from (RMI4 spec)511-000136-01_revD
+ * Function     Purpose                                      See page
+ * $01          RMI Device Control                              29
+ * $08          BIST(Built-in Self Test)                        38
+ * $09          BIST(Built-in Self Test)                        42
+ * $11          2-D TouchPad sensors                            46
+ * $19          0-D capacitive button sensors                   69
+ * $30          GPIO/LEDs (includes mechanical buttons)         76
+ * $32          Timer                                           89
+ * $34          Flash Memory Management                         93
+ */
+#define RMI_DEVICE_CONTROL                      0x01
+#define TOUCHPAD_SENSORS                        0x11
+#if defined(CONFIG_TOUCH_REG_MAP_TM2000) || defined(CONFIG_TOUCH_REG_MAP_TM2372)
+#define CAPACITIVE_BUTTON_SENSORS               0x1A
+#define GPIO_LEDS                               0x31
+#define ANALOG_CONTROL                          0x54
+#else
+#define CAPACITIVE_BUTTON_SENSORS               0x19
+#define GPIO_LEDS                               0x30
+#endif
+#define TIMER                                   0x32
+#define FLASH_MEMORY_MANAGEMENT                 0x34
+
+/* Register Map & Register bit mask
+ * - Please check "One time" this map before using this device driver
+ */
+
+#define MANUFACTURER_ID_REG (ts->common_dsc.query_base)    /* Manufacturer ID */
+#define FW_REVISION_REG     (ts->common_dsc.query_base+3)  /* FW revision */
+#define PRODUCT_ID_REG      (ts->common_dsc.query_base+11) /* Product ID */
+#if defined(CONFIG_TOUCH_REG_MAP_TM2000) || defined(CONFIG_TOUCH_REG_MAP_TM2372)
+#define FW_VERSION          (ts->flash_dsc.control_base)
+#endif
+
+#define DEVICE_CONTROL_REG (ts->common_dsc.control_base)  /* Device Control */
+#define DEVICE_CONTROL_NORMAL_OP    0x00    /* sleep mode : go to doze mode after 500 ms */
+#define DEVICE_CONTROL_SLEEP 	    0x01    /* sleep mode : go to sleep */
+#define DEVICE_CONTROL_SPECIFIC     0x02    /* sleep mode : go to doze mode after 5 sec */
+#define DEVICE_CONTROL_NOSLEEP      0x04
+#define DEVICE_CONTROL_CONFIGURED   0x80
+
+#define INTERRUPT_ENABLE_REG (ts->common_dsc.control_base+1) /* Interrupt Enable 0 */
+
+#define DEVICE_STATUS_REG    (ts->common_dsc.data_base)    /* Device Status */
+#define DEVICE_FAILURE_MASK         0x03
+#define DEVICE_CRC_ERROR_MASK       0x04
+#define DEVICE_STATUS_FLASH_PROG    0x40
+#define DEVICE_STATUS_UNCONFIGURED  0x80
+
+#define INTERRUPT_STATUS_REG  (ts->common_dsc.data_base+1) /* Interrupt Status */
+#define BUTTON_DATA_REG       (ts->button_dsc.data_base)   /* Button Data */
+#define MAX_NUM_OF_BUTTON 4
+
+#define FINGER_STATE_REG      (ts->finger_dsc.data_base)   /* Finger State */
+#define FINGER_DATA_REG_START (ts->finger_dsc.data_base+3) /* Finger Data Register */
+#define FINGER_STATE_MASK           0x03
+#define REG_X_POSITION              0
+#define REG_Y_POSITION              1
+#define REG_YX_POSITION             2
+#define REG_WY_WX                   3
+#define REG_Z                       4
+
+#define TWO_D_REPORTING_MODE (ts->finger_dsc.control_base+0) /* 2D Reporting Mode */
+#define REPORT_MODE_CONTINUOUS      0x00
+#define REPORT_MODE_REDUCED         0x01
+#define ABS_FILTER                  0x08
+#define PALM_DETECT_REG      (ts->finger_dsc.control_base+1) /* Palm Detect */
+#define DELTA_X_THRESH_REGi  (ts->finger_dsc.control_base+2) /* Delta-X Thresh */
+#define DELTA_Y_THRESH_REG   (ts->finger_dsc.control_base+3) /* Delta-Y Thresh */
+#define SENSOR_MAX_X_POS     (ts->finger_dsc.control_base+6) /* SensorMaxXPos */
+#define SENSOR_MAX_Y_POS     (ts->finger_dsc.control_base+8) /* SensorMaxYPos */
+#if defined(CONFIG_TOUCH_REG_MAP_TM2000) || defined(CONFIG_TOUCH_REG_MAP_TM2372)
+/*do nothing*/
+#else
+#define GESTURE_ENABLE_1_REG (ts->finger_dsc.control_base+10) /* Gesture Enables 1 */
+#define GESTURE_ENABLE_2_REG (ts->finger_dsc.control_base+11) /* Gesture Enables 2 */
+#endif
+
+#if defined(CONFIG_TOUCH_REG_MAP_TM2000) || defined(CONFIG_TOUCH_REG_MAP_TM2372)
+#define PAGE_SELECT_REG             0xFF           /* Button exists Page 02 */
+#define ANALOG_CONTROL_REG          (ts->analog_dsc.control_base)
+#define ANALOG_COMMAND_REG          (ts->analog_dsc.command_base)
+#define FAST_RELAXATION_RATE        (ts->analog_dsc.control_base+16)
+#define FORCE_FAST_RELAXATION       0x04
+#define FORCE_UPDATE                0x04
+#else
+#define MELT_CONTROL_REG            0xF0
+#define MELT_CONTROL_NO_MELT        0x00
+#define MELT_CONTROL_MELT           0x01
+#define MELT_CONTROL_NUKE_MELT      0x80
+#endif
+
+#define DEVICE_COMMAND_REG          (ts->common_dsc.command_base)
+#define FINGER_COMMAND_REG          (ts->finger_dsc.command_base)
+#define BUTTON_COMMAND_REG          (ts->button_dsc.command_base)
+
+#define FLASH_CONTROL_REG           (ts->flash_dsc.data_base+18)     /* Flash Control */
+#define FLASH_STATUS_MASK           0xF0
+
+/* Get user-finger-data from register.
+ */
+#define TS_SNTS_GET_X_POSITION(_high_reg, _low_reg) \
+	(((u16)(((_high_reg) << 4) & 0x0FF0) | (u16)((_low_reg) & 0x0F)))
+#define TS_SNTS_GET_Y_POSITION(_high_reg, _low_reg) \
+	(((u16)(((_high_reg) << 4) & 0x0FF0) | (u16)(((_low_reg) >> 4) & 0x0F)))
+#define TS_SNTS_GET_WIDTH_MAJOR(_width) \
+	((((((_width) & 0xF0) >> 4) - ((_width) & 0x0F)) > 0) ? \
+		((_width) & 0xF0) >> 4 : (_width) & 0x0F)
+#define TS_SNTS_GET_WIDTH_MINOR(_width) \
+	((((((_width) & 0xF0) >> 4) - ((_width) & 0x0F)) > 0) ? \
+		(_width) & 0x0F : ((_width) & 0xF0) >> 4)
+#define TS_SNTS_GET_ORIENTATION(_width) \
+	((((((_width) & 0xF0) >> 4) - ((_width) & 0x0F)) > 0) ? 0 : 1)
+#define TS_SNTS_GET_PRESSURE(_pressure) (_pressure)
+
+
+/* GET_BIT_MASK & GET_INDEX_FROM_MASK
+ *
+ * For easily checking the user input.
+ * Usually, User use only one or two fingers.
+ * However, we should always check all finger-status-register
+ * because we can't know the total number of fingers.
+ * These Macro will prevent it.
+ */
+#define GET_BIT_MASK(_finger_status_reg)	\
+	((_finger_status_reg[2] & 0x04) << 7 |  \
+	(_finger_status_reg[2] & 0x01) << 8 |   \
+	(_finger_status_reg[1] & 0x40) << 1 |   \
+	(_finger_status_reg[1] & 0x10) << 2 |   \
+	(_finger_status_reg[1] & 0x04) << 3 |   \
+	(_finger_status_reg[1] & 0x01) << 4 |   \
+	(_finger_status_reg[0] & 0x40) >> 3 |   \
+	(_finger_status_reg[0] & 0x10) >> 2 |   \
+	(_finger_status_reg[0] & 0x04) >> 1 |   \
+	(_finger_status_reg[0] & 0x01))
+
+#define GET_INDEX_FROM_MASK(_index, _bit_mask, _max_finger)              \
+	do {                                                             \
+		for (; !((_bit_mask>>_index)&0x01)                       \
+				&& _index <= _max_finger; _index++);     \
+		if (_index <= _max_finger)                               \
+			_bit_mask &= ~(_bit_mask & (1<<(_index)));       \
+	} while (0)
+
+int synaptics_ts_get_data(struct i2c_client *client, struct t_data* data,
+					struct b_data* button, u8* total_num)
+{
+	struct synaptics_ts_data* ts =
+			(struct synaptics_ts_data*)get_touch_handle(client);
+
+	u16 touch_finger_bit_mask=0;
+	u8 finger_index=0;
+	u8 index=0;
+	u8 cnt;
+
+	if (unlikely(touch_debug_mask & DEBUG_TRACE))
+		TOUCH_DEBUG_MSG("\n");
+
+	if (unlikely(touch_i2c_read(client, DEVICE_STATUS_REG,
+			sizeof(ts->ts_data.interrupt_status_reg),
+			&ts->ts_data.device_status_reg) < 0)) {
+		TOUCH_ERR_MSG("DEVICE_STATUS_REG read fail\n");
+		goto err_synaptics_getdata;
+	}
+
+	/* ESD damage check */
+	if ((ts->ts_data.device_status_reg & DEVICE_FAILURE_MASK) ==
+							DEVICE_FAILURE_MASK) {
+		TOUCH_ERR_MSG("ESD damage occured. Reset Touch IC\n");
+		goto err_synaptics_device_damage;
+	}
+
+	/* Internal reset check */
+	if (((ts->ts_data.device_status_reg & DEVICE_STATUS_UNCONFIGURED) >> 7) == 1) {
+		TOUCH_ERR_MSG("Touch IC resetted internally. "
+				"Reconfigure register setting\n");
+		goto err_synaptics_device_damage;
+	}
+
+	if (unlikely(touch_i2c_read(client, INTERRUPT_STATUS_REG,
+			sizeof(ts->ts_data.interrupt_status_reg),
+			&ts->ts_data.interrupt_status_reg) < 0)) {
+		TOUCH_ERR_MSG("INTERRUPT_STATUS_REG read fail\n");
+		goto err_synaptics_getdata;
+	}
+
+	if (unlikely(touch_debug_mask & DEBUG_GET_DATA))
+		TOUCH_INFO_MSG("Interrupt_status : 0x%x\n",
+					ts->ts_data.interrupt_status_reg);
+
+	/* IC bug Exception handling - Interrupt status reg is 0 when interrupt occur */
+	if (ts->ts_data.interrupt_status_reg == 0) {
+		TOUCH_ERR_MSG("Interrupt_status reg is 0. "
+				"Something is wrong in IC\n");
+		goto err_synaptics_device_damage;
+	}
+
+	/* Because of ESD damage... */
+	if (unlikely(ts->ts_data.interrupt_status_reg & ts->interrupt_mask.flash)) {
+		TOUCH_ERR_MSG("Impossible Interrupt\n");
+		goto err_synaptics_device_damage;
+	}
+
+	/* Finger */
+	if (likely(ts->ts_data.interrupt_status_reg & ts->interrupt_mask.abs)) {
+		if (unlikely(touch_i2c_read(client, FINGER_STATE_REG,
+				sizeof(ts->ts_data.finger.finger_status_reg),
+				ts->ts_data.finger.finger_status_reg) < 0)) {
+			TOUCH_ERR_MSG("FINGER_STATE_REG read fail\n");
+			goto err_synaptics_getdata;
+		}
+
+		touch_finger_bit_mask = GET_BIT_MASK(ts->ts_data.finger.finger_status_reg);
+		if (unlikely(touch_debug_mask & DEBUG_GET_DATA)) {
+			TOUCH_INFO_MSG("Finger_status : 0x%x, 0x%x, 0x%x\n",
+				ts->ts_data.finger.finger_status_reg[0],
+				ts->ts_data.finger.finger_status_reg[1],
+				ts->ts_data.finger.finger_status_reg[2]);
+			TOUCH_INFO_MSG("Touch_bit_mask: 0x%x\n", touch_finger_bit_mask);
+		}
+
+		while (touch_finger_bit_mask) {
+			GET_INDEX_FROM_MASK(finger_index, touch_finger_bit_mask,
+						MAX_NUM_OF_FINGERS);
+			if (unlikely(touch_i2c_read(ts->client,
+					FINGER_DATA_REG_START + (NUM_OF_EACH_FINGER_DATA_REG * finger_index),
+					NUM_OF_EACH_FINGER_DATA_REG,
+					ts->ts_data.finger.finger_reg[index]) < 0)) {
+				TOUCH_ERR_MSG("FINGER_DATA_REG read fail\n");
+				goto err_synaptics_getdata;
+			}
+
+			data[index].id = finger_index;
+			data[index].x_position = TS_SNTS_GET_X_POSITION(
+				ts->ts_data.finger.finger_reg[index][REG_X_POSITION],
+				ts->ts_data.finger.finger_reg[index][REG_YX_POSITION]);
+			data[index].y_position = TS_SNTS_GET_Y_POSITION(
+				ts->ts_data.finger.finger_reg[index][REG_Y_POSITION],
+				ts->ts_data.finger.finger_reg[index][REG_YX_POSITION]);
+			data[index].width_major = TS_SNTS_GET_WIDTH_MAJOR(
+				ts->ts_data.finger.finger_reg[index][REG_WY_WX]);
+			data[index].width_minor = TS_SNTS_GET_WIDTH_MINOR(
+				ts->ts_data.finger.finger_reg[index][REG_WY_WX]);
+			data[index].width_orientation = TS_SNTS_GET_ORIENTATION(
+				ts->ts_data.finger.finger_reg[index][REG_WY_WX]);
+			data[index].pressure = TS_SNTS_GET_PRESSURE(
+				ts->ts_data.finger.finger_reg[index][REG_Z]);
+
+			if (unlikely(touch_debug_mask & DEBUG_GET_DATA))
+				TOUCH_INFO_MSG("[%d] pos(%4d,%4d) w_m[%2d] "
+						"w_n[%2d] w_o[%2d] p[%2d]\n",
+						finger_index,
+						data[index].x_position,
+						data[index].y_position,
+						data[index].width_major,
+						data[index].width_minor,
+						data[index].width_orientation,
+						data[index].pressure);
+
+			index++;
+		}
+		*total_num = index;
+		if (unlikely(touch_debug_mask & DEBUG_GET_DATA))
+			TOUCH_INFO_MSG("Total_num: %d\n", *total_num);
+	}
+
+	 /* Button */
+	if (unlikely(ts->button_dsc.id != 0)) {
+		if (likely(ts->ts_data.interrupt_status_reg &
+						ts->interrupt_mask.button)) {
+
+#if defined(CONFIG_TOUCH_REG_MAP_TM2000) || defined(CONFIG_TOUCH_REG_MAP_TM2372)
+			if (unlikely(touch_i2c_write_byte(client,
+						PAGE_SELECT_REG, 0x02) < 0)) {
+				TOUCH_ERR_MSG("PAGE_SELECT_REG write fail\n");
+				return -EIO;
+			}
+
+			if (unlikely(touch_i2c_read(client, BUTTON_DATA_REG,
+					sizeof(ts->ts_data.button_data_reg),
+					&ts->ts_data.button_data_reg) < 0)) {
+				TOUCH_ERR_MSG("BUTTON_DATA_REG read fail\n");
+				goto err_synaptics_getdata;
+			}
+
+			if (unlikely(touch_i2c_write_byte(client,
+					PAGE_SELECT_REG, 0x00) < 0)) {
+				TOUCH_ERR_MSG("PAGE_SELECT_REG write fail\n");
+				return -EIO;
+			}
+#else
+			if (unlikely(touch_i2c_read(client, BUTTON_DATA_REG,
+					sizeof(ts->ts_data.button_data_reg),
+					&ts->ts_data.button_data_reg) < 0)) {
+				TOUCH_ERR_MSG("BUTTON_DATA_REG read fail\n");
+				goto err_synaptics_getdata;
+			}
+#endif
+			if (unlikely(touch_debug_mask & DEBUG_BUTTON))
+				TOUCH_DEBUG_MSG("Button register: 0x%x\n",
+						ts->ts_data.button_data_reg);
+
+			if (ts->ts_data.button_data_reg) {
+				/* pressed - find first one */
+				for (cnt = 0; cnt < ts->pdata->caps->number_of_button; cnt++) {
+#if defined(CONFIG_TOUCH_REG_MAP_TM2000)
+					if (((ts->ic_panel_type == IC7020_GFF ||
+						ts->ic_panel_type == IC7020_G2 ||
+						ts->ic_panel_type == IC7020_G2_H_PTN) &&
+						((ts->ts_data.button_data_reg >> cnt)
+										& 0x1))   ||
+					 	((ts->ic_panel_type == IC3203_G2) &&
+							((ts->ts_data.button_data_reg >>
+								(cnt << 1)) & 0x3))) {
+#elif defined(CONFIG_TOUCH_REG_MAP_TM2372)
+					if ((ts->ts_data.button_data_reg >> cnt) & 0x1) {
+#else
+					if ((ts->ts_data.button_data_reg >> cnt) & 0x1) {
+#endif
+						ts->ts_data.button.key_code =
+							ts->pdata->caps->button_name[cnt];
+						button->key_code =
+							ts->ts_data.button.key_code;
+						button->state = 1;
+						break;
+					}
+				}
+			} else {
+				/* release */
+				button->key_code = ts->ts_data.button.key_code;
+				button->state = 0;
+			}
+		}
+	}
+
+	return 0;
+
+err_synaptics_device_damage:
+err_synaptics_getdata:
+	return -EIO;
+}
+
+static int read_page_description_table(struct i2c_client* client)
+{
+	struct synaptics_ts_data* ts =
+			(struct synaptics_ts_data*)get_touch_handle(client);
+	struct ts_function_descriptor buffer;
+	unsigned short u_address;
+
+	if (touch_debug_mask & DEBUG_TRACE)
+		TOUCH_DEBUG_MSG("\n");
+
+	memset(&buffer, 0x0, sizeof(struct ts_function_descriptor));
+
+	ts->common_dsc.id = 0;
+	ts->finger_dsc.id = 0;
+	ts->button_dsc.id = 0;
+	ts->flash_dsc.id  = 0;
+#if defined(CONFIG_TOUCH_REG_MAP_TM2000) || defined(CONFIG_TOUCH_REG_MAP_TM2372)
+	ts->analog_dsc.id = 0;
+#endif
+
+	for (u_address = DESCRIPTION_TABLE_START; u_address > 10;
+			u_address -= sizeof(struct ts_function_descriptor)) {
+		if (unlikely(touch_i2c_read(client, u_address, sizeof(buffer),
+					(unsigned char *)&buffer) < 0)) {
+			TOUCH_ERR_MSG("RMI4 Function Descriptor read fail\n");
+			return -EIO;
+		}
+
+		if (buffer.id == 0)
+			break;
+
+		switch (buffer.id) {
+		case RMI_DEVICE_CONTROL:
+			ts->common_dsc = buffer;
+			break;
+		case TOUCHPAD_SENSORS:
+			ts->finger_dsc = buffer;
+			break;
+		case FLASH_MEMORY_MANAGEMENT:
+			ts->flash_dsc = buffer;
+		}
+	}
+
+#if defined(CONFIG_TOUCH_REG_MAP_TM2000) || defined(CONFIG_TOUCH_REG_MAP_TM2372)
+	if (unlikely(touch_i2c_write_byte(client, PAGE_SELECT_REG, 0x01) < 0)) {
+		TOUCH_ERR_MSG("PAGE_SELECT_REG write fail\n");
+		return -EIO;
+	}
+
+	u_address = DESCRIPTION_TABLE_START;
+
+	if (unlikely(touch_i2c_read(client, u_address, sizeof(buffer),
+					(unsigned char *)&buffer) < 0)) {
+		TOUCH_ERR_MSG("RMI4 Function Descriptor read fail\n");
+		return -EIO;
+	}
+
+	switch (buffer.id) {
+	case ANALOG_CONTROL:
+		ts->analog_dsc = buffer;
+		break;
+	}
+
+	if (unlikely(touch_i2c_write_byte(client, PAGE_SELECT_REG, 0x02) < 0)) {
+		TOUCH_ERR_MSG("PAGE_SELECT_REG write fail\n");
+		return -EIO;
+	}
+
+	u_address -= sizeof(struct ts_function_descriptor);
+
+	if (unlikely(touch_i2c_read(ts->client, u_address, sizeof(buffer),
+						(unsigned char *)&buffer))) {
+		TOUCH_ERR_MSG("Button ts_function_descriptor read fail\n");
+		return -EIO;
+	}
+
+	switch (buffer.id) {
+	case CAPACITIVE_BUTTON_SENSORS:
+		ts->button_dsc = buffer;
+		break;
+	}
+
+	if (unlikely(touch_i2c_write_byte(client, PAGE_SELECT_REG, 0x00) < 0)) {
+		TOUCH_ERR_MSG("PAGE_SELECT_REG write fail\n");
+		return -EIO;
+	}
+#endif
+
+	/* set interrupt mask */
+	ts->interrupt_mask.flash = 0x1;
+	ts->interrupt_mask.status = 0x2;
+
+	if (ts->button_dsc.id == 0) {
+		ts->interrupt_mask.abs = 0x4;
+	} else {
+		if (ts->finger_dsc.data_base > ts->button_dsc.data_base) {
+#if defined(CONFIG_TOUCH_REG_MAP_TM2000) || defined(CONFIG_TOUCH_REG_MAP_TM2372)
+			ts->interrupt_mask.abs = 0x4;
+			ts->interrupt_mask.button = 0x20;
+#else
+			ts->interrupt_mask.abs = 0x8;
+			ts->interrupt_mask.button = 0x4;
+#endif
+		} else {
+			ts->interrupt_mask.abs = 0x4;
+			ts->interrupt_mask.button = 0x8;
+		}
+	}
+
+	if (ts->common_dsc.id == 0 || ts->finger_dsc.id == 0 ||
+						ts->flash_dsc.id == 0) {
+		TOUCH_ERR_MSG("common_dsc/finger_dsc/flash_dsc are not initiailized\n");
+		return -EPERM;
+	}
+
+	if (touch_debug_mask & DEBUG_BASE_INFO)
+		TOUCH_INFO_MSG("common[%d] finger[%d] flash[%d] button[%d]\n",
+				ts->common_dsc.id, ts->finger_dsc.id,
+				ts->flash_dsc.id, ts->button_dsc.id);
+
+	return 0;
+}
+
+int get_ic_info(struct synaptics_ts_data* ts, struct touch_fw_info* fw_info)
+{
+#if defined(ARRAYED_TOUCH_FW_BIN)
+	int cnt;
+#endif
+	u8 device_status = 0;
+	u8 flash_control = 0;
+
+	read_page_description_table(ts->client);
+
+	memset(fw_info, 0, sizeof(fw_info));
+
+	if (unlikely(touch_i2c_read(ts->client, FW_REVISION_REG,
+			sizeof(fw_info->fw_rev), &fw_info->fw_rev) < 0)) {
+		TOUCH_ERR_MSG("FW_REVISION_REG read fail\n");
+		return -EIO;
+	}
+
+	if (unlikely(touch_i2c_read(ts->client, MANUFACTURER_ID_REG,
+					sizeof(fw_info->manufacturer_id),
+					&fw_info->manufacturer_id) < 0)) {
+		TOUCH_ERR_MSG("MANUFACTURER_ID_REG read fail\n");
+		return -EIO;
+	}
+
+	if (unlikely(touch_i2c_read(ts->client, PRODUCT_ID_REG,
+					sizeof(fw_info->product_id) - 1,
+					fw_info->product_id) < 0)) {
+		TOUCH_ERR_MSG("PRODUCT_ID_REG read fail\n");
+		return -EIO;
+	}
+
+	if (unlikely(touch_i2c_read(ts->client, FW_VERSION,
+					sizeof(fw_info->fw_version) - 1,
+					fw_info->fw_version) < 0)) {
+		TOUCH_ERR_MSG("FW_VERSION read fail\n");
+		return -EIO;
+	}
+
+#if defined(CONFIG_TOUCH_REG_MAP_TM2000)
+	if ((strncmp(fw_info->fw_version, "0000", 4) == 0) ||
+   			(strncmp(fw_info->fw_version, "S001", 4) == 0)) {
+		ts->ic_panel_type = IC7020_GFF;
+		TOUCH_INFO_MSG("IC is 7020, panel is GFF.");
+	} else {
+		if (fw_info->fw_version[0] == 'E' &&
+			(int)simple_strtol(&fw_info->fw_version[1], NULL, 10) < 14) {
+			ts->ic_panel_type = IC7020_G2;
+			TOUCH_INFO_MSG("IC is 7020, panel is G2.");
+		} else if ((fw_info->fw_version[0] == 'E'
+			&& (int)simple_strtol(&fw_info->fw_version[1], NULL, 10) >= 14
+			&& (int)simple_strtol(&fw_info->fw_version[1], NULL, 10) < 27)
+			|| fw_info->fw_version[0] == 'T') {
+			ts->ic_panel_type = IC3203_G2;
+			TOUCH_INFO_MSG("IC is 3203, panel is G2.");
+		} else {
+			ts->ic_panel_type = IC7020_G2_H_PTN;
+			TOUCH_INFO_MSG("IC is 7020, H pattern, panel is G2.");
+
+			if ((fw_info->fw_version[0] == 'E')
+				&& ((int)simple_strtol(&fw_info->fw_version[1],
+							NULL, 10) >= 40)) {
+				ts->interrupt_mask.button = 0x10;
+			}
+		}
+	}
+#elif defined(CONFIG_TOUCH_REG_MAP_TM2372)
+	ts->ic_panel_type = IC7020_GFF_H_PTN;
+	TOUCH_INFO_MSG("IC is 7020, H pattern, panel is GFF.");
+#endif
+
+#if defined(ARRAYED_TOUCH_FW_BIN)
+	for (cnt = 0; cnt < sizeof(SynaFirmware)/sizeof(SynaFirmware[0]); cnt++) {
+		strncpy(fw_info->fw_image_product_id,
+					&SynaFirmware[cnt][16], 10);
+		if (!(strncmp(fw_info->product_id,
+				fw_info->fw_image_product_id, 10)))
+			break;
+	}
+	fw_info->fw_start = (unsigned char *)&SynaFirmware[cnt][0];
+	fw_info->fw_size = sizeof(SynaFirmware[0]);
+#else
+	strncpy(fw_info->fw_image_product_id, &SynaFirmware[16], 10);
+#if defined(CONFIG_TOUCH_REG_MAP_TM2000) || defined(CONFIG_TOUCH_REG_MAP_TM2372)
+	strncpy(fw_info->fw_image_version, &SynaFirmware[0xb100],4);
+#endif
+	fw_info->fw_start = (unsigned char *)&SynaFirmware[0];
+	fw_info->fw_size = sizeof(SynaFirmware);
+#endif
+
+	fw_info->fw_image_rev = fw_info->fw_start[31];
+
+	if (unlikely(touch_i2c_read(ts->client, FLASH_CONTROL_REG,
+				sizeof(flash_control), &flash_control) < 0)) {
+		TOUCH_ERR_MSG("FLASH_CONTROL_REG read fail\n");
+		return -EIO;
+	}
+
+	if (unlikely(touch_i2c_read(ts->client, DEVICE_STATUS_REG,
+				sizeof(device_status), &device_status) < 0)) {
+		TOUCH_ERR_MSG("DEVICE_STATUS_REG read fail\n");
+		return -EIO;
+	}
+
+	/* Firmware has a problem, so we should firmware-upgrade */
+	if (device_status & DEVICE_STATUS_FLASH_PROG
+			|| (device_status & DEVICE_CRC_ERROR_MASK) != 0
+			|| (flash_control & FLASH_STATUS_MASK) != 0) {
+		TOUCH_ERR_MSG("Firmware has a unknown-problem, "
+				"so it needs firmware-upgrade.\n");
+		TOUCH_ERR_MSG("FLASH_CONTROL[%x] DEVICE_STATUS_REG[%x]\n",
+				(u32)flash_control, (u32)device_status);
+
+		fw_info->fw_rev = 0;
+#if defined(CONFIG_TOUCH_REG_MAP_TM2000) || defined(CONFIG_TOUCH_REG_MAP_TM2372)
+		fw_info->fw_force_rework = true;
+#endif
+	}
+
+	ts->fw_info = fw_info;
+
+	return 0;
+}
+
+int synaptics_ts_init(struct i2c_client* client, struct touch_fw_info* fw_info)
+{
+	struct synaptics_ts_data* ts =
+			(struct synaptics_ts_data*)get_touch_handle(client);
+	u8 buf;
+
+	if (touch_debug_mask & DEBUG_TRACE)
+		TOUCH_DEBUG_MSG("\n");
+
+	if (!ts->is_probed)
+		if (unlikely(get_ic_info(ts, fw_info) < 0))
+			return -EIO;
+
+	if (unlikely(touch_i2c_write_byte(client, DEVICE_CONTROL_REG,
+		DEVICE_CONTROL_NOSLEEP | DEVICE_CONTROL_CONFIGURED) < 0)) {
+		TOUCH_ERR_MSG("DEVICE_CONTROL_REG write fail\n");
+		return -EIO;
+	}
+
+	if (unlikely(touch_i2c_read(client, INTERRUPT_ENABLE_REG,
+		1, &buf) < 0)) {
+		TOUCH_ERR_MSG("INTERRUPT_ENABLE_REG read fail\n");
+		return -EIO;
+	}
+	if (unlikely(touch_i2c_write_byte(client, INTERRUPT_ENABLE_REG,
+		buf | ts->interrupt_mask.abs | ts->interrupt_mask.button) < 0)) {
+		TOUCH_ERR_MSG("INTERRUPT_ENABLE_REG write fail\n");
+		return -EIO;
+	}
+
+#if defined(CONFIG_TOUCH_REG_MAP_TM2000) || defined(CONFIG_TOUCH_REG_MAP_TM2372)
+	/* do nothing */
+#else
+	if (unlikely(touch_i2c_write_byte(client,
+					GESTURE_ENABLE_1_REG, 0x00) < 0)) {
+		TOUCH_ERR_MSG("GESTURE_ENABLE_1_REG write fail\n");
+		return -EIO;
+	}
+	if (unlikely(touch_i2c_write_byte(client, GESTURE_ENABLE_2_REG, 0x00) < 0)) {
+		TOUCH_ERR_MSG("GESTURE_ENABLE_2_REG write fail\n");
+		return -EIO;
+	}
+
+	if (ts->pdata->role->report_mode == CONTINUOUS_REPORT_MODE) {
+		if (unlikely(touch_i2c_write_byte(client, TWO_D_REPORTING_MODE,
+				REPORT_MODE_CONTINUOUS) < 0)) {
+			TOUCH_ERR_MSG("TWO_D_REPORTING_MODE write fail\n");
+			return -EIO;
+		}
+	} else {	/* REDUCED_REPORT_MODE */
+		if (unlikely(touch_i2c_write_byte(client, TWO_D_REPORTING_MODE,
+				REPORT_MODE_REDUCED) < 0)) {
+			TOUCH_ERR_MSG("TWO_D_REPORTING_MODE write fail\n");
+			return -EIO;
+		}
+
+		if (unlikely(touch_i2c_write_byte(client, DELTA_X_THRESH_REG,
+				ts->pdata->role->delta_pos_threshold) < 0)) {
+			TOUCH_ERR_MSG("DELTA_X_THRESH_REG write fail\n");
+			return -EIO;
+		}
+		if (unlikely(touch_i2c_write_byte(client, DELTA_Y_THRESH_REG,
+				ts->pdata->role->delta_pos_threshold) < 0)) {
+			TOUCH_ERR_MSG("DELTA_Y_THRESH_REG write fail\n");
+			return -EIO;
+		}
+	}
+#endif
+
+	if (unlikely(touch_i2c_read(client, INTERRUPT_STATUS_REG, 1, &buf) < 0)) {
+		TOUCH_ERR_MSG("INTERRUPT_STATUS_REG read fail\n");
+		return -EIO;	/* it is critical problem because interrupt will not occur. */
+	}
+
+	if (unlikely(touch_i2c_read(client, FINGER_STATE_REG,
+				sizeof(ts->ts_data.finger.finger_status_reg),
+				ts->ts_data.finger.finger_status_reg) < 0)) {
+		TOUCH_ERR_MSG("FINGER_STATE_REG read fail\n");
+		/* it is critical problem because interrupt will not occur on some FW. */
+		return -EIO;
+	}
+
+	ts->is_probed = 1;
+
+	return 0;
+}
+
+int synaptics_ts_power(struct i2c_client* client, int power_ctrl)
+{
+	struct synaptics_ts_data* ts =
+			(struct synaptics_ts_data*)get_touch_handle(client);
+
+	if (touch_debug_mask & DEBUG_TRACE)
+		TOUCH_DEBUG_MSG("\n");
+
+	switch (power_ctrl) {
+	case POWER_OFF:
+		if (ts->pdata->pwr->use_regulator) {
+			regulator_disable(ts->regulator_vio);
+			regulator_disable(ts->regulator_vdd);
+		}
+		else
+			ts->pdata->pwr->power(0);
+
+		break;
+	case POWER_ON:
+		if (ts->pdata->pwr->use_regulator) {
+			regulator_enable(ts->regulator_vdd);
+			regulator_enable(ts->regulator_vio);
+		}
+		else
+			ts->pdata->pwr->power(1);
+
+		/* P2 H/W bug fix */
+		if (ts->pdata->reset_pin > 0) {
+			msleep(10);
+			gpio_set_value(ts->pdata->reset_pin, 0);
+			msleep(ts->pdata->role->reset_delay);
+			gpio_set_value(ts->pdata->reset_pin, 1);
+		}
+		break;
+	case POWER_SLEEP:
+		if (unlikely(touch_i2c_write_byte(client, DEVICE_CONTROL_REG,
+					DEVICE_CONTROL_SLEEP |
+					DEVICE_CONTROL_CONFIGURED) < 0)) {
+			TOUCH_ERR_MSG("DEVICE_CONTROL_REG write fail\n");
+			return -EIO;
+		}
+		break;
+	case POWER_WAKE:
+		if (unlikely(touch_i2c_write_byte(client, DEVICE_CONTROL_REG,
+					DEVICE_CONTROL_SPECIFIC |
+					DEVICE_CONTROL_CONFIGURED) < 0)) {
+			TOUCH_ERR_MSG("DEVICE_CONTROL_REG write fail\n");
+			return -EIO;
+		}
+		break;
+	default:
+		return -EIO;
+		break;
+	}
+
+	return 0;
+}
+
+int synaptics_ts_probe(struct i2c_client* client)
+{
+	struct synaptics_ts_data* ts;
+	int ret = 0;
+
+	if (touch_debug_mask & DEBUG_TRACE)
+		TOUCH_DEBUG_MSG("\n");
+
+	ts = kzalloc(sizeof(struct synaptics_ts_data), GFP_KERNEL);
+	if (!ts) {
+		TOUCH_ERR_MSG("Can not allocate memory\n");
+		ret = -ENOMEM;
+		goto err_alloc_data_failed;
+	}
+
+	set_touch_handle(client, ts);
+
+	ts->client = client;
+	ts->pdata = client->dev.platform_data;
+#if defined(CONFIG_TOUCH_REG_MAP_TM2000)
+	ts->ic_panel_type = IC7020_G2_H_PTN;
+#elif defined(CONFIG_TOUCH_REG_MAP_TM2372)
+	ts->ic_panel_type = IC7020_GFF_H_PTN;
+#endif
+
+	if (ts->pdata->pwr->use_regulator) {
+		ts->regulator_vdd =
+			regulator_get_exclusive(NULL, ts->pdata->pwr->vdd);
+		if (IS_ERR(ts->regulator_vdd)) {
+			TOUCH_ERR_MSG("FAIL: regulator_get_vdd - %s\n",
+							ts->pdata->pwr->vdd);
+			ret = -EPERM;
+			goto err_get_vdd_failed;
+		}
+
+		ts->regulator_vio = regulator_get_exclusive(NULL,
+							ts->pdata->pwr->vio);
+		if (IS_ERR(ts->regulator_vio)) {
+			TOUCH_ERR_MSG("FAIL: regulator_get_vio - %s\n",
+							ts->pdata->pwr->vio);
+			ret = -EPERM;
+			goto err_get_vio_failed;
+		}
+
+		if (ts->pdata->pwr->vdd_voltage > 0) {
+			ret = regulator_set_voltage(ts->regulator_vdd,
+						ts->pdata->pwr->vdd_voltage,
+						ts->pdata->pwr->vdd_voltage);
+			if (ret < 0)
+				TOUCH_ERR_MSG("FAIL: VDD voltage setting"
+						" - (%duV)\n",
+						ts->pdata->pwr->vdd_voltage);
+		}
+
+		if (ts->pdata->pwr->vio_voltage > 0) {
+			ret = regulator_set_voltage(ts->regulator_vio,
+						ts->pdata->pwr->vio_voltage,
+						ts->pdata->pwr->vio_voltage);
+			if (ret < 0)
+				TOUCH_ERR_MSG("FAIL: VIO voltage setting"
+						" - (%duV)\n",
+						ts->pdata->pwr->vio_voltage);
+		}
+	}
+
+	return ret;
+
+err_get_vio_failed:
+	if (ts->pdata->pwr->use_regulator) {
+		regulator_put(ts->regulator_vdd);
+	}
+err_get_vdd_failed:
+err_alloc_data_failed:
+	kfree(ts);
+	return ret;
+}
+
+void synaptics_ts_remove(struct i2c_client* client)
+{
+	struct synaptics_ts_data* ts =
+			(struct synaptics_ts_data*)get_touch_handle(client);
+
+	if (touch_debug_mask & DEBUG_TRACE)
+		TOUCH_DEBUG_MSG("\n");
+
+	if (ts->pdata->pwr->use_regulator) {
+		regulator_put(ts->regulator_vio);
+		regulator_put(ts->regulator_vdd);
+	}
+
+	kfree(ts);
+}
+
+int synaptics_ts_fw_upgrade(struct i2c_client* client, const char* fw_path)
+{
+	struct synaptics_ts_data* ts =
+			(struct synaptics_ts_data*)get_touch_handle(client);
+	int ret = 0;
+
+	ts->is_probed = 0;
+
+	ret = FirmwareUpgrade(ts, fw_path);
+
+	/* update IC info */
+	get_ic_info(ts, ts->fw_info);
+
+	return ret;
+}
+
+int synaptics_ts_ic_ctrl(struct i2c_client *client, u8 code, u16 value)
+{
+	struct synaptics_ts_data* ts =
+			(struct synaptics_ts_data*)get_touch_handle(client);
+	u8 buf = 0;
+
+	switch (code) {
+	case IC_CTRL_BASELINE:
+		switch (value) {
+		case BASELINE_OPEN:
+#if defined(CONFIG_TOUCH_REG_MAP_TM2000) || defined(CONFIG_TOUCH_REG_MAP_TM2372)
+			if (unlikely(touch_i2c_write_byte(client,
+						PAGE_SELECT_REG, 0x01) < 0)) {
+				TOUCH_ERR_MSG("PAGE_SELECT_REG write fail\n");
+				return -EIO;
+			}
+
+			if (unlikely(touch_i2c_write_byte(client,
+						ANALOG_CONTROL_REG,
+						FORCE_FAST_RELAXATION) < 0)) {
+				TOUCH_ERR_MSG("ANALOG_CONTROL_REG write fail\n");
+				return -EIO;
+			}
+
+			msleep(10);
+
+			if (unlikely(touch_i2c_write_byte(client,
+						ANALOG_COMMAND_REG,
+						FORCE_UPDATE) < 0)) {
+				TOUCH_ERR_MSG("force fast relaxation command write fail\n");
+				return -EIO;
+			}
+
+			if (unlikely(touch_i2c_write_byte(client,
+						PAGE_SELECT_REG, 0x00) < 0)) {
+				TOUCH_ERR_MSG("PAGE_SELECT_REG write fail\n");
+				return -EIO;
+			}
+
+			if (unlikely(touch_debug_mask & DEBUG_GHOST))
+				TOUCH_INFO_MSG("BASELINE_OPEN  ~~~~~~~~\n");
+#else
+			if (unlikely(touch_i2c_write_byte(client,
+						MELT_CONTROL_REG,
+						MELT_CONTROL_MELT) < 0)) {
+				TOUCH_ERR_MSG("MELT_CONTROL_REG write fail\n");
+				return -EIO;
+			}
+#endif
+			break;
+		case BASELINE_FIX:
+#if defined(CONFIG_TOUCH_REG_MAP_TM2000) || defined(CONFIG_TOUCH_REG_MAP_TM2372)
+			if (unlikely(touch_i2c_write_byte(client,
+						PAGE_SELECT_REG, 0x01) < 0)) {
+				TOUCH_ERR_MSG("PAGE_SELECT_REG write fail\n");
+				return -EIO;
+			}
+
+			if (unlikely(touch_i2c_write_byte(client,
+						ANALOG_CONTROL_REG, 0x0) < 0)) {
+				TOUCH_ERR_MSG("ANALOG_CONTROL_REG write fail\n");
+				return -EIO;
+			}
+
+			msleep(10);
+
+			if (unlikely(touch_i2c_write_byte(client,
+						ANALOG_COMMAND_REG,
+						FORCE_UPDATE) < 0)) {
+				TOUCH_ERR_MSG("force fast relaxation command write fail\n");
+				return -EIO;
+			}
+
+			if (unlikely(touch_i2c_write_byte(client,
+						PAGE_SELECT_REG, 0x00) < 0)) {
+				TOUCH_ERR_MSG("PAGE_SELECT_REG write fail\n");
+				return -EIO;
+			}
+
+			if (unlikely(touch_debug_mask & DEBUG_GHOST))
+				TOUCH_INFO_MSG("BASELINE_FIX  ~~~~~~~~\n");
+#else
+			if (unlikely(touch_i2c_write_byte(client,
+						MELT_CONTROL_REG,
+						MELT_CONTROL_NO_MELT) < 0)) {
+				TOUCH_ERR_MSG("MELT_CONTROL_REG write fail\n");
+				return -EIO;
+			}
+#endif
+			break;
+		case BASELINE_REBASE:
+			/* rebase base line */
+			if (likely(ts->finger_dsc.id != 0)) {
+				if (unlikely(touch_i2c_write_byte(client,
+						FINGER_COMMAND_REG, 0x1) < 0)) {
+					TOUCH_ERR_MSG("finger baseline reset "
+							"command write fail\n");
+					return -EIO;
+				}
+			}
+
+#if defined(CONFIG_TOUCH_REG_MAP_TM2000) || defined(CONFIG_TOUCH_REG_MAP_TM2372)
+/* do nothing */
+#else
+			if (unlikely(ts->button_dsc.id != 0)) {
+				if (unlikely(touch_i2c_write_byte(client,
+						BUTTON_COMMAND_REG, 0x1) < 0)) {
+					TOUCH_ERR_MSG("finger baseline reset "
+							"command write fail\n");
+					return -EIO;
+				}
+			}
+#endif
+			break;
+		default:
+			break;
+		}
+		break;
+	case IC_CTRL_READ:
+		if (touch_i2c_read(client, value, 1, &buf) < 0) {
+			TOUCH_ERR_MSG("IC register read fail\n");
+			return -EIO;
+		}
+		break;
+	case IC_CTRL_WRITE:
+		if (touch_i2c_write_byte(client,
+				((value & 0xFF00) >> 8), (value & 0xFF)) < 0) {
+			TOUCH_ERR_MSG("IC register write fail\n");
+			return -EIO;
+		}
+		break;
+	case IC_CTRL_RESET_CMD:
+		if (unlikely(touch_i2c_write_byte(client,
+						DEVICE_COMMAND_REG, 0x1) < 0)) {
+			TOUCH_ERR_MSG("IC Reset command write fail\n");
+			return -EIO;
+		}
+		break;
+	default:
+		break;
+	}
+
+	return buf;
+}
+
+int synaptics_ts_fw_upgrade_check(struct lge_touch_data *ts)
+{
+#if defined(CONFIG_TOUCH_REG_MAP_TM2000)
+	if (ts->fw_info.fw_force_rework) {
+		TOUCH_INFO_MSG("FW-upgrade Force Rework.\n");
+	} else {
+		/* do not update 7020 gff, 7020 g2, 3203 g2 */
+		if (((ts->fw_info.fw_version[0] == '0' &&
+			(int)simple_strtoul(&ts->fw_info.fw_version[1], NULL, 10) == 0) ||
+		     (ts->fw_info.fw_version[0] == 'S' &&
+			(int)simple_strtoul(&ts->fw_info.fw_version[1], NULL, 10) == 1) ||
+		     (ts->fw_info.fw_version[0] == 'E' &&
+			(int)simple_strtoul(&ts->fw_info.fw_version[1], NULL, 10) < 27) ||
+		     (ts->fw_info.fw_version[0] == 'T'))) {
+			TOUCH_INFO_MSG("DO NOT UPDATE 7020 gff, 7020 g2, 3203 " "g2 FW-upgrade is not executed\n");
+			return -1;
+		}
+
+		if ((ts->fw_info.fw_version[0] == 'E' &&
+			(int)simple_strtoul(&ts->fw_info.fw_version[1], NULL, 10) >= 27) && !ts->fw_upgrade.fw_force_upgrade) { /* 7020 g2 h pattern */
+
+			if (((int)simple_strtoul(&ts->fw_info.fw_version[1], NULL, 10) >= (int)simple_strtoul(&ts->fw_info.fw_image_version[1], NULL, 10))) {
+	   			TOUCH_INFO_MSG("DO NOT UPDATE 7020 G2 H " "pattern FW-upgrade is not executed\n");
+				return -1;
+			} else {
+				TOUCH_INFO_MSG("7020 G2 H pattern FW-upgrade " "is executed\n");
+			}
+		} else {
+			if (!ts->fw_upgrade.fw_force_upgrade) {
+				TOUCH_INFO_MSG("UNKNOWN PANEL. FW-upgrade is" " not executed\n");
+				return -1;
+			}
+		}
+	}
+#elif defined(CONFIG_TOUCH_REG_MAP_TM2372)
+	if (ts->fw_info.fw_force_rework) {
+		TOUCH_INFO_MSG("FW-upgrade Force Rework.\n");
+	} else {
+		if ((ts->fw_info.fw_version[0] == 'E' &&
+			(int)simple_strtoul(&ts->fw_info.fw_version[1], NULL, 10) >= 1) &&
+			!ts->fw_upgrade.fw_force_upgrade) {
+
+			if (((int)simple_strtoul(&ts->fw_info.fw_version[1], NULL, 10) >=
+				(int)simple_strtoul(&ts->fw_info.fw_image_version[1],
+							NULL, 10))) {
+				TOUCH_INFO_MSG("DO NOT UPDATE 7020 GFF H " "pattern FW-upgrade is not executed\n");
+				return -1;
+			} else {
+				TOUCH_INFO_MSG("7020 GFF H pattern FW-upgrade " "is executed\n");
+			}
+		} else {
+			if (!ts->fw_upgrade.fw_force_upgrade) {
+				TOUCH_INFO_MSG("UNKNOWN PANEL. FW-upgrade is not executed\n");
+				return -1;
+			}
+		}
+	}
+#else
+	/* test revision should be over 100 */
+	if (((ts->fw_info.fw_rev >= ts->fw_info.fw_image_rev &&
+		ts->fw_info.fw_rev < 100) ||
+		strncmp(ts->fw_info.product_id ,
+			ts->fw_info.fw_image_product_id, 10)) &&
+		!ts->fw_upgrade.fw_force_upgrade) {
+		TOUCH_INFO_MSG("FW-upgrade is not executed\n");
+		return -1;
+	}
+#endif
+
+	return 0;
+}
+
+struct touch_device_driver synaptics_ts_driver = {
+	.probe            = synaptics_ts_probe,
+	.remove           = synaptics_ts_remove,
+	.init             = synaptics_ts_init,
+	.data             = synaptics_ts_get_data,
+	.power            = synaptics_ts_power,
+	.fw_upgrade       = synaptics_ts_fw_upgrade,
+	.ic_ctrl          = synaptics_ts_ic_ctrl,
+	.fw_upgrade_check = synaptics_ts_fw_upgrade_check,
+};
+
+static int __devinit touch_init(void)
+{
+	if (touch_debug_mask & DEBUG_TRACE)
+		TOUCH_DEBUG_MSG("\n");
+
+	return touch_driver_register(&synaptics_ts_driver);
+}
+
+static void __exit touch_exit(void)
+{
+	if (touch_debug_mask & DEBUG_TRACE)
+		TOUCH_DEBUG_MSG("\n");
+
+	touch_driver_unregister();
+}
+
+module_init(touch_init);
+module_exit(touch_exit);
+
+MODULE_AUTHOR("yehan.ahn@lge.com, hyesung.shin@lge.com");
+MODULE_DESCRIPTION("LGE Touch Driver");
+MODULE_LICENSE("GPL");
+