diff mbox series

[v3,3/4] HID: touchscreen: Add initial support for Himax HID-over-SPI

Message ID 20231017091900.801989-4-tylor_yang@himax.corp-partner.google.com (mailing list archive)
State New, archived
Delegated to: Jiri Kosina
Headers show
Series HID: touchscreen: add himax hid-over-spi driver | expand

Commit Message

Tylor Yang Oct. 17, 2023, 9:18 a.m. UTC
The hx83102j is a TDDI IC (Touch with Display Driver). The
IC using SPI to transferring HID packet to host CPU. The IC also
report HID report descriptor for driver to register HID device.
The driver is designed as a framework for future expansion and
hx83102j is the first case. Each hx_spi_hid_hx8xxxxx modules are
mutual exclusive, it should be initiate one at a time.

This driver takes a position similar to i2c-hid, it initialize
and control the touch IC below and register HID to upper hid-core.
When touch ic report an interrupt, it receive the data from IC
and report as HID input to hid-core. Let hid-core dispatch input
to registered hid-protocol and report to related input sub-system.

This driver also provide advanced functions by hidraw interface:
- runtime firmware update
- debug functions, such as reg r/w
- self test for touch panel

Due to patch size is too big, separate into 3 part. This is part 2.

Signed-off-by: Tylor Yang <tylor_yang@himax.corp-partner.google.com>
---
 drivers/hid/hx-hid/hx_ic_core.c | 3260 +++++++++++++++++++++++++++++++
 1 file changed, 3260 insertions(+)
 create mode 100644 drivers/hid/hx-hid/hx_ic_core.c
diff mbox series

Patch

diff --git a/drivers/hid/hx-hid/hx_ic_core.c b/drivers/hid/hx-hid/hx_ic_core.c
new file mode 100644
index 000000000000..f1a53a5b8ccf
--- /dev/null
+++ b/drivers/hid/hx-hid/hx_ic_core.c
@@ -0,0 +1,3260 @@ 
+// SPDX-License-Identifier: GPL-2.0
+/*  Himax Driver Code for Common IC to simulate HID
+ *
+ *  Copyright (C) 2023 Himax 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 "hx_ic_core.h"
+#include "hx_plat.h"
+#include "hx_hid.h"
+
+/* CORE_IC */
+/* IC side start*/
+static void himax_mcu_burst_enable(struct himax_ts_data *ts,
+				   u8 auto_add_4_byte)
+{
+	u8 tmp_data[DATA_LEN_4];
+	int ret;
+
+	/*I("Entering");*/
+	tmp_data[0] = IC_GET_VAL(data_conti);
+
+	ret = himax_bus_write(ts, IC_GET_VAL(addr_conti), NULL, tmp_data, 1);
+	if (ret < 0) {
+		E("bus access fail!");
+		return;
+	}
+
+	tmp_data[0] = (IC_GET_VAL(data_incr4) | auto_add_4_byte);
+
+	ret = himax_bus_write(ts, IC_GET_VAL(addr_incr4), NULL, tmp_data, 1);
+	if (ret < 0) {
+		E("bus access fail!");
+		return;
+	}
+}
+
+static int himax_mcu_register_read(struct himax_ts_data *ts, u8 *addr,
+				   u8 *buf, u32 len)
+{
+	int ret = -1;
+
+	mutex_lock(&ts->reg_lock);
+
+	if (memcmp(addr, FLASH_GET_ARRAY(addr_spi200_data), 4) == 0)
+		g_core_fp.fp_burst_enable(ts, 0);
+	else if (len > DATA_LEN_4)
+		g_core_fp.fp_burst_enable(ts, 1);
+	else
+		g_core_fp.fp_burst_enable(ts, 0);
+
+	ret = himax_bus_write(ts, IC_GET_VAL(addr_ahb_addr_byte_0), addr, NULL, 4);
+	if (ret < 0) {
+		E("bus access fail!");
+		mutex_unlock(&ts->reg_lock);
+		return BUS_FAIL;
+	}
+
+	ret = himax_bus_write(ts, IC_GET_VAL(addr_ahb_access_direction), NULL,
+			      IC_GET_ARRAY(data_ahb_access_direction_read), 1);
+	if (ret < 0) {
+		E("bus access fail!");
+		mutex_unlock(&ts->reg_lock);
+		return BUS_FAIL;
+	}
+
+	ret = himax_bus_read(ts, IC_GET_VAL(addr_ahb_rdata_byte_0), buf, len);
+	if (ret < 0) {
+		E("bus access fail!");
+		mutex_unlock(&ts->reg_lock);
+		return BUS_FAIL;
+	}
+
+	mutex_unlock(&ts->reg_lock);
+
+	return NO_ERR;
+}
+
+static int himax_mcu_reg_read(struct himax_ts_data *ts, struct hx_reg_t *addr,
+			      struct data_pack_t *data)
+{
+	return g_core_fp.fp_register_read(ts,
+		addr->data.byte, data->data.byte, data->len);
+}
+
+static int himax_mcu_register_write(struct himax_ts_data *ts, u8 *addr,
+				    u8 *val, u32 len)
+{
+	int ret = -1;
+	const u32 max_trans_sz = 4 * 1024;
+	int i = 0;
+	u32 orig_addr = 0;
+	union hx_dword_data_t temp_addr = {0};
+	u32 temp_len = 0;
+
+	mutex_lock(&ts->reg_lock);
+
+	if (memcmp(addr, FLASH_GET_ARRAY(addr_spi200_data), 4) == 0)
+		g_core_fp.fp_burst_enable(ts, 0);
+	else if (len > DATA_LEN_4)
+		g_core_fp.fp_burst_enable(ts, 1);
+	else
+		g_core_fp.fp_burst_enable(ts, 0);
+
+	if (len > max_trans_sz) {
+		orig_addr = le32_to_cpup((__le32 *)addr);
+		for (i = 0; i < len; i += max_trans_sz) {
+			if ((len - i) > max_trans_sz)
+				temp_len = max_trans_sz;
+			else
+				temp_len = len % max_trans_sz;
+			temp_addr.dword = cpu_to_le32(orig_addr + i);
+			ret = himax_bus_write(ts, IC_GET_VAL(addr_ahb_addr_byte_0),
+					      temp_addr.byte, val + i, temp_len + ADDR_LEN_4);
+			if (ret < 0) {
+				E("xfer fail!");
+				mutex_unlock(&ts->reg_lock);
+				return BUS_FAIL;
+			}
+		}
+	} else {
+		ret = himax_bus_write(ts, IC_GET_VAL(addr_ahb_addr_byte_0), addr, val,
+				      len + ADDR_LEN_4);
+		if (ret < 0) {
+			E("xfer fail!");
+			mutex_unlock(&ts->reg_lock);
+			return BUS_FAIL;
+		}
+	}
+
+	mutex_unlock(&ts->reg_lock);
+
+	return NO_ERR;
+}
+
+static int himax_mcu_reg_write(struct himax_ts_data *ts,
+			       struct hx_reg_t *addr, struct data_pack_t *data)
+{
+	return g_core_fp.fp_register_write(ts,
+		addr->data.byte, data->data.byte, data->len);
+}
+
+static int himax_write_read_reg(struct himax_ts_data *ts, u8 *tmp_addr,
+				u8 *tmp_data, u8 hb, u8 lb)
+{
+	u16 retry = 0;
+	union hx_dword_data_t r_data = {0};
+	union hx_dword_data_t t_addr = {0};
+	union hx_dword_data_t t_data = {0};
+
+	memcpy(t_addr.byte, tmp_addr, ADDR_LEN_4);
+	memcpy(t_data.byte, tmp_data, DATA_LEN_4);
+
+	while (retry++ < 40) { /* ceil[16.6*2] */
+		g_core_fp.fp_register_read(ts, t_addr.byte, r_data.byte, DATA_LEN_4);
+		D("Read handshake = 0x%08X:0x%08X", le32_to_cpu(t_addr.dword),
+		  le32_to_cpu(r_data.dword));
+		if (r_data.byte[1] == lb && r_data.byte[0] == hb)
+			break;
+		else if (r_data.byte[1] == hb && r_data.byte[0] == lb)
+			return NO_ERR;
+
+		g_core_fp.fp_register_write(ts, t_addr.byte, t_data.byte, DATA_LEN_4);
+		D("Write handshake = 0x%08X:0x%08X", le32_to_cpu(t_addr.dword),
+		  le32_to_cpu(t_data.dword));
+		usleep_range(1000, 1100);
+	}
+
+	if (retry >= 40)
+		goto FAIL;
+
+	retry = 0;
+	while (retry++ < 200) { /* self test item might take long time */
+		g_core_fp.fp_register_read(ts, t_addr.byte, r_data.byte, DATA_LEN_4);
+		if (r_data.byte[1] == hb && r_data.byte[0] == lb)
+			return NO_ERR;
+
+		D("wait data ready %d times, handshake = 0x%08X:0x%08X", retry,
+		  le32_to_cpu(t_addr.dword), le32_to_cpu(r_data.dword));
+		usleep_range(10000, 10100);
+	}
+
+FAIL:
+	E("failed to handshaking with DSRAM");
+	E("addr = 0x%02X%02X%02X%02X; data = 0x%02X%02X%02X%02X",
+	  tmp_addr[3], tmp_addr[2], tmp_addr[1], tmp_addr[0],
+	  tmp_data[3], tmp_data[2], tmp_data[1], tmp_data[0]);
+	E("target = %02X%02X; r_data = %02X%02X",
+	  hb, lb, r_data.byte[1], r_data.byte[0]);
+
+	return HX_RW_REG_FAIL;
+}
+
+static void himax_mcu_interface_on(struct himax_ts_data *ts)
+{
+	u8 tmp_data[DATA_LEN_4];
+	u8 tmp_data2[DATA_LEN_4];
+	int cnt = 0;
+	int ret = 0;
+
+	/* Read a dummy register to wake up BUS.*/
+	ret = himax_bus_read(ts, IC_GET_VAL(addr_ahb_rdata_byte_0), tmp_data,
+			     DATA_LEN_4);
+	if (ret < 0) {/* to knock BUS*/
+		E("bus access fail!");
+		return;
+	}
+
+	do {
+		tmp_data[0] = IC_GET_VAL(data_conti);
+
+		ret = himax_bus_write(ts, IC_GET_VAL(addr_conti), NULL, tmp_data, 1);
+		if (ret < 0) {
+			E("bus access fail!");
+			return;
+		}
+
+		tmp_data[0] = IC_GET_VAL(data_incr4);
+
+		ret = himax_bus_write(ts, IC_GET_VAL(addr_incr4), NULL, tmp_data, 1);
+		if (ret < 0) {
+			E("bus access fail!");
+			return;
+		}
+
+		/*Check cmd*/
+		himax_bus_read(ts, IC_GET_VAL(addr_conti), tmp_data, 1);
+		himax_bus_read(ts, IC_GET_VAL(addr_incr4), tmp_data2, 1);
+
+		if (tmp_data[0] == IC_GET_VAL(data_conti) &&
+		    tmp_data2[0] == IC_GET_VAL(data_incr4))
+			break;
+
+		usleep_range(1000, 1100);
+	} while (++cnt < 10);
+
+	if (cnt > 0)
+		I("Polling burst mode: %d times", cnt);
+}
+
+static void himax_mcu_sense_on(struct himax_ts_data *ts, u8 flash_mode)
+{
+	u8 tmp_data[DATA_LEN_4];
+	int retry = 0;
+	int ret = 0;
+
+	I("Enter");
+	ts->notouch_frame = ts->ic_notouch_frame;
+	g_core_fp.fp_interface_on(ts);
+	g_core_fp.fp_register_write(ts, FW_GET_ARRAY(addr_ctrl_fw_isr),
+		FW_GET_ARRAY(data_clear), FW_GET_SZ(data_clear));
+	usleep_range(10000, 11000);
+	if (!flash_mode) {
+		g_core_fp.fp_ic_reset(ts, false, false);
+	} else {
+		do {
+			g_core_fp.fp_register_read(ts,
+				FW_GET_ARRAY(addr_flag_reset_event),
+				tmp_data, DATA_LEN_4);
+			I("Read status from IC = %X,%X", tmp_data[0], tmp_data[1]);
+		} while ((tmp_data[1] != 0x01 ||
+			tmp_data[0] != 0x00) &&
+			retry++ < 5);
+
+		if (retry >= 5) {
+			E("Fail");
+			g_core_fp.fp_ic_reset(ts, false, false);
+		} else {
+			I("OK and Read status from IC = %X,%X",
+			  tmp_data[0], tmp_data[1]);
+			/* reset code*/
+			tmp_data[0] = 0x00;
+
+			ret = himax_bus_write(ts, IC_GET_VAL(adr_i2c_psw_lb), NULL,
+					      tmp_data, 1);
+			if (ret < 0) {
+				E("cmd=%x bus access fail!",
+				  IC_GET_VAL(adr_i2c_psw_lb));
+			}
+			ret = himax_bus_write(ts, IC_GET_VAL(adr_i2c_psw_ub), NULL,
+					      tmp_data, 1);
+			if (ret < 0) {
+				E("cmd=%x bus access fail!",
+				  IC_GET_VAL(adr_i2c_psw_ub));
+			}
+		}
+	}
+}
+
+static bool himax_mcu_sense_off(struct himax_ts_data *ts, bool check_en)
+{
+	u8 cnt = 0;
+	u8 tmp_data[DATA_LEN_4];
+	int ret = 0;
+
+	do {
+		tmp_data[0] = IC_GET_VAL(data_i2c_psw_lb);
+		tmp_data[1] = IC_GET_VAL(data_i2c_psw_ub);
+
+		ret = himax_bus_write(ts, IC_GET_VAL(adr_i2c_psw_lb), NULL, tmp_data,
+				      2);
+		if (ret < 0) {
+			E("bus access fail!");
+			return false;
+		}
+
+		g_core_fp.fp_register_read(ts, IC_GET_ARRAY(addr_cs_central_state),
+			tmp_data, ADDR_LEN_4);
+		I("Check enter_save_mode data[0]=%X", tmp_data[0]);
+
+		if (tmp_data[0] == 0x0C) {
+			g_core_fp.fp_register_write(ts, IC_GET_ARRAY(addr_tcon_on_rst),
+				IC_GET_ARRAY(data_rst), DATA_LEN_4);
+			usleep_range(1000, 1100);
+
+			g_core_fp.fp_register_write(ts, IC_GET_ARRAY(addr_adc_on_rst),
+				IC_GET_ARRAY(data_rst), DATA_LEN_4);
+			usleep_range(1000, 1100);
+			tmp_data[3] = IC_GET_ARRAY(data_rst)[3];
+			tmp_data[2] = IC_GET_ARRAY(data_rst)[2];
+			tmp_data[1] = IC_GET_ARRAY(data_rst)[1];
+			tmp_data[0] = IC_GET_ARRAY(data_rst)[0] | 0x01;
+			g_core_fp.fp_register_write(ts, IC_GET_ARRAY(addr_adc_on_rst),
+				tmp_data, DATA_LEN_4);
+			goto TRUE_END;
+		} else {
+			/* usleep_range(10000, 10001); */
+			g_core_fp.fp_ic_reset(ts, false, false);
+		}
+	} while (cnt++ < 15);
+
+	return false;
+TRUE_END:
+	return true;
+}
+
+#define WIP_PRT_LOG "retry:%d, bf[0]=%d, bf[1]=%d,bf[2]=%d, bf[3]=%d"
+static bool himax_mcu_wait_wip(struct himax_ts_data *ts, int timing)
+{
+	u8 tmp_data[DATA_LEN_4];
+	int retry_cnt = 0;
+
+	g_core_fp.fp_register_write(ts, FLASH_GET_ARRAY(addr_spi200_trans_fmt),
+		FLASH_GET_ARRAY(data_spi200_trans_fmt), DATA_LEN_4);
+	tmp_data[0] = 0x01;
+
+	do {
+		g_core_fp.fp_register_write(ts,
+			FLASH_GET_ARRAY(addr_spi200_trans_ctrl),
+			FLASH_GET_ARRAY(data_spi200_trans_ctrl_1), DATA_LEN_4);
+
+		g_core_fp.fp_register_write(ts, FLASH_GET_ARRAY(addr_spi200_cmd),
+			FLASH_GET_ARRAY(data_spi200_cmd_1), DATA_LEN_4);
+		memset(tmp_data, 0xFF, DATA_LEN_4);
+		g_core_fp.fp_register_read(ts, FLASH_GET_ARRAY(addr_spi200_data),
+			tmp_data, 4);
+
+		if ((tmp_data[0] & 0x01) == 0x00)
+			return true;
+
+		retry_cnt++;
+
+		if (tmp_data[0] != 0x00 ||
+		    tmp_data[1] != 0x00 ||
+		    tmp_data[2] != 0x00 ||
+		    tmp_data[3] != 0x00)
+			I(WIP_PRT_LOG,
+			  retry_cnt, tmp_data[0],
+			  tmp_data[1], tmp_data[2], tmp_data[3]);
+
+		if (retry_cnt > 100) {
+			E("Wait wip error!");
+			return false;
+		}
+
+		usleep_range(timing * 1000, timing * 1000 + 1);
+	} while ((tmp_data[0] & 0x01) == 0x01);
+
+	return true;
+}
+
+/*power saving level*/
+static void himax_mcu_init_psl(struct himax_ts_data *ts)
+{
+	g_core_fp.fp_register_write(ts, IC_GET_ARRAY(addr_psl),
+		IC_GET_ARRAY(data_rst), IC_GET_SZ(data_rst));
+	I("power saving level reset OK!");
+}
+
+static void himax_mcu_resume_ic_action(struct himax_ts_data *ts)
+{
+	/* Nothing to do */
+}
+
+static void himax_mcu_suspend_ic_action(struct himax_ts_data *ts)
+{
+	/* Nothing to do */
+}
+
+static void himax_mcu_power_on_init(struct himax_ts_data *ts)
+{
+	union hx_dword_data_t tmp_data = { .byte = {0x01, 0x00, 0x00, 0x00} };
+	u8 retry = 0;
+
+	/*RawOut select initial*/
+	g_core_fp.fp_register_write(ts, FW_GET_ARRAY(addr_raw_out_sel),
+		FW_GET_ARRAY(data_clear), FW_GET_SZ(data_clear));
+	/*DSRAM func initial*/
+	g_core_fp.fp_assign_sorting_mode(ts, FW_GET_ARRAY(data_clear));
+	/*N frame initial*/
+	/* reset N frame back to default value 1 for normal mode */
+	g_core_fp.fp_register_write(ts, FW_GET_ARRAY(addr_set_frame_addr),
+		tmp_data.byte, 4);
+	/*FW reload done initial*/
+	g_core_fp.fp_register_write(ts,
+		DRV_GET_ARRAY(addr_fw_define_2nd_flash_reload),
+		FW_GET_ARRAY(data_clear), FW_GET_SZ(data_clear));
+
+	g_core_fp.fp_sense_on(ts, 0x00);
+
+	I("waiting for FW reload data");
+
+	while (retry++ < 30) {
+		g_core_fp.fp_register_read(ts,
+			DRV_GET_ARRAY(addr_fw_define_2nd_flash_reload), tmp_data.byte,
+			DATA_LEN_4);
+
+		/* use all 4 bytes to compare */
+		if (le32_to_cpu(tmp_data.dword) == 0x72C0) {
+			I("FW reload done");
+			break;
+		}
+		I("wait FW reload %d times", retry);
+		g_core_fp.fp_read_FW_status(ts);
+		usleep_range(10000, 11000);
+	}
+}
+
+/* IC side end*/
+/* CORE_IC */
+
+/* CORE_FW */
+/* FW side start*/
+static void himax_mcu_system_reset(struct himax_ts_data *ts)
+{
+	int ret = 0;
+	u8 tmp_data[DATA_LEN_4];
+	int retry = 0;
+
+	g_core_fp.fp_interface_on(ts);
+	g_core_fp.fp_register_write(ts, FW_GET_ARRAY(addr_ctrl_fw_isr),
+		FW_GET_ARRAY(data_clear), FW_GET_SZ(data_clear));
+	do {
+		/* reset code*/
+		/**
+		 * I2C_password[7:0] set Enter safe mode : 0x31 ==> 0x27
+		 */
+		tmp_data[0] = IC_GET_VAL(data_i2c_psw_lb);
+
+		ret = himax_bus_write(ts, IC_GET_VAL(adr_i2c_psw_lb), NULL, tmp_data,
+				      1);
+		if (ret < 0)
+			E("bus access fail!");
+
+		/**
+		 * I2C_password[15:8] set Enter safe mode :0x32 ==> 0x95
+		 */
+		tmp_data[0] = IC_GET_VAL(data_i2c_psw_ub);
+
+		ret = himax_bus_write(ts, IC_GET_VAL(adr_i2c_psw_ub), NULL, tmp_data,
+				      1);
+		if (ret < 0)
+			E("bus access fail!");
+
+		/**
+		 * I2C_password[7:0] set Enter safe mode : 0x31 ==> 0x00
+		 */
+		tmp_data[0] = 0x00;
+
+		ret = himax_bus_write(ts, IC_GET_VAL(adr_i2c_psw_lb), NULL, tmp_data,
+				      1);
+		if (ret < 0)
+			E("bus access fail!");
+
+		usleep_range(10000, 11000);
+
+		g_core_fp.fp_register_read(ts, FW_GET_ARRAY(addr_flag_reset_event),
+			tmp_data, DATA_LEN_4);
+		I("Read status from IC = %X,%X", tmp_data[0], tmp_data[1]);
+	} while ((tmp_data[1] != 0x02 || tmp_data[0] != 0x00) && retry++ < 5);
+}
+
+static int himax_mcu_calculate_crc_with_ap(const unsigned char *FW_content,
+					   int CRC_from_FW, int len)
+{
+	int i, j, length = 0;
+	int fw_data;
+	int fw_data_2;
+	int CRC = 0xFFFFFFFF;
+	int polynomial = 0x82F63B78;
+
+	length = len / 4;
+
+	for (i = 0; i < length; i++) {
+		fw_data = FW_content[i * 4];
+
+		for (j = 1; j < 4; j++) {
+			fw_data_2 = FW_content[i * 4 + j];
+			fw_data += (fw_data_2) << (8 * j);
+		}
+		CRC = fw_data ^ CRC;
+		for (j = 0; j < 32; j++) {
+			if ((CRC % 2) != 0)
+				CRC = ((CRC >> 1) & 0x7FFFFFFF) ^ polynomial;
+			else
+				CRC = (((CRC >> 1) & 0x7FFFFFFF));
+		}
+	}
+
+	return CRC;
+}
+
+static u32 himax_mcu_check_crc(struct himax_ts_data *ts,
+			       u8 *start_addr, int reload_length)
+{
+	u32 result = 0;
+	union {
+		u8 byte[4];
+		u16 word[2];
+		u32 dword;
+	} tmp_data = {0};
+	int cnt = 0, ret = 0;
+	int length = reload_length / DATA_LEN_4;
+
+	ret = g_core_fp.fp_register_write(ts, FW_GET_ARRAY(addr_reload_addr_from),
+		start_addr, DATA_LEN_4);
+	if (ret < NO_ERR) {
+		E("bus access fail!");
+		return HW_CRC_FAIL;
+	}
+
+	tmp_data.word[1] = 0x0099;
+	tmp_data.word[1] = cpu_to_le16(tmp_data.word[1]);
+	tmp_data.word[0] = length;
+	tmp_data.word[0] = cpu_to_le16(tmp_data.word[0]);
+	ret = g_core_fp.fp_register_write(ts,
+		FW_GET_ARRAY(addr_reload_addr_cmd_beat), tmp_data.byte, DATA_LEN_4);
+	if (ret < NO_ERR) {
+		E("bus access fail!");
+		return HW_CRC_FAIL;
+	}
+	tmp_data.word[0] = 0x0000;
+
+	ret = g_core_fp.fp_register_read(ts,
+		FW_GET_ARRAY(addr_reload_addr_cmd_beat), tmp_data.byte, DATA_LEN_4);
+
+	if (le16_to_cpu(tmp_data.word[0]) != length) {
+		E("Flash content is Wrong");
+		return HW_CRC_FAIL;
+	}
+
+	cnt = 0;
+
+	do {
+		ret = g_core_fp.fp_register_read(ts, FW_GET_ARRAY(addr_reload_status),
+			tmp_data.byte, DATA_LEN_4);
+		if (ret < NO_ERR) {
+			E("bus access fail!");
+			return HW_CRC_FAIL;
+		}
+
+		if ((tmp_data.byte[0] & 0x01) != 0x01) {
+			ret = g_core_fp.fp_register_read(ts,
+				FW_GET_ARRAY(addr_reload_crc32_result), tmp_data.byte,
+				DATA_LEN_4);
+			if (ret < NO_ERR) {
+				E("bus access fail!");
+				return HW_CRC_FAIL;
+			}
+			I("data[3]=%X,data[2]=%X,data[1]=%X,data[0]=%X",
+			  tmp_data.byte[3],
+			  tmp_data.byte[2],
+			  tmp_data.byte[1],
+			  tmp_data.byte[0]);
+			result = tmp_data.dword;
+			goto END;
+		} else {
+			I("Waiting for HW ready!");
+			usleep_range(1000, 1100);
+			if (cnt >= 100)
+				g_core_fp.fp_read_FW_status(ts);
+		}
+
+	} while (cnt++ < 100);
+END:
+	return result;
+}
+
+static void himax_mcu_set_reload_cmd(u8 *write_data, int idx,
+				     u32 cmd_from, u32 cmd_to, u32 cmd_beat)
+{
+	int index = idx * 12;
+	int i;
+
+	for (i = 3; i >= 0; i--) {
+		write_data[index + i] = (cmd_from >> (8 * i));
+		write_data[index + 4 + i] = (cmd_to >> (8 * i));
+		write_data[index + 8 + i] = (cmd_beat >> (8 * i));
+	}
+}
+
+static bool himax_mcu_program_reload(void)
+{
+	return true;
+}
+
+static void himax_mcu_usb_detect_set(struct himax_ts_data *ts,
+				     const u8 *cable_config)
+{
+	struct hx_reg_t tmp_reg;
+	struct hx_reg_t back_reg;
+	u8 retry_cnt = 0;
+
+	do {
+		if (cable_config[1] == 0x01) {
+			WORD_REG(tmp_reg, fw_func_handshaking_pwd);
+			g_core_fp.fp_register_write(ts, FW_GET_ARRAY(addr_usb_detect),
+				REG_GET_ARRAY(tmp_reg), REG_GET_SZ(tmp_reg));
+			WORD_REG(back_reg, fw_func_handshaking_pwd);
+			I("USB detect status IN!");
+		} else {
+			WORD_REG(tmp_reg, fw_data_safe_mode_release_pw_reset);
+			g_core_fp.fp_register_write(ts, FW_GET_ARRAY(addr_usb_detect),
+				REG_GET_ARRAY(tmp_reg), REG_GET_SZ(tmp_reg));
+			WORD_REG(back_reg, fw_data_safe_mode_release_pw_reset);
+			I("USB detect status OUT!");
+		}
+
+		g_core_fp.fp_register_read(ts, FW_GET_ARRAY(addr_usb_detect),
+			REG_GET_ARRAY(tmp_reg), REG_GET_SZ(tmp_reg));
+		/*I("tmp_data[0]=%d, USB detect=%d, retry_cnt=%d",
+		 *	tmp_data[0], cable_config[1], retry_cnt);
+		 */
+		retry_cnt++;
+	} while ((REG_GET_ARRAY(tmp_reg)[3] != REG_GET_ARRAY(back_reg)[3] ||
+		REG_GET_ARRAY(tmp_reg)[2] != REG_GET_ARRAY(back_reg)[2] ||
+		REG_GET_ARRAY(tmp_reg)[1] != REG_GET_ARRAY(back_reg)[1] ||
+		REG_GET_ARRAY(tmp_reg)[0] != REG_GET_ARRAY(back_reg)[0]) &&
+		retry_cnt < HIMAX_REG_RETRY_TIMES);
+}
+
+#define PRT_DATA "[3]=0x%02X, [2]=0x%02X, [1]=0x%02X, [0]=0x%02X"
+static void himax_mcu_diag_register_set(struct himax_ts_data *ts,
+					u8 diag_command)
+{
+	u8 tmp_data[DATA_LEN_4];
+	u8 back_data[DATA_LEN_4];
+	u8 cnt = 50;
+
+	tmp_data[0] = diag_command;
+	I("diag_command = %d, tmp_data[0] = %X", diag_command, tmp_data[0]);
+	g_core_fp.fp_interface_on(ts);
+	tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00;
+	do {
+		g_core_fp.fp_register_write(ts, FW_GET_ARRAY(addr_raw_out_sel),
+			tmp_data, DATA_LEN_4);
+		g_core_fp.fp_register_read(ts, FW_GET_ARRAY(addr_raw_out_sel), back_data,
+			DATA_LEN_4);
+		I(PRT_DATA, back_data[3], back_data[2], back_data[1], back_data[0]);
+		cnt--;
+	} while (tmp_data[0] != back_data[0] && cnt > 0);
+}
+
+static int himax_mcu_diag_register_get(struct himax_ts_data *ts,
+				       u32 *diag_value)
+{
+	int ret = 0;
+	union hx_dword_data_t *tmp_data = (union hx_dword_data_t *)diag_value;
+
+	if (tmp_data) {
+		ret = g_core_fp.fp_register_read(ts, FW_GET_ARRAY(addr_raw_out_sel),
+			tmp_data->byte, DATA_LEN_4);
+	} else {
+		E("diag_value is NULL");
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+#define PRT_TMP_DATA "[0]=0x%2X,[1]=0x%2X,	[2]=0x%2X,[3]=0x%2X"
+static void himax_mcu_idle_mode(struct himax_ts_data *ts, int disable)
+{
+	int retry = 20;
+	u8 tmp_data[DATA_LEN_4];
+	u8 switch_cmd = 0x00;
+
+	I("entering");
+
+	do {
+		I("now %d times!", retry);
+		g_core_fp.fp_register_read(ts, FW_GET_ARRAY(addr_fw_mode_status),
+			tmp_data, DATA_LEN_4);
+
+		if (disable)
+			switch_cmd = FW_GET_ARRAY(data_idle_dis_pwd)[0];
+		else
+			switch_cmd = FW_GET_ARRAY(data_idle_en_pwd)[0];
+
+		tmp_data[0] = switch_cmd;
+		g_core_fp.fp_register_write(ts, FW_GET_ARRAY(addr_fw_mode_status),
+			tmp_data, DATA_LEN_4);
+		g_core_fp.fp_register_read(ts, FW_GET_ARRAY(addr_fw_mode_status),
+			tmp_data, DATA_LEN_4);
+
+		I(PRT_TMP_DATA,	tmp_data[0], tmp_data[1], tmp_data[2], tmp_data[3]);
+
+		retry--;
+		usleep_range(10000, 11000);
+	} while ((tmp_data[0] != switch_cmd) && retry > 0);
+
+	I("setting OK!");
+}
+
+static void himax_mcu_reload_disable(struct himax_ts_data *ts, int disable)
+{
+	I("entering");
+
+	if (disable) { /*reload disable*/
+		g_core_fp.fp_register_write(ts,
+			DRV_GET_ARRAY(addr_fw_define_flash_reload),
+			DRV_GET_ARRAY(data_fw_define_flash_reload_dis),
+			DATA_LEN_4);
+	} else { /*reload enable*/
+		g_core_fp.fp_register_write(ts,
+			DRV_GET_ARRAY(addr_fw_define_flash_reload),
+			DRV_GET_ARRAY(data_fw_define_flash_reload_en),
+			DATA_LEN_4);
+	}
+
+	I("setting OK!");
+}
+
+static int himax_mcu_read_ic_trigger_type(struct himax_ts_data *ts)
+{
+	u8 tmp_data[DATA_LEN_4];
+	int trigger_type = false;
+
+	g_core_fp.fp_register_read(ts, DRV_GET_ARRAY(addr_fw_define_int_is_edge),
+		tmp_data, DATA_LEN_4);
+
+	if ((tmp_data[1] & 0x01) == 1)
+		trigger_type = true;
+
+	return trigger_type;
+}
+
+/* Please call this function after FW finish reload done */
+static void himax_mcu_read_FW_ver(struct himax_ts_data *ts)
+{
+	u8 data[12] = {0};
+
+	g_core_fp.fp_register_read(ts, FW_GET_ARRAY(addr_fw_ver_addr), data,
+		DATA_LEN_4);
+	ts->ic_data->vendor_panel_ver =  data[0];
+	ts->ic_data->vendor_fw_ver = data[1] << 8 | data[2];
+	I("PANEL_VER : %X", ts->ic_data->vendor_panel_ver);
+	I("FW_VER : %X", ts->ic_data->vendor_fw_ver);
+	g_core_fp.fp_register_read(ts, FW_GET_ARRAY(addr_fw_cfg_addr), data,
+		DATA_LEN_4);
+	ts->ic_data->vendor_config_ver = data[2] << 8 | data[3];
+	/*I("CFG_VER : %X",ts->ic_data->vendor_config_ver);*/
+	ts->ic_data->vendor_touch_cfg_ver = data[2];
+	I("TOUCH_VER : %X", ts->ic_data->vendor_touch_cfg_ver);
+	ts->ic_data->vendor_display_cfg_ver = data[3];
+	I("DISPLAY_VER : %X", ts->ic_data->vendor_display_cfg_ver);
+	g_core_fp.fp_register_read(ts, FW_GET_ARRAY(addr_fw_vendor_addr), data,
+		DATA_LEN_4);
+	ts->ic_data->vendor_cid_maj_ver = data[2];
+	ts->ic_data->vendor_cid_min_ver = data[3];
+	I("CID_VER : %X", (ts->ic_data->vendor_cid_maj_ver << 8
+			| ts->ic_data->vendor_cid_min_ver));
+	g_core_fp.fp_register_read(ts, FW_GET_ARRAY(addr_cus_info), data, 12);
+	memcpy(ts->ic_data->vendor_cus_info, data, 12);
+	I("Cusomer ID = %s", ts->ic_data->vendor_cus_info);
+	g_core_fp.fp_register_read(ts, FW_GET_ARRAY(addr_proj_info), data, 12);
+	memcpy(ts->ic_data->vendor_proj_info, data, 12);
+	I("Project ID = %s", ts->ic_data->vendor_proj_info);
+	hx_hid_update_info(ts);
+}
+
+static bool himax_mcu_read_event_stack(struct himax_ts_data *ts, u8 *buf,
+				       u32 length)
+{
+	u8 cmd[DATA_LEN_4];
+	struct time_var t_start, t_end, t_delta;
+	int len = length;
+	int i2c_speed = 0;
+	int ret = 0;
+
+	/*  AHB_I2C Burst Read Off */
+	cmd[0] = FW_GET_VAL(data_ahb_dis);
+
+	ret = himax_bus_write(ts, FW_GET_VAL(addr_ahb_addr), NULL, cmd, 1);
+	if (ret < 0) {
+		E("bus access fail!");
+		return 0;
+	}
+	if (ts->debug_log_level & BIT(2))
+		time_func(&t_start);
+
+	himax_bus_read(ts, FW_GET_VAL(addr_event_addr), buf, length);
+
+	if (ts->debug_log_level & BIT(2)) {
+		time_func(&t_end);
+		t_delta.tv_nsec = (t_end.tv_sec * 1000000000 + t_end.tv_nsec)
+			- (t_start.tv_sec * 1000000000 + t_start.tv_nsec);
+
+		i2c_speed = (len * 9 * 1000000
+			/ (int)t_delta.tv_nsec) * 13 / 10;
+		ts->bus_speed = (int)i2c_speed;
+	}
+
+	/*  AHB_I2C Burst Read On */
+	cmd[0] = FW_GET_VAL(data_ahb_en);
+
+	ret = himax_bus_write(ts, FW_GET_VAL(addr_ahb_addr), NULL, cmd, 1);
+	if (ret < 0) {
+		E("bus access fail!");
+		return 0;
+	}
+
+	return 1;
+}
+
+static void himax_mcu_return_event_stack(struct himax_ts_data *ts)
+{
+	int retry = 20, i;
+	u8 tmp_data[DATA_LEN_4];
+
+	I("entering");
+
+	do {
+		I("now %d times!", retry);
+
+		for (i = 0; i < DATA_LEN_4; i++)
+			tmp_data[i] = SRAM_GET_ARRAY(addr_rawdata_end)[i];
+
+		g_core_fp.fp_register_write(ts, SRAM_GET_ARRAY(addr_rawdata_addr),
+			tmp_data, DATA_LEN_4);
+		g_core_fp.fp_register_read(ts, SRAM_GET_ARRAY(addr_rawdata_addr),
+			tmp_data, DATA_LEN_4);
+		retry--;
+		usleep_range(10000, 11000);
+	} while ((tmp_data[1] != SRAM_GET_ARRAY(addr_rawdata_end)[1] &&
+		tmp_data[0] != SRAM_GET_ARRAY(addr_rawdata_end)[0]) &&
+		retry > 0);
+
+	I("End of setting!");
+}
+
+static bool himax_mcu_calculate_checksum(struct himax_ts_data *ts,
+					 bool change_iref, u32 size)
+{
+	u32 CRC_result = 0xFFFFFFFF;
+	u8 i;
+	u8 tmp_data[DATA_LEN_4];
+
+	I("Now size=%d", size);
+	for (i = 0; i < DATA_LEN_4; i++)
+		tmp_data[i] = SRAM_GET_ARRAY(addr_rawdata_end)[i];
+
+	CRC_result = g_core_fp.fp_check_crc(ts, tmp_data, size);
+	usleep_range(50000, 50001);
+
+	if (CRC_result != 0)
+		I("CRC Fail=%d", CRC_result);
+
+	return (CRC_result == 0) ? true : false;
+}
+
+static u32 dbg_reg_ary[4] = {fw_addr_fw_dbg_msg_addr,
+	fw_addr_chk_fw_status, fw_addr_chk_dd_status, fw_addr_flag_reset_event};
+
+static void himax_mcu_read_FW_status(struct himax_ts_data *ts)
+{
+	u8 len = 0;
+	u8 i = 0;
+	struct hx_reg_t addr_reg;
+	u8 data[4] = {0};
+
+	len = (u8)(sizeof(dbg_reg_ary) / sizeof(u32));
+
+	for (i = 0; i < len; i++) {
+		WORD_REG(addr_reg, dbg_reg_ary[i]);
+		g_core_fp.fp_register_read(ts, REG_GET_ARRAY(addr_reg),
+			data, DATA_LEN_4);
+
+		I("reg[0-3] : 0x%08X = 0x%02X, 0x%02X, 0x%02X, 0x%02X",
+		  dbg_reg_ary[i], data[0], data[1], data[2], data[3]);
+	}
+}
+
+static void himax_mcu_irq_switch(struct himax_ts_data *ts, int switch_on)
+{
+	if (switch_on) {
+		if (ts->use_irq)
+			himax_int_enable(ts, switch_on);
+		else
+			hrtimer_start(&ts->timer, ktime_set(1, 0),
+				      HRTIMER_MODE_REL);
+	} else {
+		if (ts->use_irq) {
+			himax_int_enable(ts, switch_on);
+		} else {
+			hrtimer_cancel(&ts->timer);
+			cancel_work_sync(&ts->work);
+		}
+	}
+}
+
+static int himax_mcu_assign_sorting_mode(struct himax_ts_data *ts,
+					 u8 *tmp_data_in)
+{
+	u8 retry = 0;
+	union hx_dword_data_t rdata = {0};
+	u32 sorting_addr = FW_GET_VAL(addr_sorting_mode_en);
+	union hx_dword_data_t *tmp_data = (union hx_dword_data_t *)tmp_data_in;
+
+	I("addr: 0x%08X, write: 0x%08X",
+	  sorting_addr, le32_to_cpu(tmp_data->dword));
+
+	while (retry++ < 3) {
+		g_core_fp.fp_register_write(ts, FW_GET_ARRAY(addr_sorting_mode_en),
+			tmp_data->byte, DATA_LEN_4);
+		usleep_range(1000, 1100);
+		g_core_fp.fp_register_read(ts, FW_GET_ARRAY(addr_sorting_mode_en),
+			rdata.byte, DATA_LEN_4);
+
+		if (rdata.dword == tmp_data->dword) {
+			I("success to write sorting mode");
+			return NO_ERR;
+		}
+		E("fail to write sorting mode");
+	}
+
+	return BUS_FAIL;
+}
+
+static int himax_mcu_check_sorting_mode(struct himax_ts_data *ts,
+					u8 *tmp_data_in)
+{
+	int ret = NO_ERR;
+	u32 sorting_addr = FW_GET_VAL(addr_sorting_mode_en);
+	union hx_dword_data_t *tmp_data = (union hx_dword_data_t *)tmp_data_in;
+
+	ret = g_core_fp.fp_register_read(ts, FW_GET_ARRAY(addr_sorting_mode_en),
+		tmp_data->byte, DATA_LEN_4);
+	I("addr: 0x%08X, Now is:0x%08X",
+	  sorting_addr, le32_to_cpu(tmp_data->dword));
+	if (tmp_data->dword == 0xFFFFFFFF) {
+		ret = BUS_FAIL;
+		I("All 0xFF, Fail!");
+	}
+
+	return ret;
+}
+
+static u8 himax_mcu_read_DD_status(struct himax_ts_data *ts,
+				   u8 *cmd_set, u8 *tmp_data)
+{
+	int cnt = 0;
+	u8 req_size = cmd_set[0];
+
+	cmd_set[3] = FW_GET_ARRAY(data_dd_request)[0];
+	g_core_fp.fp_register_write(ts, FW_GET_ARRAY(addr_dd_handshak_addr),
+		cmd_set, DATA_LEN_4);
+	I("cmd set[0]=0x%2X,set[1]=0x%2X,set[2]=0x%2X,set[3]=0x%2X",
+	  cmd_set[0], cmd_set[1], cmd_set[2], cmd_set[3]);
+
+	/* Doing hand shaking 0xAA -> 0xBB */
+	for (cnt = 0; cnt < 100; cnt++) {
+		g_core_fp.fp_register_read(ts, FW_GET_ARRAY(addr_dd_handshak_addr),
+			tmp_data, DATA_LEN_4);
+		usleep_range(10000, 11000);
+
+		if (tmp_data[3] == FW_GET_ARRAY(data_dd_ack)[0]) {
+			I("Data ready goto moving data");
+			goto FINALIZE;
+		} else {
+			if (cnt >= 99) {
+				I("Data not ready in FW");
+				return FW_NOT_READY;
+			}
+		}
+	}
+FINALIZE:
+	g_core_fp.fp_register_read(ts, FW_GET_ARRAY(addr_dd_data_addr), tmp_data,
+		req_size);
+	return NO_ERR;
+}
+
+static void hx_clr_fw_reord_dd_sts(struct himax_ts_data *ts)
+{
+	union hx_dword_data_t tmp_data = {0};
+
+	g_core_fp.fp_register_read(ts, IC_GET_ARRAY(addr_cs_central_state),
+		tmp_data.byte, ADDR_LEN_4);
+	I("Check enter_save_mode data[0]=%02X", tmp_data.byte[0]);
+
+	if (tmp_data.byte[0] == 0x0C) {
+		I("Enter safe mode, OK!");
+	} else {
+		E("It doen't enter safe mode, please check it again");
+		return;
+	}
+	g_core_fp.fp_register_read(ts, FW_GET_ARRAY(addr_clr_fw_record_dd_sts),
+		tmp_data.byte, DATA_LEN_4);
+	I("Before Write :Now 10007FCC=0x%08X",
+	  le32_to_cpu(tmp_data.dword));
+	usleep_range(10000, 10001);
+
+	tmp_data.byte[2] = 0x00;
+	tmp_data.byte[3] = 0x00;
+	g_core_fp.fp_register_write(ts, FW_GET_ARRAY(addr_clr_fw_record_dd_sts),
+		tmp_data.byte, DATA_LEN_4);
+	usleep_range(10000, 10001);
+
+	g_core_fp.fp_register_read(ts, FW_GET_ARRAY(addr_clr_fw_record_dd_sts),
+		tmp_data.byte, DATA_LEN_4);
+	I("After Write :Now 10007FCC=0x%08X",
+	  le32_to_cpu(tmp_data.dword));
+}
+
+static void hx_ap_notify_fw_sus(struct himax_ts_data *ts, int suspend)
+{
+	int retry = 0;
+	int read_sts = 0;
+	union hx_dword_data_t read_tmp = {0};
+	union hx_dword_data_t addr_tmp = {0};
+	union hx_dword_data_t data_tmp = {0};
+
+	addr_tmp.dword = FW_GET_VAL(addr_ap_notify_fw_sus);
+
+	if (suspend) {
+		I("Suspend mode!");
+		data_tmp.dword = FW_GET_VAL(data_ap_notify_fw_sus_en);
+	} else {
+		I("Non-Suspend mode!");
+		data_tmp.dword = FW_GET_VAL(data_ap_notify_fw_sus_dis);
+	}
+
+	I("R%08XH<-0x%08X",	addr_tmp.dword,	data_tmp.dword);
+	addr_tmp.dword = cpu_to_le32(addr_tmp.dword);
+	data_tmp.dword = cpu_to_le32(data_tmp.dword);
+	do {
+		g_core_fp.fp_register_write(ts, addr_tmp.byte, data_tmp.byte,
+			sizeof(data_tmp.byte));
+		usleep_range(1000, 1001);
+		read_sts = g_core_fp.fp_register_read(ts, addr_tmp.byte, read_tmp.byte,
+			sizeof(read_tmp.byte));
+		I("read bus status=%d", read_sts);
+		I("Now retry=%d, data=0x%08X", retry,
+		  le32_to_cpu(read_tmp.dword));
+	} while ((retry++ < 10) && (read_sts != NO_ERR) &&
+		(read_tmp.dword != data_tmp.dword));
+}
+
+/* FW side end*/
+/* CORE_FW */
+
+/* CORE_FLASH */
+/* FLASH side start*/
+static void himax_mcu_chip_erase(struct himax_ts_data *ts)
+{
+	g_core_fp.fp_interface_on(ts);
+
+	/* Reset power saving level */
+	if (g_core_fp.fp_init_psl)
+		g_core_fp.fp_init_psl(ts);
+
+	g_core_fp.fp_register_write(ts, FLASH_GET_ARRAY(addr_spi200_trans_fmt),
+		FLASH_GET_ARRAY(data_spi200_trans_fmt), DATA_LEN_4);
+
+	g_core_fp.fp_register_write(ts, FLASH_GET_ARRAY(addr_spi200_trans_ctrl),
+		FLASH_GET_ARRAY(data_spi200_trans_ctrl_2), DATA_LEN_4);
+	g_core_fp.fp_register_write(ts, FLASH_GET_ARRAY(addr_spi200_cmd),
+		FLASH_GET_ARRAY(data_spi200_cmd_2), DATA_LEN_4);
+
+	g_core_fp.fp_register_write(ts, FLASH_GET_ARRAY(addr_spi200_cmd),
+		FLASH_GET_ARRAY(data_spi200_cmd_3), DATA_LEN_4);
+	usleep_range(2000000, 2000001);
+
+	if (!g_core_fp.fp_wait_wip(ts, 100))
+		E("Chip_Erase Fail");
+	else
+		I("Chip_Erase Success");
+}
+
+static bool himax_mcu_block_erase(struct himax_ts_data *ts, int start_addr,
+				  int length)
+{
+	u32 page_prog_start = 0;
+	u32 block_size = 0x10000;
+
+	DEF_WORD_DATA(tmp_data);
+
+	g_core_fp.fp_interface_on(ts);
+
+	g_core_fp.fp_init_psl(ts);
+
+	g_core_fp.fp_register_write(ts, FLASH_GET_ARRAY(addr_spi200_trans_fmt),
+		FLASH_GET_ARRAY(data_spi200_trans_fmt), DATA_LEN_4);
+
+	for (page_prog_start = start_addr;
+		page_prog_start < start_addr + length;
+		page_prog_start = page_prog_start + block_size) {
+		g_core_fp.fp_register_write(ts,
+			FLASH_GET_ARRAY(addr_spi200_trans_ctrl),
+			FLASH_GET_ARRAY(data_spi200_trans_ctrl_2), DATA_LEN_4);
+		g_core_fp.fp_register_write(ts,
+			FLASH_GET_ARRAY(addr_spi200_cmd),
+			FLASH_GET_ARRAY(data_spi200_cmd_2), DATA_LEN_4);
+
+		VAL_SET(tmp_data, page_prog_start);
+		g_core_fp.fp_register_write(ts, FLASH_GET_ARRAY(addr_spi200_addr),
+			tmp_data.data.byte, DATA_LEN_4);
+
+		g_core_fp.fp_register_write(ts,
+			FLASH_GET_ARRAY(addr_spi200_trans_ctrl),
+			FLASH_GET_ARRAY(data_spi200_trans_ctrl_3), DATA_LEN_4);
+		g_core_fp.fp_register_write(ts,
+			FLASH_GET_ARRAY(addr_spi200_cmd),
+			FLASH_GET_ARRAY(data_spi200_cmd_4), DATA_LEN_4);
+		usleep_range(1000000, 1000001);
+
+		if (!g_core_fp.fp_wait_wip(ts, 100)) {
+			E("Erase Fail");
+			return false;
+		}
+	}
+
+	I("END");
+	return true;
+}
+
+static bool himax_mcu_sector_erase(int start_addr)
+{
+	return true;
+}
+
+static bool himax_mcu_flash_programming(struct himax_ts_data *ts,
+					u8 *FW_content, int fw_size)
+{
+	int page_prog_start = 0;
+	union hx_dword_data_t tmp_data = {0};
+	int ret = 0;
+	/* 4 bytes for padding*/
+	g_core_fp.fp_interface_on(ts);
+
+	g_core_fp.fp_register_write(ts,
+		FLASH_GET_ARRAY(addr_spi200_trans_fmt),
+		FLASH_GET_ARRAY(data_spi200_trans_fmt), DATA_LEN_4);
+
+	for (page_prog_start = 0; page_prog_start < fw_size;
+		page_prog_start += FLASH_RW_MAX_LEN) {
+		/* ===Flash Write Enable ===*/
+
+		g_core_fp.fp_register_write(ts,
+				FLASH_GET_ARRAY(addr_spi200_trans_ctrl),
+				FLASH_GET_ARRAY(data_spi200_trans_ctrl_2), DATA_LEN_4);
+
+		g_core_fp.fp_register_write(ts, FLASH_GET_ARRAY(addr_spi200_cmd),
+				FLASH_GET_ARRAY(data_spi200_cmd_2),	DATA_LEN_4);
+
+		/* ===WEL Write Control ===*/
+		g_core_fp.fp_register_write(ts,
+				FLASH_GET_ARRAY(addr_spi200_trans_ctrl),
+				FLASH_GET_ARRAY(data_spi200_trans_ctrl_6), DATA_LEN_4);
+
+		g_core_fp.fp_register_write(ts,
+				FLASH_GET_ARRAY(addr_spi200_cmd),
+				FLASH_GET_ARRAY(data_spi200_cmd_1),	DATA_LEN_4);
+
+		g_core_fp.fp_register_read(ts, FLASH_GET_ARRAY(addr_spi200_data),
+				tmp_data.byte, DATA_LEN_4);
+
+		/* === Check WEL Fail ===*/
+		if (((tmp_data.byte[0] & 0x02) >> 1) == 0) {
+			I("SPI 0x8000002c = %d, Check WEL Fail",
+			  tmp_data.byte[0]);
+			return false;
+		}
+
+		g_core_fp.fp_register_write(ts,
+			FLASH_GET_ARRAY(addr_spi200_trans_ctrl),
+			FLASH_GET_ARRAY(data_spi200_trans_ctrl_2), DATA_LEN_4);
+		g_core_fp.fp_register_write(ts,
+			FLASH_GET_ARRAY(addr_spi200_cmd),
+			FLASH_GET_ARRAY(data_spi200_cmd_2), DATA_LEN_4);
+
+		 /*Programmable size = 1 page = 256 bytes,*/
+		 /*word_number = 256 byte / 4 = 64*/
+		g_core_fp.fp_register_write(ts,
+			FLASH_GET_ARRAY(addr_spi200_trans_ctrl),
+			FLASH_GET_ARRAY(data_spi200_trans_ctrl_4), DATA_LEN_4);
+
+		/* Flash start address 1st : 0x0000_0000*/
+		tmp_data.dword = cpu_to_le32(page_prog_start);
+		g_core_fp.fp_register_write(ts,
+			FLASH_GET_ARRAY(addr_spi200_addr), tmp_data.byte, DATA_LEN_4);
+
+		ret = g_core_fp.fp_register_write(ts,
+			FLASH_GET_ARRAY(addr_spi200_data),
+			&FW_content[page_prog_start], 16);
+		if (ret < 0) {
+			E("bus access fail!");
+			return false;
+		}
+
+		g_core_fp.fp_register_write(ts, FLASH_GET_ARRAY(addr_spi200_cmd),
+			FLASH_GET_ARRAY(data_spi200_cmd_6), DATA_LEN_4);
+
+		ret = g_core_fp.fp_register_write(ts,
+			FLASH_GET_ARRAY(addr_spi200_data),
+			&FW_content[page_prog_start + 16], 240);
+		if (ret < 0) {
+			E("bus access fail!");
+			return false;
+		}
+
+		if (!g_core_fp.fp_wait_wip(ts, 1)) {
+			E("Flash_Programming Fail");
+			return false;
+		}
+	}
+	return true;
+}
+
+static void himax_mcu_flash_page_write(u8 *write_addr, int length,
+				       u8 *write_data)
+{
+}
+
+static void himax_flash_speed_set(struct himax_ts_data *ts, u8 speed)
+{
+	struct hx_reg_t reg_addr;
+	struct hx_reg_t reg_data;
+
+	reg_data.data.word = 0;
+	reg_data.data.byte[1] = 0x02; /*extand cs high to 100ns*/
+	reg_data.data.byte[0] = speed;
+	WORD_REG(reg_addr, flash_clk_setup_addr);
+	g_core_fp.fp_register_write(ts, REG_GET_ARRAY(reg_addr),
+		REG_GET_ARRAY(reg_data), 4);
+}
+
+static int himax_mcu_fts_ctpm_fw_upgrade_with_sys_fs_32k
+		(struct himax_ts_data *ts, unsigned char *fw,
+		 int len, bool change_iref)
+{
+	/* Not use */
+	return 0;
+}
+
+static int himax_mcu_fts_ctpm_fw_upgrade_with_sys_fs_60k
+		(struct himax_ts_data *ts, unsigned char *fw,
+		 int len, bool change_iref)
+{
+	/* Not use */
+	return 0;
+}
+
+static int himax_mcu_fts_ctpm_fw_upgrade_with_sys_fs_64k
+		(struct himax_ts_data *ts, unsigned char *fw,
+		 int len, bool change_iref)
+{
+	int burn_firmware_success = 0;
+	int counter = 0;
+
+	if (len != FW_SIZE_64k) {
+		E("The file size is not 64K bytes");
+		return false;
+	}
+
+	g_core_fp.fp_ic_reset(ts, false, false);
+	for (counter = 0; counter < 3; counter++) {
+		g_core_fp.fp_sense_off(ts, true);
+		himax_flash_speed_set(ts, HX_FLASH_SPEED_12p5M);
+		g_core_fp.fp_block_erase(ts, 0x00, FW_SIZE_64k);
+		if (g_core_fp.fp_flash_programming(ts, fw, FW_SIZE_64k) == false) {
+			g_core_fp.fp_ic_reset(ts, false, false);
+			continue;
+		}
+
+		if (g_core_fp.fp_check_crc(ts, FW_GET_ARRAY(addr_program_reload_from),
+					   FW_SIZE_64k) == 0) {
+			burn_firmware_success = 1;
+			break;
+		}
+	}
+	/*RawOut select initial*/
+	g_core_fp.fp_register_write(ts, FW_GET_ARRAY(addr_raw_out_sel),
+		FW_GET_ARRAY(data_clear), FW_GET_SZ(data_clear));
+	/*DSRAM func initial*/
+	g_core_fp.fp_assign_sorting_mode(ts, FW_GET_ARRAY(data_clear));
+	g_core_fp.fp_ic_reset(ts, false, false);
+
+	return burn_firmware_success;
+}
+
+static int himax_mcu_fts_ctpm_fw_upgrade_with_sys_fs_124k
+		(struct himax_ts_data *ts, unsigned char *fw,
+		 int len, bool change_iref)
+{
+	/* Not use */
+	return 0;
+}
+
+static int himax_mcu_fts_ctpm_fw_upgrade_with_sys_fs_128k
+		(struct himax_ts_data *ts, unsigned char *fw,
+		 int len, bool change_iref)
+{
+	int burn_firmware_success = 0;
+	int counter = 0;
+
+	if (len != FW_SIZE_128k) {
+		E("The file size is not 128K bytes");
+		return false;
+	}
+
+	g_core_fp.fp_ic_reset(ts, false, false);
+	for (counter = 0; counter < 3; counter++) {
+		g_core_fp.fp_sense_off(ts, true);
+		himax_flash_speed_set(ts, HX_FLASH_SPEED_12p5M);
+		g_core_fp.fp_block_erase(ts, 0x00, FW_SIZE_128k);
+		if (g_core_fp.fp_flash_programming(ts, fw, FW_SIZE_128k) == false) {
+			g_core_fp.fp_ic_reset(ts, false, false);
+			continue;
+		}
+
+		if (g_core_fp.fp_check_crc(ts, FW_GET_ARRAY(addr_program_reload_from),
+					   FW_SIZE_128k) == 0) {
+			burn_firmware_success = 1;
+			break;
+		}
+	}
+	/*RawOut select initial*/
+	g_core_fp.fp_register_write(ts, FW_GET_ARRAY(addr_raw_out_sel),
+		FW_GET_ARRAY(data_clear), FW_GET_SZ(data_clear));
+	/*DSRAM func initial*/
+	g_core_fp.fp_assign_sorting_mode(ts, FW_GET_ARRAY(data_clear));
+
+	return burn_firmware_success;
+}
+
+static int himax_mcu_fts_ctpm_fw_upgrade_with_sys_fs_255k
+		(struct himax_ts_data *ts, unsigned char *fw,
+		 int len, bool change_iref)
+{
+	int burn_firmware_success = 0;
+	int counter = 0;
+
+	if (len != FW_SIZE_255k) {
+		E("The file size is not 255K bytes");
+		return false;
+	}
+
+	g_core_fp.fp_ic_reset(ts, false, false);
+	for (counter = 0; counter < 3; counter++) {
+		g_core_fp.fp_sense_off(ts, true);
+		himax_flash_speed_set(ts, HX_FLASH_SPEED_12p5M);
+		g_core_fp.fp_block_erase(ts, 0x00, FW_SIZE_255k);
+		if (g_core_fp.fp_flash_programming(ts, fw, FW_SIZE_255k) == false) {
+			g_core_fp.fp_ic_reset(ts, false, false);
+			continue;
+		}
+		if (g_core_fp.fp_check_crc(ts, FW_GET_ARRAY(addr_program_reload_from),
+					   FW_SIZE_255k) == 0) {
+			burn_firmware_success = 1;
+			break;
+		}
+	}
+	/*RawOut select initial*/
+	g_core_fp.fp_register_write(ts, FW_GET_ARRAY(addr_raw_out_sel),
+		FW_GET_ARRAY(data_clear), FW_GET_SZ(data_clear));
+	/*DSRAM func initial*/
+	g_core_fp.fp_assign_sorting_mode(ts, FW_GET_ARRAY(data_clear));
+
+	return burn_firmware_success;
+}
+
+static void himax_mcu_flash_dump_func
+		(struct himax_ts_data *ts, u8 local_flash_command,
+		 int flash_size, u8 *flash_buffer)
+{
+	struct hx_reg_t tmp_addr;
+	int page_prog_start = 0;
+
+	g_core_fp.fp_sense_off(ts, true);
+
+	for (page_prog_start = 0; page_prog_start < flash_size;
+		page_prog_start += 128) {
+		WORD_REG(tmp_addr, page_prog_start);
+		g_core_fp.fp_register_read(ts, REG_GET_ARRAY(tmp_addr),
+			flash_buffer + page_prog_start, 128);
+	}
+
+	g_core_fp.fp_sense_on(ts, 0x01);
+}
+
+static bool himax_mcu_flash_lastdata_check(struct himax_ts_data *ts,
+					   u32 size)
+{
+	struct hx_reg_t tmp_addr;
+	/* 64K - 0x80, which is the address of
+	 * the last 128bytes in 64K, default value
+	 */
+	u32 start_addr = 0xFFFFFFFF;
+	u32 temp_addr = 0;
+	u32 flash_page_len = 0x80;
+	u8 flash_tmp_buffer[128];
+
+	if (size < flash_page_len) {
+		E("flash size is wrong, terminated");
+		E("flash size = %08X; flash page len = %08X",
+		  size, flash_page_len);
+		goto FAIL;
+	}
+
+	/* In order to match other size of fw */
+	start_addr = size - flash_page_len;
+	I("Now size is %d, the start_addr is 0x%08X",
+	  size, start_addr);
+	for (temp_addr = start_addr; temp_addr < (start_addr + flash_page_len);
+		temp_addr = temp_addr + flash_page_len) {
+		/*I("temp_addr=%d,tmp_addr[0]=0x%2X, tmp_addr[1]=0x%2X,
+		 *	tmp_addr[2]=0x%2X,tmp_addr[3]=0x%2X",
+		 *	temp_addr,tmp_addr[0], tmp_addr[1],
+		 *	tmp_addr[2],tmp_addr[3]);
+		 */
+		WORD_REG(tmp_addr, temp_addr);
+		g_core_fp.fp_register_read(ts, REG_GET_ARRAY(tmp_addr),
+			&flash_tmp_buffer[0], flash_page_len);
+	}
+
+	I("FLASH[%08X] ~ FLASH[%08X] = %02X%02X%02X%02X", size - 4, size - 1,
+	  flash_tmp_buffer[flash_page_len - 4],
+	  flash_tmp_buffer[flash_page_len - 3],
+	  flash_tmp_buffer[flash_page_len - 2],
+	  flash_tmp_buffer[flash_page_len - 1]);
+
+	if (!flash_tmp_buffer[flash_page_len - 4] &&
+	    !flash_tmp_buffer[flash_page_len - 3] &&
+		!flash_tmp_buffer[flash_page_len - 2] &&
+		!flash_tmp_buffer[flash_page_len - 1]) {
+		I("Fail, Last four Bytes are all 0x00:");
+		goto FAIL;
+	} else if (flash_tmp_buffer[flash_page_len - 4] == 0xFF &&
+			  (flash_tmp_buffer[flash_page_len - 3] == 0xFF) &&
+			  (flash_tmp_buffer[flash_page_len - 2] == 0xFF) &&
+			  (flash_tmp_buffer[flash_page_len - 1] == 0xFF)) {
+		I("Fail, Last four Bytes are all 0xFF:");
+		goto FAIL;
+	} else {
+		return 0;
+	}
+
+FAIL:
+	return 1;
+}
+
+static bool hx_bin_desc_data_get(struct himax_ts_data *ts,
+				 u32 addr, u8 *flash_buf,
+				 const u8 *fw_all_data)
+{
+	u8 data_sz = 0x10;
+	u32 i = 0, j = 0;
+	u16 chk_end = 0;
+	u16 chk_sum = 0;
+	u32 map_code = 0;
+	unsigned long flash_addr = 0;
+	u32 hid_table_addr = 0;
+	union {
+		u8 *buf;
+		u32 *word;
+	} map_data;
+
+	for (i = 0; i < FW_PAGE_SZ; i = i + data_sz) {
+		for (j = i; j < (i + data_sz); j++) {
+			chk_end |= flash_buf[j];
+			chk_sum += flash_buf[j];
+		}
+		if (!chk_end) { /*1. Check all zero*/
+			I("End in %X", i + addr);
+			return false;
+		} else if (chk_sum % 0x100) { /*2. Check sum*/
+			I("chk sum failed in %X", i + addr);
+		} else { /*3. get data*/
+			map_data.buf = &flash_buf[i];
+			map_code = le32_to_cpup(map_data.word);
+			map_data.buf = &flash_buf[i + 4];
+			flash_addr = le32_to_cpup(map_data.word);
+			switch (map_code) {
+			case FW_CID:
+				WORD_REG(g_core_regs.flash_ver_info.addr_cid_ver_major,
+					 flash_addr);
+				WORD_REG(g_core_regs.flash_ver_info.addr_cid_ver_minor,
+					 flash_addr + 1);
+				I("CID_VER in %X", FLASH_VER_GET_VAL(addr_cid_ver_major));
+				memcpy(&ts->fw_bin_desc, &fw_all_data
+					   [flash_addr - sizeof(ts->hid_info.fw_bin_desc.passwd)],
+				       sizeof(struct hx_bin_desc_t));
+				break;
+			case FW_VER:
+				WORD_REG(g_core_regs.flash_ver_info.addr_fw_ver_major,
+					 flash_addr);
+				WORD_REG(g_core_regs.flash_ver_info.addr_fw_ver_minor,
+					 flash_addr + 1);
+				I("FW_VER in %X", FLASH_VER_GET_VAL(addr_fw_ver_major));
+				break;
+			case CFG_VER:
+				WORD_REG(g_core_regs.flash_ver_info.addr_cfg_ver_major,
+					 flash_addr);
+				WORD_REG(g_core_regs.flash_ver_info.addr_cfg_ver_minor,
+					 flash_addr + 1);
+				I("CFG_VER in = %08X",	FLASH_VER_GET_VAL(addr_cfg_ver_major));
+				break;
+			case TP_CONFIG_TABLE:
+				WORD_REG(g_core_regs.flash_ver_info.addr_cfg_table,
+					 flash_addr);
+				I("CONFIG_TABLE in %X", FLASH_VER_GET_VAL(addr_cfg_table));
+				break;
+			case HID_TABLE:
+				WORD_REG(g_core_regs.flash_ver_info.addr_hid_table,
+					 flash_addr);
+				I("HID_TABLE in %X", FLASH_VER_GET_VAL(addr_hid_table));
+				hid_table_addr = FLASH_VER_GET_VAL(addr_hid_table);
+				WORD_REG(g_core_regs.flash_ver_info.addr_hid_desc,
+					 hid_table_addr);
+				I("HID_DESC in %X", FLASH_VER_GET_VAL(addr_hid_desc));
+				WORD_REG(g_core_regs.flash_ver_info.addr_hid_rd_desc,
+					 (hid_table_addr + 24));
+				I("HID_RD_DESC in %X", FLASH_VER_GET_VAL(addr_hid_rd_desc));
+				break;
+			}
+		}
+		chk_end = 0;
+		chk_sum = 0;
+	}
+
+	return true;
+}
+
+static bool hx_mcu_bin_desc_get(unsigned char *fw, struct himax_ts_data *ts,
+				u32 max_sz)
+{
+	u32 addr_t = 0;
+	unsigned char *fw_buf = NULL;
+	bool keep_on_flag = false;
+	bool bin_desc_flag = false;
+
+	do {
+		fw_buf = &fw[addr_t];
+
+		/*Check bin is with description table or not*/
+		if (!bin_desc_flag) {
+			if (fw_buf[0x00] == 0x00 && fw_buf[0x01] == 0x00 &&
+			    fw_buf[0x02] == 0x00 && fw_buf[0x03] == 0x00 &&
+			    fw_buf[0x04] == 0x00 && fw_buf[0x05] == 0x00 &&
+			    fw_buf[0x06] == 0x00 && fw_buf[0x07] == 0x00 &&
+			    fw_buf[0x0E] == 0x87)
+				bin_desc_flag = true;
+		}
+		if (!bin_desc_flag) {
+			I("fw_buf[0x00] = %2X, fw_buf[0x0E] = %2X",
+			  fw_buf[0x00], fw_buf[0x0E]);
+			I("No description table");
+			break;
+		}
+
+		/*Get related data*/
+		keep_on_flag = hx_bin_desc_data_get(ts, addr_t, fw_buf, fw);
+		if (FLASH_VER_GET_VAL(addr_hid_table) >= ts->hxfw->size ||
+		    (FLASH_VER_GET_VAL(addr_hid_rd_desc) +
+			ts->hid_rd_data.rd_length) >= ts->hxfw->size) {
+			W("hid_table_addr = %d, ts->hxfw->size = %lu!",
+			  FLASH_VER_GET_VAL(addr_hid_table), ts->hxfw->size);
+			W("hid_rd_desc_addr = %d, rd_len = %d, ts->hxfw->size = %lu!",
+			  FLASH_VER_GET_VAL(addr_hid_rd_desc),
+			  ts->hid_rd_data.rd_length,
+			  ts->hxfw->size);
+			WORD_REG(g_core_regs.flash_ver_info.addr_hid_table, 0);
+			WORD_REG(g_core_regs.flash_ver_info.addr_hid_desc, 0);
+			WORD_REG(g_core_regs.flash_ver_info.addr_hid_rd_desc, 0);
+		}
+
+		addr_t = addr_t + FW_PAGE_SZ;
+	} while (max_sz > addr_t && keep_on_flag);
+
+	return bin_desc_flag;
+}
+
+static int hx_mcu_diff_overlay_flash(struct himax_ts_data *ts)
+{
+	int rslt = 0;
+	int diff_val = 0;
+
+	diff_val = (ts->ic_data->vendor_fw_ver);
+	I("Now fw ID is 0x%04X", diff_val);
+	diff_val = (diff_val >> 12);
+	I("Now diff value=0x%04X", diff_val);
+
+	if (diff_val == 1)
+		I("Now size should be 128K!");
+	else
+		I("Now size should be 64K!");
+	rslt = diff_val;
+	return rslt;
+}
+
+/* FLASH side end*/
+/* CORE_FLASH */
+
+/* CORE_SRAM */
+/* SRAM side start*/
+static void himax_mcu_sram_write(struct himax_ts_data *ts, u8 *fw_content)
+{
+}
+
+static bool himax_mcu_sram_verify(struct himax_ts_data *ts, u8 *fw_file,
+				  int fw_size)
+{
+	return true;
+}
+
+static bool himax_mcu_get_DSRAM_data(struct himax_ts_data *ts,
+				     u8 *info_data, bool dsram_flag)
+{
+	unsigned int i = 0;
+	struct hx_reg_t tmp_addr;
+	union hx_dword_data_t tmp_data = {0};
+	unsigned int max_bus_size = MAX_I2C_TRANS_SZ;
+	const u32 x_num = ts->ic_data->HX_RX_NUM;
+	const u32 y_num = ts->ic_data->HX_TX_NUM;
+	unsigned int total_size = (x_num * y_num + x_num + y_num) * 2 + 4;
+	unsigned int remain_size;
+	u32 retry = 0;
+	unsigned int addr = 0;
+	u8  *temp_info_data = NULL; /*max mkey size = 8*/
+	u32 checksum = 0;
+	s32 fw_run_flag = -1;
+
+#if defined(BUS_R_DLEN)
+	max_bus_size = BUS_R_DLEN;
+#endif
+
+	if (strcmp(ts->chip_name, HX83121A_ID) == 0) {
+		if (max_bus_size > 4096)
+			max_bus_size = 4096;
+	}
+
+	temp_info_data = kcalloc((total_size + 8), sizeof(u8), GFP_KERNEL);
+	if (!temp_info_data) {
+		E("Failed to allocate memory");
+		return false;
+	}
+	/* 1. Read number of MKey R100070E8H to determin data size */
+	/* m_key_num = g_hx_ic_data->HX_BT_NUM; */
+	/* I("m_key_num=%d", m_key_num); */
+	/* total_size += m_key_num * 2; */
+
+	/* 2. Start DSRAM Rawdata and Wait Data Ready */
+	tmp_data.dword = SRAM_GET_VAL(passwrd_start);
+	tmp_data.dword = cpu_to_le32(tmp_data.dword);
+	fw_run_flag = himax_write_read_reg(ts, SRAM_GET_ARRAY(addr_rawdata_addr),
+					   tmp_data.byte,
+					   SRAM_GET_ARRAY(passwrd_end)[1],
+					   SRAM_GET_ARRAY(passwrd_end)[0]);
+
+	if (fw_run_flag < 0) {
+		E("Data NOT ready => bypass");
+		kfree(temp_info_data);
+		return false;
+	}
+
+	/* 3. Read RawData */
+	while (retry++ < 5) {
+		remain_size = total_size;
+		while (remain_size > 0) {
+			i = total_size - remain_size;
+			addr = sram_adr_rawdata_addr + i;
+
+			WORD_REG(tmp_addr, addr);
+
+			if (remain_size >= max_bus_size) {
+				g_core_fp.fp_register_read(ts, REG_GET_ARRAY(tmp_addr),
+					&temp_info_data[i], max_bus_size);
+				remain_size -= max_bus_size;
+			} else {
+				g_core_fp.fp_register_read(ts, REG_GET_ARRAY(tmp_addr),
+					&temp_info_data[i], remain_size);
+				remain_size = 0;
+			}
+		}
+
+		/* 5. Data Checksum Check */
+		/* 2 is meaning PASSWORD NOT included */
+		checksum = 0;
+		for (i = 2; i < total_size; i += 2)
+			checksum += temp_info_data[i + 1] << 8 | temp_info_data[i];
+
+		if (checksum % 0x10000 != 0) {
+			E("check_sum_cal fail=%08X", checksum);
+
+		} else {
+			memcpy(info_data, temp_info_data,
+			       total_size * sizeof(u8));
+			break;
+		}
+	}
+
+	/* 4. FW stop outputing */
+	tmp_data.dword = 0;
+	tmp_data.byte[3] = temp_info_data[3];
+	tmp_data.byte[2] = temp_info_data[2];
+	g_core_fp.fp_register_write(ts, SRAM_GET_ARRAY(addr_rawdata_addr),
+		tmp_data.byte, DATA_LEN_4);
+
+	kfree(temp_info_data);
+	if (retry >= 5)
+		return false;
+	else
+		return true;
+}
+
+/* SRAM side end*/
+/* CORE_SRAM */
+
+/* CORE_DRIVER */
+static void himax_mcu_init_ic(struct himax_ts_data *ts)
+{
+	I("use default incell init.");
+}
+
+static void himax_suspend_proc(struct himax_ts_data *ts, bool suspended)
+{
+	I("himax suspend.");
+}
+
+static void himax_resume_proc(struct himax_ts_data *ts, bool suspended)
+{
+	int result = 0;
+
+	I("himax resume.");
+	if (!ts->ic_data->has_flash) {
+		if (g_core_fp.fp_0f_op_file_dirly) {
+			result = g_core_fp.fp_0f_op_file_dirly(g_fw_boot_upgrade_name,
+				ts);
+			if (result)
+				E("update FW fail, code[%d]!!", result);
+			else
+				ts->resume_success = true;
+		}
+	} else {
+		if (g_core_fp.fp_resend_cmd_func) {
+			g_core_fp.fp_resend_cmd_func(ts, suspended);
+			ts->resume_success = true;
+		}
+	}
+
+	if (g_core_fp.fp_ap_notify_fw_sus && result == 0)
+		g_core_fp.fp_ap_notify_fw_sus(ts, 0);
+}
+
+static void himax_mcu_pin_reset(struct himax_ts_data *ts)
+{
+	const int rst_low_period_s = RST_LOW_PERIOD_S;
+	const int rst_low_period_e = RST_LOW_PERIOD_E;
+	int rst_high_period_s;
+	int rst_high_period_e;
+
+	I("Now reset the Touch chip.");
+	if (!ts->ic_data->has_flash) {
+		rst_high_period_s = RST_HIGH_PERIOD_ZF_S;
+		rst_high_period_e = RST_HIGH_PERIOD_ZF_E;
+	} else {
+		rst_high_period_s = RST_HIGH_PERIOD_S;
+		rst_high_period_e = RST_HIGH_PERIOD_E;
+	}
+	himax_rst_gpio_set(ts->rst_gpio, 0);
+	usleep_range(rst_low_period_s, rst_low_period_e);
+	himax_rst_gpio_set(ts->rst_gpio, 1);
+	usleep_range(rst_high_period_s, rst_high_period_e);
+}
+
+static void himax_mcu_ic_reset(struct himax_ts_data *ts, u8 loadconfig,
+			       u8 int_off)
+{
+	I("status: loadconfig=%d,int_off=%d", loadconfig, int_off);
+
+	if (ts->rst_gpio >= 0) {
+		if (int_off)
+			g_core_fp.fp_irq_switch(ts, 0);
+
+		g_core_fp.fp_pin_reset(ts);
+
+		if (int_off)
+			g_core_fp.fp_irq_switch(ts, 1);
+	}
+}
+
+static u8 himax_mcu_tp_info_check(struct himax_ts_data *ts)
+{
+	union hx_dword_data_t addr;
+	char data[DATA_LEN_4] = {0};
+	u32 rx_num;
+	u32 tx_num;
+	u32 bt_num;
+	u32 max_pt;
+	u32 y_res;
+	u32 x_res;
+	u8 int_is_edge;
+	u8 stylus_func;
+	u8 stylus_id_v2;
+	u8 stylus_ratio;
+
+	g_core_fp.fp_register_read(ts,
+		DRV_GET_ARRAY(addr_fw_define_rxnum_txnum), data, DATA_LEN_4);
+	rx_num = data[2];
+	tx_num = data[3];
+
+	g_core_fp.fp_register_read(ts,
+		DRV_GET_ARRAY(addr_fw_define_maxpt_xyrvs), data, DATA_LEN_4);
+	max_pt = data[0];
+
+	g_core_fp.fp_register_read(ts,
+		DRV_GET_ARRAY(addr_fw_define_x_y_res), data, DATA_LEN_4);
+	y_res = be16_to_cpup((u16 *)&data[0]);
+	x_res = be16_to_cpup((u16 *)&data[2]);
+	/* I("rx_num=%d, tx_num=%d, max_pt=%d, y_res=%d, x_res=%d",
+	 *	rx_num, tx_num, max_pt, y_res, x_res);
+	 */
+
+	g_core_fp.fp_register_read(ts,
+		DRV_GET_ARRAY(addr_fw_define_int_is_edge), data, DATA_LEN_4);
+	if ((data[1] & 0x01) == 1)
+		int_is_edge = true;
+	else
+		int_is_edge = false;
+
+	/*1. Read number of MKey R100070E8H to determin data size*/
+	g_core_fp.fp_register_read(ts, SRAM_GET_ARRAY(addr_mkey), data,
+		DATA_LEN_4);
+	bt_num = data[0] & 0x03;
+	ts->ic_data->HX_BT_NUM = bt_num;
+
+	addr.dword = 0x1000719C;
+	addr.dword = cpu_to_le32(addr.dword);
+
+	g_core_fp.fp_register_read(ts, addr.byte, data, DATA_LEN_4);
+	stylus_func = data[3];
+	ts->ic_data->HX_STYLUS_FUNC = stylus_func;
+
+	ts->ic_data->HX_RX_NUM = rx_num;
+
+	ts->ic_data->HX_TX_NUM = tx_num;
+
+	ts->ic_data->HX_X_RES = x_res;
+	ts->ic_data->HX_Y_RES = y_res;
+	ts->ic_data->HX_MAX_PT = max_pt;
+	ts->ic_data->HX_INT_IS_EDGE = int_is_edge;
+
+	if (ts->ic_data->HX_STYLUS_FUNC) {
+		addr.dword = 0x100071FC;
+		addr.dword = cpu_to_le32(addr.dword);
+		g_core_fp.fp_register_read(ts, addr.byte, data, DATA_LEN_4);
+		stylus_id_v2 = data[2];/* 0x100071FE 0=off 1=on */
+		stylus_ratio = data[3];
+		/* 0x100071FF 0=ratio_1 10=ratio_10 */
+		ts->ic_data->HX_STYLUS_ID_V2 = stylus_id_v2;
+		ts->ic_data->HX_STYLUS_RATIO = stylus_ratio;
+	}
+
+	I("TOUCH_INFO updated");
+
+	return 0;
+}
+
+static void himax_mcu_touch_information(struct himax_ts_data *ts)
+{
+	if (ts->ic_data->HX_RX_NUM == 0xFFFFFFFF)
+		ts->ic_data->HX_RX_NUM = FIX_HX_RX_NUM;
+
+	if (ts->ic_data->HX_TX_NUM == 0xFFFFFFFF)
+		ts->ic_data->HX_TX_NUM = FIX_HX_TX_NUM;
+
+	if (ts->ic_data->HX_BT_NUM == 0xFFFFFFFF)
+		ts->ic_data->HX_BT_NUM = FIX_HX_BT_NUM;
+
+	if (ts->ic_data->HX_MAX_PT == 0xFFFFFFFF)
+		ts->ic_data->HX_MAX_PT = FIX_HX_MAX_PT;
+
+	if (ts->ic_data->HX_INT_IS_EDGE == 0xFF)
+		ts->ic_data->HX_INT_IS_EDGE = FIX_HX_INT_IS_EDGE;
+
+	if (ts->ic_data->HX_STYLUS_FUNC == 0xFF)
+		ts->ic_data->HX_STYLUS_FUNC = FIX_HX_STYLUS_FUNC;
+
+	if (ts->ic_data->HX_STYLUS_ID_V2 == 0xFF)
+		ts->ic_data->HX_STYLUS_ID_V2 = FIX_HX_STYLUS_ID_V2;
+
+	if (ts->ic_data->HX_STYLUS_RATIO == 0xFF)
+		ts->ic_data->HX_STYLUS_RATIO = FIX_HX_STYLUS_RATIO;
+
+	I("HX_RX_NUM = %d,HX_TX_NUM = %d",
+	  ts->ic_data->HX_RX_NUM, ts->ic_data->HX_TX_NUM);
+	I("HX_MAX_PT = %d", ts->ic_data->HX_MAX_PT);
+	I("HX_INT_IS_EDGE = %d,HX_STYLUS_FUNC = %d",
+	  ts->ic_data->HX_INT_IS_EDGE, ts->ic_data->HX_STYLUS_FUNC);
+	I("HX_STYLUS_ID_V2 = %d,HX_STYLUS_RATIO = %d",
+	  ts->ic_data->HX_STYLUS_ID_V2, ts->ic_data->HX_STYLUS_RATIO);
+}
+
+static void himax_mcu_calc_touch_data_size(struct himax_ts_data *ts)
+{
+	ts->x_channel = ts->ic_data->HX_RX_NUM;
+	ts->y_channel = ts->ic_data->HX_TX_NUM;
+	ts->n_finger_support = ts->ic_data->HX_MAX_PT;
+}
+
+static int himax_mcu_get_touch_data_size(void)
+{
+	return HIMAX_TOUCH_DATA_SIZE;
+}
+
+static int himax_mcu_hand_shaking(void)
+{
+	/* 0:Running, 1:Stop, 2:I2C Fail */
+	int result = 0;
+	return result;
+}
+
+static int himax_mcu_determin_diag_rawdata(int diag_command)
+{
+	return diag_command % 10;
+}
+
+static int himax_mcu_determin_diag_storage(int diag_command)
+{
+	return diag_command / 10;
+}
+
+static int himax_mcu_cal_data_len(int raw_cnt_rmd, int HX_MAX_PT,
+				  int raw_cnt_max)
+{
+	int raw_data_len;
+	/* rawdata checksum is 2 bytes */
+	if (raw_cnt_rmd != 0x00)
+		raw_data_len = MAX_I2C_TRANS_SZ
+			- ((HX_MAX_PT + raw_cnt_max + 3) * 4) - 2;
+	else
+		raw_data_len = MAX_I2C_TRANS_SZ
+			- ((HX_MAX_PT + raw_cnt_max + 2) * 4) - 2;
+
+	return raw_data_len;
+}
+
+static bool himax_mcu_diag_check_sum(struct himax_ts_data *ts)
+{
+	u16 check_sum_cal = 0;
+	int i;
+
+	/* Check 128th byte CRC */
+	for (i = 0, check_sum_cal = 0;
+		i < (ts->touch_all_size
+		- ts->touch_info_size);
+		i += 2) {
+		check_sum_cal += (ts->hx_rawdata_buf[i + 1]
+			* FLASH_RW_MAX_LEN
+			+ ts->hx_rawdata_buf[i]);
+	}
+
+	if (check_sum_cal % HX64K != 0) {
+		I("fail = %2X", check_sum_cal);
+		return 0;
+	}
+
+	return 1;
+}
+
+static int himax_mcu_ic_excp_recovery
+		(struct himax_ts_data *ts,
+		 u32 hx_excp_event,
+		 u32 hx_zero_event,
+		 u32 length)
+{
+	int ret_val = NO_ERR;
+
+	if (hx_excp_event == length) {
+		ts->excp_zero_event_count = 0;
+		ret_val = HX_EXCP_EVENT;
+	} else if (hx_zero_event == length) {
+		if (ts->excp_zero_event_count > 5) {
+			ts->excp_zero_event_count = 0;
+			I("EXCEPTION event checked - ALL Zero.");
+			ret_val = HX_EXCP_EVENT;
+		} else {
+			ts->excp_zero_event_count++;
+			I("ALL Zero event is %d times.",
+			  ts->excp_zero_event_count);
+			ret_val = HX_ZERO_EVENT_COUNT;
+		}
+	}
+
+	return ret_val;
+}
+
+static void himax_mcu_excp_ic_reset(struct himax_ts_data *ts)
+{
+	ts->excp_reset_active = 0;
+	himax_mcu_pin_reset(ts);
+	I("reset!");
+}
+
+static void himax_mcu_resend_cmd_func(struct himax_ts_data *ts, bool suspended)
+{
+	himax_cable_detect_func(ts, true);
+}
+
+/* CORE_DRIVER */
+
+static int hx_turn_on_mp_func(struct himax_ts_data *ts, int on)
+{
+	int rslt = 0;
+	int retry = 3;
+	struct hx_reg_t tmp_addr;
+	struct hx_reg_t tmp_data;
+	u8 tmp_read[4] = {0};
+
+	if (strcmp(HX83102D_ID, ts->chip_name) == 0) {
+		WORD_REG(tmp_addr, fw_addr_ctrl_mpap_ovl);
+		if (on) {
+			I("Turn on MPAP mode!");
+			WORD_REG(tmp_data, fw_data_ctrl_mpap_ovl_on);
+			do {
+				g_core_fp.fp_register_write(ts, REG_GET_ARRAY(tmp_addr),
+					REG_GET_ARRAY(tmp_data), REG_GET_SZ(tmp_data));
+				usleep_range(10000, 10001);
+				g_core_fp.fp_register_read(ts, REG_GET_ARRAY(tmp_addr),
+					tmp_read, 4);
+
+				I("read2=0x%02X,read1=0x%02X,read0=0x%02X",
+				  tmp_read[2], tmp_read[1],
+				  tmp_read[0]);
+
+				retry--;
+			} while (((retry > 0) &&
+			(tmp_read[2] != REG_GET_ARRAY(tmp_data)[2] &&
+			tmp_read[1] != REG_GET_ARRAY(tmp_data)[1] &&
+			tmp_read[0] != REG_GET_ARRAY(tmp_data)[0])));
+		} else {
+			I("Turn off MPAP mode!");
+			WORD_REG(tmp_data, fw_data_clear);
+			do {
+				g_core_fp.fp_register_write(ts, REG_GET_ARRAY(tmp_addr),
+					REG_GET_ARRAY(tmp_data), REG_GET_SZ(tmp_data));
+				usleep_range(10000, 10001);
+				g_core_fp.fp_register_read(ts, REG_GET_ARRAY(tmp_addr),
+					tmp_read, sizeof(tmp_read));
+
+				I("read2=0x%02X,read1=0x%02X,read0=0x%02X",
+				  tmp_read[2], tmp_read[1], tmp_read[0]);
+
+				retry--;
+			} while ((retry > 0) &&
+			(tmp_read[2] != REG_GET_ARRAY(tmp_data)[2] &&
+			tmp_read[1] != REG_GET_ARRAY(tmp_data)[1] &&
+			tmp_read[0] != REG_GET_ARRAY(tmp_data)[0]));
+		}
+	} else {
+		I("Nothing to be done!");
+	}
+
+	return rslt;
+}
+
+static void hx_dis_rload_0f(struct himax_ts_data *ts, int disable)
+{
+	/*Disable Flash Reload*/
+	g_core_fp.fp_register_write(ts,
+		DRV_GET_ARRAY(addr_fw_define_flash_reload),
+		ZF_GET_ARRAY(data_dis_flash_reload), DATA_LEN_4);
+}
+
+static void himax_mcu_clean_sram_0f(struct himax_ts_data *ts, u8 *addr,
+				    int write_len, int type)
+{
+	int total_read_times = 0;
+	int max_bus_size = MAX_I2C_TRANS_SZ;
+	int total_size_temp = 0;
+	int address = 0;
+	int i = 0;
+
+	u8 fix_data = 0x00;
+	union hx_dword_data_t tmp_addr;
+	u8 tmp_data[MAX_I2C_TRANS_SZ] = {0};
+
+	I("Entering");
+
+	total_size_temp = write_len;
+
+	tmp_addr.dword = le32_to_cpup((__le32 *)addr);
+	I("addr = 0x%08X", tmp_addr.dword);
+
+	switch (type) {
+	case 0:
+		fix_data = 0x00;
+		break;
+	case 1:
+		fix_data = 0xAA;
+		break;
+	case 2:
+		fix_data = 0xBB;
+		break;
+	}
+
+	for (i = 0; i < MAX_I2C_TRANS_SZ; i++)
+		tmp_data[i] = fix_data;
+
+	I("total size=%d", total_size_temp);
+
+	if (total_size_temp % max_bus_size == 0)
+		total_read_times = total_size_temp / max_bus_size;
+	else
+		total_read_times = total_size_temp / max_bus_size + 1;
+
+	tmp_addr.dword = cpu_to_le32(tmp_addr.dword);
+	for (i = 0; i < (total_read_times); i++) {
+		I("[log]write %d time start!", i);
+		if (total_size_temp >= max_bus_size) {
+			g_core_fp.fp_register_write(ts, tmp_addr.byte, tmp_data,
+				max_bus_size);
+			total_size_temp = total_size_temp - max_bus_size;
+		} else {
+			I("last total_size_temp=%d", total_size_temp);
+			g_core_fp.fp_register_write(ts, tmp_addr.byte, tmp_data,
+				total_size_temp % max_bus_size);
+		}
+		address = ((i + 1) * max_bus_size);
+		tmp_addr.dword = cpu_to_le32(address);
+
+		usleep_range(10000, 11000);
+	}
+
+	I("END");
+}
+
+static void himax_mcu_write_sram_0f(struct himax_ts_data *ts,
+				    u8 *addr, const u8 *data, u32 len)
+{
+	int max_bus_size = MAX_I2C_TRANS_SZ;
+	u32 remain_len = 0;
+	u32 address = 0;
+	u32 i;
+	struct hx_reg_t tmp_addr;
+
+	I("Entering - total write size = %d", len);
+
+#if defined(BUS_W_DLEN)
+	max_bus_size = BUS_W_DLEN - ADDR_LEN_4;
+#endif
+
+	if (strcmp(ts->chip_name, HX83121A_ID) == 0) {
+		if (max_bus_size > 4096)
+			max_bus_size = 4096;
+	}
+
+	remain_len = len;
+	address = le32_to_cpup((__le32 *)addr);
+
+	while (remain_len > 0) {
+		i = len - remain_len;
+		WORD_REG(tmp_addr, address + i);
+
+		if (remain_len > max_bus_size) {
+			g_core_fp.fp_register_write(ts, REG_GET_ARRAY(tmp_addr),
+				(u8 *)data + i, max_bus_size);
+			remain_len -= max_bus_size;
+		} else {
+			g_core_fp.fp_register_write(ts, REG_GET_ARRAY(tmp_addr),
+				(u8 *)data + i, remain_len);
+			remain_len = 0;
+		}
+	}
+
+	I("End");
+}
+
+static int himax_sram_write_crc_check(struct himax_ts_data *ts,
+				      u8 *addr, const u8 *data, u32 len)
+{
+	int retry = 0;
+	int crc = -1;
+
+	do {
+		g_core_fp.fp_write_sram_0f(ts, addr, data, len);
+		crc = g_core_fp.fp_check_crc(ts, addr, len);
+		retry++;
+		I("HW CRC %s in %d time",
+		  (crc == 0) ? "OK" : "Fail", retry);
+	} while (crc != 0 && retry < 3);
+
+	return crc;
+}
+
+static int code_overlay(struct zf_info *info, const struct firmware *fw,
+			struct himax_ts_data *ts, int type)
+{
+	int ret = 0;
+	int retry = 0;
+	union hx_dword_data_t tmp_addr = { .dword = 0x10007FFC };
+	union hx_dword_data_t rdata = {0};
+	u8 code_idx_t = 0;
+	union hx_dword_data_t code_sdata = {0};
+
+	/* ovl_idx[0] - sorting */
+	/* ovl_idx[1] - gesture */
+	/* ovl_idx[2] - border	*/
+
+	code_idx_t = ts->ovl_idx[0];
+	code_sdata.dword = ovl_sorting_reply;
+
+	if (type == 0) {
+		code_idx_t = ts->ovl_idx[2];
+		code_sdata.dword = ovl_border_reply;
+	}
+	if (code_idx_t == 0 || info[code_idx_t].write_size == 0) {
+		E("wrong code overlay section[%d, %d]!",
+		  code_idx_t, info[code_idx_t].write_size);
+		ret = FW_NOT_READY;
+		goto ALOC_CFG_BUF_FAIL;
+	}
+
+	I("upgrade code overlay section[%d]", code_idx_t);
+	if (himax_sram_write_crc_check(ts, info[code_idx_t].sram_addr,
+				       &fw->data[info[code_idx_t].fw_addr],
+				       info[code_idx_t].write_size) != 0) {
+		E("code overlay HW CRC FAIL");
+		code_sdata.dword = ovl_fault;
+		ret = 2;
+	}
+
+	retry = 0;
+	tmp_addr.dword = cpu_to_le32(tmp_addr.dword);
+	code_sdata.dword = cpu_to_le32(code_sdata.dword);
+	do {
+		g_core_fp.fp_register_write(ts, tmp_addr.byte, code_sdata.byte,
+			DATA_LEN_4);
+		usleep_range(1000, 1100);
+		g_core_fp.fp_register_read(ts, tmp_addr.byte, rdata.byte,
+			DATA_LEN_4);
+		retry++;
+	} while ((code_sdata.dword != rdata.dword) &&
+		(retry < HIMAX_REG_RETRY_TIMES));
+
+	if (retry >= HIMAX_REG_RETRY_TIMES)
+		E("fail code rpl data = 0x%08X", rdata.dword);
+
+ALOC_CFG_BUF_FAIL:
+	return ret;
+}
+
+static int alg_overlay(struct himax_ts_data *ts, u8 alg_idx_t,
+		       struct zf_info *info, const struct firmware *fw)
+{
+	int ret = 0;
+	int retry = 0;
+	union hx_dword_data_t tmp_addr = { .dword = 0x10007FFC };
+	union hx_dword_data_t rdata = {0};
+	u8 i = 0;
+	union hx_dword_data_t alg_sdata = { .dword = 0xA55A5AA5 };
+	union hx_dword_data_t data = { .dword = 0x00000001 };
+
+	if (alg_idx_t == 0 || info[alg_idx_t].write_size == 0) {
+		E("wrong alg overlay section[%d, %d]!",
+		  alg_idx_t, info[alg_idx_t].write_size);
+		ret = FW_NOT_READY;
+		goto ALOC_CFG_BUF_FAIL;
+	}
+
+	// clear handshaking to 0xA55A5AA5
+
+	retry = 0;
+	tmp_addr.dword = cpu_to_le32(tmp_addr.dword);
+	alg_sdata.dword = cpu_to_le32(alg_sdata.dword);
+	do {
+		g_core_fp.fp_register_write(ts, tmp_addr.byte, alg_sdata.byte,
+			DATA_LEN_4);
+		usleep_range(1000, 1100);
+		g_core_fp.fp_register_read(ts, tmp_addr.byte, rdata.byte,
+			DATA_LEN_4);
+	} while ((rdata.dword != alg_sdata.dword) &&
+	retry++ < HIMAX_REG_RETRY_TIMES);
+
+	if (retry > HIMAX_REG_RETRY_TIMES) {
+		E("init handshaking data FAIL[0x%08X]!!",
+		  le32_to_cpu(rdata.dword));
+	}
+
+	alg_sdata.dword = ovl_alg_reply;
+
+	g_core_fp.fp_reload_disable(ts, 0);
+
+	/*Rawout Sel initial*/
+	g_core_fp.fp_register_write(ts, FW_GET_ARRAY(addr_raw_out_sel),
+		FW_GET_ARRAY(data_clear), FW_GET_SZ(data_clear));
+	/*DSRAM func initial*/
+	g_core_fp.fp_assign_sorting_mode(ts, FW_GET_ARRAY(data_clear));
+	/* reset N frame back to default for normal mode */
+	g_core_fp.fp_register_write(ts, FW_GET_ARRAY(addr_set_frame_addr),
+		data.byte, 4);
+	/*FW reload done initial*/
+	g_core_fp.fp_register_write(ts,
+		DRV_GET_ARRAY(addr_fw_define_2nd_flash_reload),
+		FW_GET_ARRAY(data_clear), FW_GET_SZ(data_clear));
+
+	g_core_fp.fp_sense_on(ts, 0x00);
+
+	retry = 0;
+	do {
+		usleep_range(3000, 3100);
+		g_core_fp.fp_register_read(ts, tmp_addr.byte, rdata.byte, DATA_LEN_4);
+	} while ((rdata.dword != ovl_alg_request) && retry++ < 30);
+
+	if (retry > 30) {
+		E("fail req data = 0x%08X", le32_to_cpu(rdata.dword));
+		/* monitor FW status for debug */
+		for (i = 0; i < 10; i++) {
+			usleep_range(10000, 10100);
+			g_core_fp.fp_register_read(ts, tmp_addr.byte, rdata.byte,
+				DATA_LEN_4);
+			I("req data = 0x%08X", le32_to_cpu(rdata.dword));
+			g_core_fp.fp_read_FW_status(ts);
+		}
+		ret = 3;
+		goto BURN_OVL_FAIL;
+	}
+
+	I("upgrade alg overlay section[%d]", alg_idx_t);
+
+	if (himax_sram_write_crc_check(ts, info[alg_idx_t].sram_addr,
+				       &fw->data[info[alg_idx_t].fw_addr],
+				       info[alg_idx_t].write_size) != 0) {
+		E("Alg Overlay HW CRC FAIL");
+		ret = 2;
+	}
+
+	retry = 0;
+	do {
+		g_core_fp.fp_register_write(ts, tmp_addr.byte, alg_sdata.byte,
+			DATA_LEN_4);
+		usleep_range(1000, 1100);
+		g_core_fp.fp_register_read(ts, tmp_addr.byte, rdata.byte, DATA_LEN_4);
+	} while ((alg_sdata.dword != rdata.dword) &&
+	retry++ < HIMAX_REG_RETRY_TIMES);
+
+	if (retry > HIMAX_REG_RETRY_TIMES) {
+		E("fail rpl data = 0x%08X",	le32_to_cpu(rdata.dword));
+		// maybe need to reset
+	} else {
+		I("waiting for FW reload data");
+
+		retry = 0;
+		while (retry++ < 30) {
+			g_core_fp.fp_register_read(ts,
+				DRV_GET_ARRAY(addr_fw_define_2nd_flash_reload),
+				data.byte, DATA_LEN_4);
+
+			/* use all 4 bytes to compare */
+			if (le32_to_cpu(data.dword) == 0x72C0) {
+				I("FW reload done");
+					break;
+			}
+			I("wait FW reload %d times", retry);
+			g_core_fp.fp_read_FW_status(ts);
+			usleep_range(10000, 11000);
+		}
+	}
+
+BURN_OVL_FAIL:
+ALOC_CFG_BUF_FAIL:
+	return ret;
+}
+
+int himax_zf_part_info(const struct firmware *fw, struct himax_ts_data *ts,
+		       int type)
+{
+	u32 table_addr = FLASH_VER_GET_VAL(addr_cfg_table);
+	int pnum = 0;
+	int ret = 0;
+	u8 buf[16];
+	struct zf_info *info;
+	u8 sram_min[4];
+	int cfg_sz = 0;
+	int cfg_crc_sw = 0;
+	int cfg_crc_hw = 0;
+	s32 i = 0;
+	int i_max = 0;
+	int i_min = 0;
+	u32 dsram_base = 0xFFFFFFFF;
+	u32 dsram_max = 0;
+	int retry = 0;
+	int allovlidx = 0;
+	s32 alg_idx_t = 0;
+	s32 j = 0;
+	bool has_code_overlay = false;
+
+	ts->has_alg_overlay = false;
+
+	/* 1. initial check */
+	if (g_core_fp._en_hw_crc)
+		g_core_fp._en_hw_crc(ts, 1);
+	pnum = fw->data[table_addr + 12];
+	if (pnum < 2) {
+		E("partition number is not correct");
+		return FW_NOT_READY;
+	}
+
+	info = kcalloc(pnum, sizeof(struct zf_info), GFP_KERNEL);
+	if (!info) {
+		E("memory allocation fail[info]!!");
+		return 1;
+	}
+	memset(info, 0, pnum * sizeof(struct zf_info));
+	if (!ts->ovl_idx) {
+		ts->ovl_idx = kcalloc(ovl_section_num, sizeof(u8), GFP_KERNEL);
+		if (!ts->ovl_idx) {
+			E("memory allocation fail[ovl_idx]!!");
+			ret = 1;
+			goto ALOC_CFG_BUF_FAIL;
+		}
+	}
+	memset(ts->ovl_idx, 0, ovl_section_num);
+
+	/* 2. record partition information */
+	memcpy(buf, &fw->data[table_addr], 16);
+	memcpy(info[0].sram_addr, buf, 4);
+	info[0].write_size = le32_to_cpup((u32 *)&buf[4]);
+	info[0].fw_addr = le32_to_cpup((u32 *)&buf[8]);
+	I("[%d]SRAM addr=%08X, fw_addr=%08X, write_size=%d",
+	  0, info[0].cfg_addr, info[0].fw_addr,
+	  info[0].write_size);
+
+	for (i = 1; i < pnum; i++) {
+		memcpy(buf, &fw->data[i * 0x10 + table_addr], 16);
+
+		memcpy(info[i].sram_addr, buf, 4);
+		info[i].write_size = le32_to_cpup((u32 *)&buf[4]);
+		info[i].fw_addr = le32_to_cpup((u32 *)&buf[8]);
+		info[i].cfg_addr = le32_to_cpup((u32 *)&info[i].sram_addr[0]);
+
+		if (info[i].cfg_addr % 4 != 0)
+			info[i].cfg_addr -= (info[i].cfg_addr % 4);
+
+		I("[%d]SRAM addr=%08X, fw_addr=%08X, write_size=%d",
+		  i, info[i].cfg_addr, info[i].fw_addr,
+		  info[i].write_size);
+
+		/* alg overlay section */
+		if ((buf[15] == 0x77 && buf[14] == 0x88)) {
+			I("find alg overlay section in index %d", i);
+			/* record index of alg overlay section */
+			allovlidx |= 1 << i;
+			alg_idx_t = i;
+			ts->has_alg_overlay = true;
+			continue;
+		}
+
+		/* code overlay section */
+		if ((buf[15] == 0x55 && buf[14] == 0x66) ||
+		    le32_to_cpup((u32 *)&buf[0]) == 0x20008CE0) {
+			I("find code overlay section in index %d", i);
+			has_code_overlay = true;
+			/* record index of code overlay section */
+			allovlidx |= 1 << i;
+			if (buf[15] == 0x55 && buf[14] == 0x66) {
+				/* current mechanism */
+				j = buf[13];
+				if (j < ovl_section_num)
+					ts->ovl_idx[j] = i;
+			} else {
+				/* previous mechanism */
+				if (j < ovl_section_num)
+					ts->ovl_idx[j++] = i;
+			}
+			continue;
+		}
+
+		if (dsram_base > info[i].cfg_addr) {
+			dsram_base = info[i].cfg_addr;
+			i_min = i;
+		}
+		if (dsram_max < info[i].cfg_addr) {
+			dsram_max = info[i].cfg_addr;
+			i_max = i;
+		}
+	}
+
+	/* 3. prepare data to update */
+	for (i = 0; i < ADDR_LEN_4; i++)
+		sram_min[i] = (info[i_min].cfg_addr >> (8 * i)) & 0xFF;
+
+	D("dsram_max: %d, dsram_base: %d, write_size: %d",
+	  dsram_max, dsram_base, info[i_max].write_size);
+	cfg_sz = (dsram_max - dsram_base) + info[i_max].write_size;
+	if (cfg_sz % 16 != 0)
+		cfg_sz = cfg_sz + 16 - (cfg_sz % 16);
+
+	I("cfg_sz = %d!, dsram_base = %X, dsram_max = %X",
+	  cfg_sz, dsram_base, dsram_max);
+	/* config size should be smaller than DSRAM size */
+	if (cfg_sz > ts->chip_max_dsram_size) {
+		E("config size error[%d, %d]!!",
+		  cfg_sz, ts->chip_max_dsram_size);
+		ret = LENGTH_FAIL;
+		goto ALOC_CFG_BUF_FAIL;
+	}
+
+	memset(ts->zf_update_cfg_buffer, 0x00,
+	       ts->chip_max_dsram_size * sizeof(u8));
+
+	for (i = 1; i < pnum; i++) {
+		/* overlay section */
+		if (allovlidx & (1 << i)) {
+			I("skip overlay section %d", i);
+			continue;
+		}
+
+		memcpy(&ts->zf_update_cfg_buffer[info[i].cfg_addr - dsram_base],
+		       &fw->data[info[i].fw_addr], info[i].write_size);
+	}
+
+	/* 4. write to sram */
+	/* FW entity */
+	if (himax_sram_write_crc_check(ts, info[0].sram_addr,
+				       &fw->data[info[0].fw_addr], info[0].write_size) != 0) {
+		E("HW CRC FAIL");
+		ret = 2;
+		goto BURN_SRAM_FAIL;
+	}
+
+	cfg_crc_sw = g_core_fp.fp_calculate_crc_with_ap(ts->zf_update_cfg_buffer,
+		0, cfg_sz);
+	do {
+		g_core_fp.fp_write_sram_0f(ts, sram_min, ts->zf_update_cfg_buffer,
+			cfg_sz);
+		cfg_crc_hw = g_core_fp.fp_check_crc(ts, sram_min, cfg_sz);
+		if (cfg_crc_hw != cfg_crc_sw) {
+			E("Cfg CRC FAIL,HWCRC=%X,SWCRC=%X,retry=%d",
+			  cfg_crc_hw, cfg_crc_sw, retry);
+		}
+	} while (cfg_crc_hw != cfg_crc_sw && retry++ < 3);
+
+	if (retry > 3) {
+		ret = 2;
+		goto BURN_SRAM_FAIL;
+	}
+
+	/*write back system config*/
+	if (type == 0)
+		g_core_fp.fp_resend_cmd_func(ts, ts->suspended);
+
+	if (ts->has_alg_overlay)
+		ret = alg_overlay(ts, alg_idx_t, info, fw);
+	if (has_code_overlay)
+		ret = code_overlay(info, fw, ts, type);
+
+BURN_SRAM_FAIL:
+ALOC_CFG_BUF_FAIL:
+	kfree(info);
+
+	return ret;
+/* ret = 1, memory allocation fail
+ *     = 2, crc fail
+ *     = 3, flow control error
+ */
+}
+
+int himax_mcu_firmware_update_0f(const struct firmware *fw,
+				 struct himax_ts_data *ts, int type)
+{
+	int ret = 0;
+	bool bret;
+
+	I("Entering - total FW size=%d", (int)fw->size);
+
+	g_core_fp.fp_register_write(ts, ZF_GET_ARRAY(addr_system_reset),
+		ZF_GET_ARRAY(data_system_reset), 4);
+
+	bret = g_core_fp.fp_sense_off(ts, false);
+	if (!bret) {
+		E("sense off fail");
+		return -1;
+	}
+
+	if ((int)fw->size > HX64K) {
+		ret = himax_zf_part_info(fw, ts, type);
+	} else {
+		/* first 48K */
+		ret = himax_sram_write_crc_check
+			(ts, ZF_GET_ARRAY(data_sram_start_addr), &fw->data[0], HX_48K_SZ);
+		if (ret != 0)
+			E("HW CRC FAIL - Main SRAM 48K");
+
+		/*config info*/
+		if (!ts->ic_data->has_flash) {
+			ret = himax_sram_write_crc_check(ts, ZF_GET_ARRAY(data_cfg_info),
+							 &fw->data[0xc000], 128);
+			if (ret != 0)
+				E("Config info CRC Fail!");
+		} else {
+			g_core_fp.fp_clean_sram_0f(ts, ZF_GET_ARRAY(data_cfg_info),
+				128, 2);
+		}
+
+		if (!ts->ic_data->has_flash) {
+			ret = himax_sram_write_crc_check(ts, ZF_GET_ARRAY(data_fw_cfg_1),
+							 &fw->data[0xc0fe], 528);
+			if (ret != 0)
+				E("FW config 1 CRC Fail!");
+		} else {
+			g_core_fp.fp_clean_sram_0f(ts, ZF_GET_ARRAY(data_fw_cfg_1),
+				528, 1);
+		}
+
+		if (!ts->ic_data->has_flash) {
+			ret = himax_sram_write_crc_check(ts, ZF_GET_ARRAY(data_fw_cfg_3),
+							 &fw->data[0xca00], 128);
+			if (ret != 0)
+				E("FW config 3 CRC Fail!");
+		} else {
+			g_core_fp.fp_clean_sram_0f(ts, ZF_GET_ARRAY(data_fw_cfg_3),
+				128, 2);
+		}
+
+		/*ADC config*/
+		if (!ts->ic_data->has_flash) {
+			ret = himax_sram_write_crc_check(ts, ZF_GET_ARRAY(data_adc_cfg_1),
+							 &fw->data[0xd640], 1200);
+			if (ret != 0)
+				E("ADC config 1 CRC Fail!");
+		} else {
+			g_core_fp.fp_clean_sram_0f(ts, ZF_GET_ARRAY(data_adc_cfg_1),
+				1200, 2);
+		}
+
+		if (!ts->ic_data->has_flash) {
+			ret = himax_sram_write_crc_check(ts, ZF_GET_ARRAY(data_adc_cfg_2),
+							 &fw->data[0xd320], 800);
+			if (ret != 0)
+				E("ADC config 2 CRC Fail!");
+		} else {
+			g_core_fp.fp_clean_sram_0f(ts, ZF_GET_ARRAY(data_adc_cfg_2),
+				800, 2);
+		}
+
+		/*mapping table*/
+		if (!ts->ic_data->has_flash) {
+			ret = himax_sram_write_crc_check(ts, ZF_GET_ARRAY(data_map_table),
+							 &fw->data[0xe000], 1536);
+			if (ret != 0)
+				E("Mapping table CRC Fail!");
+		} else {
+			g_core_fp.fp_clean_sram_0f(ts, ZF_GET_ARRAY(data_map_table),
+				1536, 2);
+		}
+	}
+
+	I("End");
+
+	return ret;
+}
+
+int hx_0f_op_file_dirly(char *file_name, struct himax_ts_data *ts)
+{
+	const struct firmware *fw = NULL;
+	int reqret = -1;
+	int ret = -1;
+	int type = 0; /* FW type: 0, normal; 1, MPAP */
+
+	if (ts->zf_update_flag) {
+		W("Other thread is updating now!");
+		return ret;
+	}
+	ts->zf_update_flag = true;
+	I("Preparing to update %s!", file_name);
+
+	reqret = request_firmware(&fw, file_name, ts->dev);
+	if (reqret < 0) {
+		ret = reqret;
+		E("request firmware fail, code[%d]!!", ret);
+		goto END;
+	}
+
+	if (strcmp(file_name, MPAP_FWNAME) == 0)
+		type = 1;
+
+	ret = g_core_fp.fp_firmware_update_0f(fw, ts, type);
+
+	if (reqret >= 0)
+		release_firmware(fw);
+
+	if (ret < 0)
+		goto END;
+
+	if (!ts->has_alg_overlay) {
+		if (type == 1)
+			g_core_fp.fp_turn_on_mp_func(ts, 1);
+		else
+			g_core_fp.fp_turn_on_mp_func(ts, 0);
+		g_core_fp.fp_reload_disable(ts, 0);
+		g_core_fp.fp_power_on_init(ts);
+	}
+
+END:
+	ts->zf_update_flag = false;
+
+	I("END");
+	return ret;
+}
+
+static int himax_mcu_0f_excp_check(void)
+{
+	return NO_ERR;
+}
+
+void himax_mcu_read_sram_0f(struct himax_ts_data *ts,
+			    const struct firmware *fw_entry,
+			    u8 *addr, int start_index, int read_len)
+{
+	int total_read_times = 0;
+	int max_bus_size = MAX_I2C_TRANS_SZ;
+	int total_size_temp = 0;
+	int total_size = 0;
+	int address = 0;
+	int i = 0, j = 0;
+	int not_same = 0;
+	struct hx_reg_t in_addr = { .data = {0}, .len = 4 };
+	struct hx_reg_t tmp_addr = { .data = {0}, .len = 4 };
+	u8 *temp_info_data = NULL;
+	int *not_same_buff = NULL;
+
+	I("Entering");
+	PTR_SET(in_addr, addr, 4);
+	total_size = read_len;
+	total_size_temp = read_len;
+
+	if (read_len > 2048)
+		max_bus_size = 2048;
+	else
+		max_bus_size = read_len;
+
+	if (total_size % max_bus_size == 0)
+		total_read_times = total_size / max_bus_size;
+	else
+		total_read_times = total_size / max_bus_size + 1;
+
+	I("total size=%d, bus size=%d, read time=%d",
+	  total_size, max_bus_size,	total_read_times);
+
+	memcpy(REG_GET_ARRAY(tmp_addr), addr, 4);
+	I("addr[3]=0x%2X,addr[2]=0x%2X,addr[1]=0x%2X,addr[0]=0x%2X",
+	  REG_GET_ARRAY(tmp_addr)[3], REG_GET_ARRAY(tmp_addr)[2],
+	  REG_GET_ARRAY(tmp_addr)[1], REG_GET_ARRAY(tmp_addr)[0]);
+
+	temp_info_data = kcalloc(total_size, sizeof(u8), GFP_KERNEL);
+	if (!temp_info_data) {
+		E("Failed to allocate temp_info_data");
+		goto err_malloc_temp_info_data;
+	}
+
+	not_same_buff = kcalloc(total_size, sizeof(int), GFP_KERNEL);
+	if (!not_same_buff) {
+		E("Failed to allocate not_same_buff");
+		goto err_malloc_not_same_buff;
+	}
+
+	for (i = 0; i < (total_read_times); i++) {
+		if (total_size_temp >= max_bus_size) {
+			g_core_fp.fp_register_read(ts, REG_GET_ARRAY(tmp_addr),
+				&temp_info_data[i * max_bus_size], max_bus_size);
+			total_size_temp = total_size_temp - max_bus_size;
+		} else {
+			g_core_fp.fp_register_read(ts, REG_GET_ARRAY(tmp_addr),
+				&temp_info_data[i * max_bus_size],
+				total_size_temp % max_bus_size);
+		}
+
+		address = ((i + 1) * max_bus_size);
+		WORD_REG(tmp_addr, address + REG_GET_VAL(in_addr));
+	}
+	I("READ Start, start_index = %d", start_index);
+
+	j = start_index;
+	for (i = 0; i < read_len; i++, j++) {
+		if (fw_entry->data[j] != temp_info_data[i]) {
+			not_same++;
+			not_same_buff[i] = 1;
+		}
+
+		I("0x%2.2X, ", temp_info_data[i]);
+
+		if (i > 0 && i % 16 == 15)
+			pr_info("\n");
+	}
+	I("READ END,Not Same count=%d", not_same);
+
+	if (not_same != 0) {
+		j = start_index;
+		for (i = 0; i < read_len; i++, j++) {
+			if (not_same_buff[i] == 1)
+				I("bin=[%d] 0x%2.2X", i, fw_entry->data[j]);
+		}
+		for (i = 0; i < read_len; i++, j++) {
+			if (not_same_buff[i] == 1)
+				I("sram=[%d] 0x%2.2X", i, temp_info_data[i]);
+		}
+	}
+	I("READ END, Not Same count=%d", not_same);
+
+	kfree(not_same_buff);
+err_malloc_not_same_buff:
+	kfree(temp_info_data);
+err_malloc_temp_info_data:
+	return;
+}
+
+void himax_mcu_read_all_sram(struct himax_ts_data *ts, u8 *addr,
+			     int read_len)
+{
+	int total_read_times = 0;
+	int max_bus_size = MAX_I2C_TRANS_SZ;
+	int total_size_temp = 0;
+	int total_size = 0;
+	int address = 0;
+	int i = 0;
+	struct hx_reg_t tmp_addr = { .data = {0}, .len = 4 };
+	u8 *temp_info_data;
+
+	I("Entering");
+
+	total_size = read_len;
+	total_size_temp = read_len;
+
+	if (total_size % max_bus_size == 0)
+		total_read_times = total_size / max_bus_size;
+	else
+		total_read_times = total_size / max_bus_size + 1;
+
+	I("total size=%d", total_size);
+
+	PTR_SET(tmp_addr, addr, 4);
+	I("addr[3]=0x%2X,addr[2]=0x%2X,addr[1]=0x%2X,addr[0]=0x%2X",
+	  REG_GET_ARRAY(tmp_addr)[3], REG_GET_ARRAY(tmp_addr)[2],
+	  REG_GET_ARRAY(tmp_addr)[1], REG_GET_ARRAY(tmp_addr)[0]);
+
+	temp_info_data = kcalloc(total_size, sizeof(u8), GFP_KERNEL);
+	if (!temp_info_data) {
+		E("Failed to allocate temp_info_data");
+		return;
+	}
+
+	for (i = 0; i < (total_read_times); i++) {
+		if (total_size_temp >= max_bus_size) {
+			g_core_fp.fp_register_read(ts, REG_GET_ARRAY(tmp_addr),
+				&temp_info_data[i * max_bus_size], max_bus_size);
+			total_size_temp = total_size_temp - max_bus_size;
+		} else {
+			g_core_fp.fp_register_read(ts, REG_GET_ARRAY(tmp_addr),
+				&temp_info_data[i * max_bus_size],
+				total_size_temp % max_bus_size);
+		}
+
+		address = ((i + 1) * max_bus_size);
+		WORD_REG(tmp_addr, address + REG_GET_VAL(tmp_addr));
+	}
+	I("addr[3]=0x%2X,addr[2]=0x%2X,addr[1]=0x%2X,addr[0]=0x%2X",
+	  REG_GET_ARRAY(tmp_addr)[3], REG_GET_ARRAY(tmp_addr)[2],
+	  REG_GET_ARRAY(tmp_addr)[1], REG_GET_ARRAY(tmp_addr)[0]);
+
+	kfree(temp_info_data);
+
+	I("END");
+}
+
+void himax_mcu_firmware_read_0f(struct himax_ts_data *ts,
+				const struct firmware *fw_entry, int type)
+{
+	u8 tmp_addr[4];
+
+	I("Entering");
+	if (type == 0) { /* first 48K */
+		g_core_fp.fp_read_sram_0f(ts, fw_entry,
+			ZF_GET_ARRAY(data_sram_start_addr),
+			0,
+			HX_48K_SZ);
+		g_core_fp.fp_read_all_sram(ts, tmp_addr, 0xC000);
+	} else { /*last 16k*/
+		g_core_fp.fp_read_sram_0f(ts, fw_entry, ZF_GET_ARRAY(data_cfg_info),
+			0xC000, 132);
+
+		/*FW config*/
+		g_core_fp.fp_read_sram_0f(ts, fw_entry, ZF_GET_ARRAY(data_fw_cfg_1),
+			0xC0FE, 484);
+		g_core_fp.fp_read_sram_0f(ts, fw_entry, ZF_GET_ARRAY(data_fw_cfg_2),
+			0xC9DE, 36);
+		g_core_fp.fp_read_sram_0f(ts, fw_entry, ZF_GET_ARRAY(data_fw_cfg_3),
+			0xCA00, 72);
+
+		/*ADC config*/
+
+		g_core_fp.fp_read_sram_0f(ts, fw_entry, ZF_GET_ARRAY(data_adc_cfg_1),
+			0xD630, 1188);
+		g_core_fp.fp_read_sram_0f(ts, fw_entry, ZF_GET_ARRAY(data_adc_cfg_2),
+			0xD318, 792);
+
+		/*mapping table*/
+		g_core_fp.fp_read_sram_0f(ts, fw_entry, ZF_GET_ARRAY(data_map_table),
+			0xE000, 1536);
+
+		/* set n frame=0*/
+		g_core_fp.fp_read_sram_0f(ts, fw_entry,
+			FW_GET_ARRAY(addr_set_frame_addr), 0xC30C, 4);
+	}
+
+	I("END");
+}
+
+void himax_ic_reg_init(struct himax_core_command_regs *reg_data)
+{
+	I("Entering!");
+/* CORE_IC -start- */
+	BYTE_REG(reg_data->ic_op.addr_ahb_addr_byte_0, ic_adr_ahb_addr_byte_0);
+	BYTE_REG(reg_data->ic_op.addr_ahb_rdata_byte_0, ic_adr_ahb_rdata_byte_0);
+	BYTE_REG(reg_data->ic_op.addr_ahb_access_direction, ic_adr_ahb_access_direction);
+	BYTE_REG(reg_data->ic_op.addr_conti, ic_adr_conti);
+	BYTE_REG(reg_data->ic_op.addr_incr4, ic_adr_incr4);
+	BYTE_REG(reg_data->ic_op.adr_i2c_psw_lb, ic_adr_i2c_psw_lb);
+	BYTE_REG(reg_data->ic_op.adr_i2c_psw_ub, ic_adr_i2c_psw_ub);
+	BYTE_REG(reg_data->ic_op.data_ahb_access_direction_read, ic_cmd_ahb_access_direction_read);
+	BYTE_REG(reg_data->ic_op.data_conti, ic_cmd_conti);
+	BYTE_REG(reg_data->ic_op.data_incr4, ic_cmd_incr4);
+	BYTE_REG(reg_data->ic_op.data_i2c_psw_lb, ic_cmd_i2c_psw_lb);
+	BYTE_REG(reg_data->ic_op.data_i2c_psw_ub, ic_cmd_i2c_psw_ub);
+	WORD_REG(reg_data->ic_op.addr_tcon_on_rst, ic_adr_tcon_on_rst);
+	WORD_REG(reg_data->ic_op.addr_adc_on_rst, ic_addr_adc_on_rst);
+	WORD_REG(reg_data->ic_op.addr_psl, ic_adr_psl);
+	WORD_REG(reg_data->ic_op.addr_cs_central_state, ic_adr_cs_central_state);
+	WORD_REG(reg_data->ic_op.data_rst, ic_cmd_rst);
+	WORD_REG(reg_data->ic_op.adr_osc_en, ic_adr_osc_en);
+	WORD_REG(reg_data->ic_op.adr_osc_pw, ic_adr_osc_pw);
+/* CORE_IC -end- */
+/* CORE_FW -start- */
+	WORD_REG(reg_data->fw_op.addr_system_reset, fw_addr_system_reset);
+	WORD_REG(reg_data->fw_op.addr_ctrl_fw_isr, fw_addr_ctrl_fw);
+	WORD_REG(reg_data->fw_op.addr_flag_reset_event, fw_addr_flag_reset_event);
+	WORD_REG(reg_data->fw_op.addr_hsen_enable, fw_addr_hsen_enable);
+	WORD_REG(reg_data->fw_op.addr_program_reload_from,
+		 fw_addr_program_reload_from);
+	WORD_REG(reg_data->fw_op.addr_program_reload_to,
+		 fw_addr_program_reload_to);
+	WORD_REG(reg_data->fw_op.addr_program_reload_page_write,
+		 fw_addr_program_reload_page_write);
+	WORD_REG(reg_data->fw_op.addr_raw_out_sel, fw_addr_raw_out_sel);
+	WORD_REG(reg_data->fw_op.addr_reload_status, fw_addr_reload_status);
+	WORD_REG(reg_data->fw_op.addr_reload_crc32_result,
+		 fw_addr_reload_crc32_result);
+	WORD_REG(reg_data->fw_op.addr_reload_addr_from, fw_addr_reload_addr_from);
+	WORD_REG(reg_data->fw_op.addr_reload_addr_cmd_beat,
+		 fw_addr_reload_addr_cmd_beat);
+	WORD_REG(reg_data->fw_op.addr_selftest_addr_en, fw_addr_selftest_addr_en);
+	WORD_REG(reg_data->fw_op.addr_criteria_addr, fw_addr_criteria_addr);
+	WORD_REG(reg_data->fw_op.addr_set_frame_addr, fw_addr_set_frame_addr);
+	WORD_REG(reg_data->fw_op.addr_selftest_result_addr,
+		 fw_addr_selftest_result_addr);
+	WORD_REG(reg_data->fw_op.addr_sorting_mode_en, fw_addr_sorting_mode_en);
+	WORD_REG(reg_data->fw_op.addr_fw_mode_status, fw_addr_fw_mode_status);
+	WORD_REG(reg_data->fw_op.addr_icid_addr, fw_addr_icid_addr);
+	WORD_REG(reg_data->fw_op.addr_fw_ver_addr, fw_addr_fw_ver_addr);
+	WORD_REG(reg_data->fw_op.addr_fw_cfg_addr, fw_addr_fw_cfg_addr);
+	WORD_REG(reg_data->fw_op.addr_fw_vendor_addr, fw_addr_fw_vendor_addr);
+	WORD_REG(reg_data->fw_op.addr_cus_info, fw_addr_cus_info);
+	WORD_REG(reg_data->fw_op.addr_proj_info, fw_addr_proj_info);
+	WORD_REG(reg_data->fw_op.addr_fw_state_addr, fw_addr_fw_state_addr);
+	WORD_REG(reg_data->fw_op.addr_fw_dbg_msg_addr, fw_addr_fw_dbg_msg_addr);
+	WORD_REG(reg_data->fw_op.addr_chk_fw_status, fw_addr_chk_fw_status);
+	WORD_REG(reg_data->fw_op.addr_dd_handshak_addr, fw_addr_dd_handshak_addr);
+	WORD_REG(reg_data->fw_op.addr_dd_data_addr, fw_addr_dd_data_addr);
+	WORD_REG(reg_data->fw_op.addr_clr_fw_record_dd_sts,
+		 fw_addr_clr_fw_record_dd_sts);
+	WORD_REG(reg_data->fw_op.addr_ap_notify_fw_sus, fw_addr_ap_notify_fw_sus);
+	WORD_REG(reg_data->fw_op.data_ap_notify_fw_sus_en,
+		 fw_data_ap_notify_fw_sus_en);
+	WORD_REG(reg_data->fw_op.data_ap_notify_fw_sus_dis,
+		 fw_data_ap_notify_fw_sus_dis);
+	WORD_REG(reg_data->fw_op.data_system_reset, fw_data_system_reset);
+	WORD_REG(reg_data->fw_op.data_safe_mode_release_pw_active,
+		 fw_data_safe_mode_release_pw_active);
+	WORD_REG(reg_data->fw_op.data_safe_mode_release_pw_reset,
+		 fw_data_safe_mode_release_pw_reset);
+	WORD_REG(reg_data->fw_op.data_clear, fw_data_clear);
+	WORD_REG(reg_data->fw_op.data_fw_stop, fw_data_fw_stop);
+	WORD_REG(reg_data->fw_op.data_program_reload_start,
+		 fw_data_program_reload_start);
+	WORD_REG(reg_data->fw_op.data_program_reload_compare,
+		 fw_data_program_reload_compare);
+	WORD_REG(reg_data->fw_op.data_program_reload_break,
+		 fw_data_program_reload_break);
+	WORD_REG(reg_data->fw_op.data_selftest_request, fw_data_selftest_request);
+	BYTE_REG(reg_data->fw_op.data_criteria_aa_top, fw_data_criteria_aa_top);
+	BYTE_REG(reg_data->fw_op.data_criteria_aa_bot, fw_data_criteria_aa_bot);
+	BYTE_REG(reg_data->fw_op.data_criteria_key_top, fw_data_criteria_key_top);
+	BYTE_REG(reg_data->fw_op.data_criteria_key_bot, fw_data_criteria_key_bot);
+	BYTE_REG(reg_data->fw_op.data_criteria_avg_top, fw_data_criteria_avg_top);
+	BYTE_REG(reg_data->fw_op.data_criteria_avg_bot, fw_data_criteria_avg_bot);
+	WORD_REG(reg_data->fw_op.data_set_frame, fw_data_set_frame);
+	BYTE_REG(reg_data->fw_op.data_selftest_ack_hb, fw_data_selftest_ack_hb);
+	BYTE_REG(reg_data->fw_op.data_selftest_ack_lb, fw_data_selftest_ack_lb);
+	BYTE_REG(reg_data->fw_op.data_selftest_pass, fw_data_selftest_pass);
+	BYTE_REG(reg_data->fw_op.data_normal_cmd, fw_data_normal_cmd);
+	BYTE_REG(reg_data->fw_op.data_normal_status, fw_data_normal_status);
+	BYTE_REG(reg_data->fw_op.data_sorting_cmd, fw_data_sorting_cmd);
+	BYTE_REG(reg_data->fw_op.data_sorting_status, fw_data_sorting_status);
+	BYTE_REG(reg_data->fw_op.data_dd_request, fw_data_dd_request);
+	BYTE_REG(reg_data->fw_op.data_dd_ack, fw_data_dd_ack);
+	BYTE_REG(reg_data->fw_op.data_idle_dis_pwd, fw_data_idle_dis_pwd);
+	BYTE_REG(reg_data->fw_op.data_idle_en_pwd, fw_data_idle_en_pwd);
+	BYTE_REG(reg_data->fw_op.data_rawdata_ready_hb, fw_data_rawdata_ready_hb);
+	BYTE_REG(reg_data->fw_op.data_rawdata_ready_lb, fw_data_rawdata_ready_lb);
+	BYTE_REG(reg_data->fw_op.addr_ahb_addr, fw_addr_ahb_addr);
+	BYTE_REG(reg_data->fw_op.data_ahb_dis, fw_data_ahb_dis);
+	BYTE_REG(reg_data->fw_op.data_ahb_en, fw_data_ahb_en);
+	BYTE_REG(reg_data->fw_op.addr_event_addr, fw_addr_event_addr);
+	WORD_REG(reg_data->fw_op.addr_usb_detect, fw_usb_detect_addr);
+/* CORE_FW -end- */
+/* CORE_FLASH -start- */
+	WORD_REG(reg_data->flash_op.addr_spi200_trans_fmt,
+		 flash_addr_spi200_trans_fmt);
+	WORD_REG(reg_data->flash_op.addr_spi200_trans_ctrl,
+		 flash_addr_spi200_trans_ctrl);
+	WORD_REG(reg_data->flash_op.addr_spi200_fifo_rst,
+		 flash_addr_spi200_fifo_rst);
+	WORD_REG(reg_data->flash_op.addr_spi200_flash_speed,
+		 flash_addr_spi200_flash_speed);
+	WORD_REG(reg_data->flash_op.addr_spi200_rst_status,
+		 flash_addr_spi200_rst_status);
+	WORD_REG(reg_data->flash_op.addr_spi200_cmd, flash_addr_spi200_cmd);
+	WORD_REG(reg_data->flash_op.addr_spi200_addr, flash_addr_spi200_addr);
+	WORD_REG(reg_data->flash_op.addr_spi200_data, flash_addr_spi200_data);
+	WORD_REG(reg_data->flash_op.addr_spi200_bt_num, flash_addr_spi200_bt_num);
+	WORD_REG(reg_data->flash_op.data_spi200_trans_fmt,
+		 flash_data_spi200_trans_fmt);
+	WORD_REG(reg_data->flash_op.data_spi200_txfifo_rst,
+		 flash_data_spi200_txfifo_rst);
+	WORD_REG(reg_data->flash_op.data_spi200_rxfifo_rst,
+		 flash_data_spi200_rxfifo_rst);
+	WORD_REG(reg_data->flash_op.data_spi200_trans_ctrl_1,
+		 flash_data_spi200_trans_ctrl_1);
+	WORD_REG(reg_data->flash_op.data_spi200_trans_ctrl_2,
+		 flash_data_spi200_trans_ctrl_2);
+	WORD_REG(reg_data->flash_op.data_spi200_trans_ctrl_3,
+		 flash_data_spi200_trans_ctrl_3);
+	WORD_REG(reg_data->flash_op.data_spi200_trans_ctrl_4,
+		 flash_data_spi200_trans_ctrl_4);
+	WORD_REG(reg_data->flash_op.data_spi200_trans_ctrl_5,
+		 flash_data_spi200_trans_ctrl_5);
+	WORD_REG(reg_data->flash_op.data_spi200_trans_ctrl_6,
+		 flash_data_spi200_trans_ctrl_6);
+	WORD_REG(reg_data->flash_op.data_spi200_trans_ctrl_7,
+		 flash_data_spi200_trans_ctrl_7);
+	WORD_REG(reg_data->flash_op.data_spi200_cmd_1, flash_data_spi200_cmd_1);
+	WORD_REG(reg_data->flash_op.data_spi200_cmd_2, flash_data_spi200_cmd_2);
+	WORD_REG(reg_data->flash_op.data_spi200_cmd_3, flash_data_spi200_cmd_3);
+	WORD_REG(reg_data->flash_op.data_spi200_cmd_4, flash_data_spi200_cmd_4);
+	WORD_REG(reg_data->flash_op.data_spi200_cmd_5, flash_data_spi200_cmd_5);
+	WORD_REG(reg_data->flash_op.data_spi200_cmd_6, flash_data_spi200_cmd_6);
+	WORD_REG(reg_data->flash_op.data_spi200_cmd_7, flash_data_spi200_cmd_7);
+	WORD_REG(reg_data->flash_op.data_spi200_cmd_8, flash_data_spi200_cmd_8);
+	WORD_REG(reg_data->flash_op.data_spi200_addr, flash_data_spi200_addr);
+/* CORE_FLASH -end- */
+/* CORE_SRAM */
+	/* sram start*/
+	WORD_REG(reg_data->sram_op.addr_mkey, sram_adr_mkey);
+	WORD_REG(reg_data->sram_op.addr_rawdata_addr, sram_adr_rawdata_addr);
+	WORD_REG(reg_data->sram_op.addr_rawdata_end, sram_adr_rawdata_end);
+	HALF_REG(reg_data->sram_op.passwrd_start, sram_passwrd_start);
+	HALF_REG(reg_data->sram_op.passwrd_end, sram_passwrd_end);
+	/* sram end*/
+/* CORE_SRAM */
+/* CORE_DRIVER -start- */
+	WORD_REG(reg_data->driver_op.addr_fw_define_flash_reload,
+		 driver_addr_fw_define_flash_reload);
+	WORD_REG(reg_data->driver_op.addr_fw_define_2nd_flash_reload,
+		 driver_addr_fw_define_2nd_flash_reload);
+	WORD_REG(reg_data->driver_op.addr_fw_define_int_is_edge,
+		 driver_addr_fw_define_int_is_edge);
+	WORD_REG(reg_data->driver_op.addr_fw_define_rxnum_txnum,
+		 driver_addr_fw_define_rxnum_txnum);
+	WORD_REG(reg_data->driver_op.addr_fw_define_maxpt_xyrvs,
+		 driver_addr_fw_define_maxpt_xyrvs);
+	WORD_REG(reg_data->driver_op.addr_fw_define_x_y_res,
+		 driver_addr_fw_define_x_y_res);
+	BYTE_REG(reg_data->driver_op.data_df_rx, driver_data_df_rx);
+	BYTE_REG(reg_data->driver_op.data_df_tx, driver_data_df_tx);
+	BYTE_REG(reg_data->driver_op.data_df_pt, driver_data_df_pt);
+	WORD_REG(reg_data->driver_op.data_fw_define_flash_reload_dis,
+		 driver_data_fw_define_flash_reload_dis);
+	WORD_REG(reg_data->driver_op.data_fw_define_flash_reload_en,
+		 driver_data_fw_define_flash_reload_en);
+	WORD_REG(reg_data->driver_op.data_fw_define_rxnum_txnum_maxpt_sorting,
+		 driver_data_fw_define_rxnum_txnum_maxpt_sorting);
+	WORD_REG(reg_data->driver_op.data_fw_define_rxnum_txnum_maxpt_normal,
+		 driver_data_fw_define_rxnum_txnum_maxpt_normal);
+/* CORE_DRIVER -end- */
+	WORD_REG(reg_data->zf_op.data_dis_flash_reload, zf_data_dis_flash_reload);
+	WORD_REG(reg_data->zf_op.addr_system_reset, zf_addr_system_reset);
+	BYTE_REG(reg_data->zf_op.data_system_reset, zf_data_system_reset);
+	WORD_REG(reg_data->zf_op.data_sram_start_addr, zf_data_sram_start_addr);
+	WORD_REG(reg_data->zf_op.data_cfg_info, zf_data_cfg_info);
+	WORD_REG(reg_data->zf_op.data_fw_cfg_1, zf_data_fw_cfg_1);
+	WORD_REG(reg_data->zf_op.data_fw_cfg_2, zf_data_fw_cfg_2);
+	WORD_REG(reg_data->zf_op.data_fw_cfg_3, zf_data_fw_cfg_3);
+	WORD_REG(reg_data->zf_op.data_adc_cfg_1, zf_data_adc_cfg_1);
+	WORD_REG(reg_data->zf_op.data_adc_cfg_2, zf_data_adc_cfg_2);
+	WORD_REG(reg_data->zf_op.data_adc_cfg_3, zf_data_adc_cfg_3);
+	WORD_REG(reg_data->zf_op.data_map_table, zf_data_map_table);
+	WORD_REG(reg_data->zf_op.addr_sts_chk, zf_addr_sts_chk);
+	BYTE_REG(reg_data->zf_op.data_activ_sts, zf_data_activ_sts);
+	WORD_REG(reg_data->zf_op.addr_activ_relod, zf_addr_activ_relod);
+	BYTE_REG(reg_data->zf_op.data_activ_in, zf_data_activ_in);
+}
+
+/* CORE_INIT */
+/* init start */
+void himax_ic_fp_init(void)
+{
+/* CORE_IC */
+	g_core_fp.fp_burst_enable = himax_mcu_burst_enable;
+	g_core_fp.fp_register_read = himax_mcu_register_read;
+	g_core_fp.fp_reg_read = himax_mcu_reg_read;
+	/*
+	 * g_core_fp.fp_flash_write_burst = himax_mcu_flash_write_burst;
+	 */
+	/*
+	 * g_core_fp.fp_flash_write_burst_length =
+	 *	himax_mcu_flash_write_burst_length;
+	 */
+	g_core_fp.fp_register_write = himax_mcu_register_write;
+	g_core_fp.fp_reg_write = himax_mcu_reg_write;
+	g_core_fp.fp_interface_on = himax_mcu_interface_on;
+	g_core_fp.fp_sense_on = himax_mcu_sense_on;
+	g_core_fp.fp_sense_off = himax_mcu_sense_off;
+	g_core_fp.fp_wait_wip = himax_mcu_wait_wip;
+	g_core_fp.fp_init_psl = himax_mcu_init_psl;
+	g_core_fp.fp_resume_ic_action = himax_mcu_resume_ic_action;
+	g_core_fp.fp_suspend_ic_action = himax_mcu_suspend_ic_action;
+	g_core_fp.fp_power_on_init = himax_mcu_power_on_init;
+/* CORE_IC */
+/* CORE_FW */
+	g_core_fp.fp_system_reset = himax_mcu_system_reset;
+	g_core_fp.fp_calculate_crc_with_ap = himax_mcu_calculate_crc_with_ap;
+	g_core_fp.fp_check_crc = himax_mcu_check_crc;
+	g_core_fp.fp_set_reload_cmd = himax_mcu_set_reload_cmd;
+	g_core_fp.fp_program_reload = himax_mcu_program_reload;
+	g_core_fp.fp_usb_detect_set = himax_mcu_usb_detect_set;
+	g_core_fp.fp_diag_register_set = himax_mcu_diag_register_set;
+	g_core_fp.fp_diag_register_get = himax_mcu_diag_register_get;
+	g_core_fp.fp_idle_mode = himax_mcu_idle_mode;
+	g_core_fp.fp_reload_disable = himax_mcu_reload_disable;
+	g_core_fp.fp_read_ic_trigger_type = himax_mcu_read_ic_trigger_type;
+	g_core_fp.fp_read_FW_ver = himax_mcu_read_FW_ver;
+	g_core_fp.fp_read_event_stack = himax_mcu_read_event_stack;
+	g_core_fp.fp_return_event_stack = himax_mcu_return_event_stack;
+	g_core_fp.fp_calculate_checksum = himax_mcu_calculate_checksum;
+	g_core_fp.fp_read_FW_status = himax_mcu_read_FW_status;
+	g_core_fp.fp_irq_switch = himax_mcu_irq_switch;
+	g_core_fp.fp_assign_sorting_mode = himax_mcu_assign_sorting_mode;
+	g_core_fp.fp_check_sorting_mode = himax_mcu_check_sorting_mode;
+	g_core_fp.fp_read_DD_status = himax_mcu_read_DD_status;
+	g_core_fp.fp_clr_fw_reord_dd_sts = hx_clr_fw_reord_dd_sts;
+	g_core_fp.fp_ap_notify_fw_sus = hx_ap_notify_fw_sus;
+/* CORE_FW */
+/* CORE_FLASH */
+	g_core_fp.fp_chip_erase = himax_mcu_chip_erase;
+	g_core_fp.fp_block_erase = himax_mcu_block_erase;
+	g_core_fp.fp_sector_erase = himax_mcu_sector_erase;
+	g_core_fp.fp_flash_programming = himax_mcu_flash_programming;
+	g_core_fp.fp_flash_page_write = himax_mcu_flash_page_write;
+	g_core_fp.fp_fts_ctpm_fw_upgrade_with_sys_fs_32k =
+			himax_mcu_fts_ctpm_fw_upgrade_with_sys_fs_32k;
+	g_core_fp.fp_fts_ctpm_fw_upgrade_with_sys_fs_60k =
+			himax_mcu_fts_ctpm_fw_upgrade_with_sys_fs_60k;
+	g_core_fp.fp_fts_ctpm_fw_upgrade_with_sys_fs_64k =
+			himax_mcu_fts_ctpm_fw_upgrade_with_sys_fs_64k;
+	g_core_fp.fp_fts_ctpm_fw_upgrade_with_sys_fs_124k =
+			himax_mcu_fts_ctpm_fw_upgrade_with_sys_fs_124k;
+	g_core_fp.fp_fts_ctpm_fw_upgrade_with_sys_fs_128k =
+			himax_mcu_fts_ctpm_fw_upgrade_with_sys_fs_128k;
+	g_core_fp.fp_fts_ctpm_fw_upgrade_with_sys_fs_255k =
+			himax_mcu_fts_ctpm_fw_upgrade_with_sys_fs_255k;
+	g_core_fp.fp_flash_dump_func = himax_mcu_flash_dump_func;
+	g_core_fp.fp_flash_lastdata_check = himax_mcu_flash_lastdata_check;
+	g_core_fp.fp_bin_desc_get = hx_mcu_bin_desc_get;
+	g_core_fp.fp_diff_overlay_flash = hx_mcu_diff_overlay_flash;
+/* CORE_FLASH */
+/* CORE_SRAM */
+	g_core_fp.fp_sram_write = himax_mcu_sram_write;
+	g_core_fp.fp_sram_verify = himax_mcu_sram_verify;
+	g_core_fp.fp_get_DSRAM_data = himax_mcu_get_DSRAM_data;
+/* CORE_SRAM */
+/* CORE_DRIVER */
+	g_core_fp.fp_chip_init = himax_mcu_init_ic;
+	g_core_fp.fp_pin_reset = himax_mcu_pin_reset;
+	g_core_fp.fp_ic_reset = himax_mcu_ic_reset;
+	g_core_fp.fp_tp_info_check = himax_mcu_tp_info_check;
+	g_core_fp.fp_touch_information = himax_mcu_touch_information;
+	g_core_fp.fp_calc_touch_data_size = himax_mcu_calc_touch_data_size;
+	g_core_fp.fp_get_touch_data_size = himax_mcu_get_touch_data_size;
+	g_core_fp.fp_hand_shaking = himax_mcu_hand_shaking;
+	g_core_fp.fp_determin_diag_rawdata = himax_mcu_determin_diag_rawdata;
+	g_core_fp.fp_determin_diag_storage = himax_mcu_determin_diag_storage;
+	g_core_fp.fp_cal_data_len = himax_mcu_cal_data_len;
+	g_core_fp.fp_diag_check_sum = himax_mcu_diag_check_sum;
+	g_core_fp.fp_ic_excp_recovery = himax_mcu_ic_excp_recovery;
+	g_core_fp.fp_excp_ic_reset = himax_mcu_excp_ic_reset;
+	g_core_fp.fp_resend_cmd_func = himax_mcu_resend_cmd_func;
+/* CORE_DRIVER */
+	g_core_fp.fp_turn_on_mp_func = hx_turn_on_mp_func;
+	g_core_fp.fp_reload_disable = hx_dis_rload_0f;
+	g_core_fp.fp_clean_sram_0f = himax_mcu_clean_sram_0f;
+	g_core_fp.fp_write_sram_0f = himax_mcu_write_sram_0f;
+	g_core_fp.fp_write_sram_0f_crc = himax_sram_write_crc_check;
+	g_core_fp.fp_firmware_update_0f = himax_mcu_firmware_update_0f;
+	g_core_fp.fp_0f_op_file_dirly = hx_0f_op_file_dirly;
+	g_core_fp.fp_0f_excp_check = himax_mcu_0f_excp_check;
+	g_core_fp.fp_read_sram_0f = himax_mcu_read_sram_0f;
+	g_core_fp.fp_read_all_sram = himax_mcu_read_all_sram;
+	g_core_fp.fp_firmware_read_0f = himax_mcu_firmware_read_0f;
+	g_core_fp.fp_suspend_proc = himax_suspend_proc;
+	g_core_fp.fp_resume_proc = himax_resume_proc;
+}