int ist30xx_set_cmcs_cmd(struct i2c_client *client, CMCS_INFO *cmcs)
{
	int ret;
	u32 val;

	val = (u32)(cmcs->cmd.base_screen | (cmcs->cmd.mode << 16));
	ret = ist30xx_write_cmd(client, cmcs->addr.base_screen, val);
	if (ret) return ret;
	tsp_verb("Baseline screen(0x%08x): 0x%08x\n", cmcs->addr.base_screen, val);

	val = (u32)cmcs->cmd.base_key;
	ret = ist30xx_write_cmd(client, cmcs->addr.base_key, val);
	if (ret) return ret;
	tsp_verb("Baseline key(0x%08x): 0x%08x\n", cmcs->addr.base_key, val);

	val = cmcs->cmd.start_cp_cm | (cmcs->cmd.start_cp_cs << 16);
	ret = ist30xx_write_cmd(client, cmcs->addr.start_cp, val);
	if (ret) return ret;
	tsp_verb("StartCP(0x%08x): 0x%08x\n", cmcs->addr.start_cp, val);

	val = cmcs->cmd.vcmp_cm | (cmcs->cmd.vcmp_cs << 16);
	ret = ist30xx_write_cmd(client, cmcs->addr.vcmp, val);
	if (ret) return ret;
	tsp_verb("VCMP(0x%08x): 0x%08x\n", cmcs->addr.vcmp, val);

	return 0;
}
/* sysfs: /sys/class/touch/tracking/track_frame */
ssize_t ist30xx_track_frame_show(struct device *dev, struct device_attribute *attr,
				 char *buf)
{
	int i, buf_cnt = 0;
	u32 track_cnt = MAX_TRACKING_COUNT;
	u32 track;
	char msg[10];

	mutex_lock(&ist30xx_mutex);

	buf[0] = '\0';

	if (track_cnt > ist30xx_get_track_cnt())
		track_cnt = ist30xx_get_track_cnt();

	track_cnt /= sizeof(track);

	tsp_verb("num: %d of %d\n", track_cnt, ist30xx_get_track_cnt());

	for (i = 0; i < track_cnt; i++) {
		ist30xx_get_track(&track, 1);

		tsp_verb("%08X\n", track);

		buf_cnt += sprintf(msg, "%08x", track);
		strcat(buf, msg);
	}

	mutex_unlock(&ist30xx_mutex);

	return buf_cnt;
}
int ist30xx_check_valid_ch(struct ist30xx_data *data, int ch_tx, int ch_rx)
{
	TKEY_INFO *tkey = &data->tkey_info;
	TSP_INFO *tsp = &data->tsp_info;

	if (unlikely((ch_tx > tsp->ch_num.tx) || (ch_rx > tsp->ch_num.rx)))
		return 0;

	if (tkey->enable) {
		if (tkey->axis_rx) {
			tsp_verb("tx: %d, rx: %d\n", ch_tx, ch_rx);
			if (ch_rx == tsp->ch_num.rx - 1) {
				tsp_verb("ch_tx: %d\n", ch_tx);
				if ((ch_tx == tkey->ch_num[0]) || (ch_tx == tkey->ch_num[1]) ||
				    (ch_tx == tkey->ch_num[2]) || (ch_tx == tkey->ch_num[3]) ||
				    (ch_tx == tkey->ch_num[4]))
					return TSP_CH_KEY;
				else
					return 0;
			}
		} else {
			if (ch_tx == tsp->ch_num.tx - 1) {
				if ((ch_rx == tkey->ch_num[0]) || (ch_rx == tkey->ch_num[1]) ||
				    (ch_rx == tkey->ch_num[2]) || (ch_rx == tkey->ch_num[3]) ||
				    (ch_rx == tkey->ch_num[4]))
					return TSP_CH_KEY;
				else
					return 0;
			}
		}
	}

	return TSP_CH_SCREEN;
}
int ist30xx_set_cmcs_sensor(struct i2c_client *client, CMCS_INFO *cmcs,
			    u32 *buf32)
{
	int i, ret;
	int len;
	u32 waddr;
	u32 *tmp32;

	tsp_verb("%08x %08x %08x %08x\n", buf32[0], buf32[1], buf32[2], buf32[3]);

	waddr = cmcs->addr.sensor1;
	len = cmcs->sensor1_size / IST30XX_DATA_LEN;

	for (i = 0; i < len; i++) {
		ret = ist30xx_write_cmd(client, waddr, *buf32++);
		if (ret)
			return ret;

		waddr += IST30XX_DATA_LEN;
	}

	tmp32 = buf32;
	tsp_verb("%08x %08x %08x %08x\n", tmp32[0], tmp32[1], tmp32[2], tmp32[3]);

	waddr = cmcs->addr.sensor2;
	len = (cmcs->sensor2_size - 0x10) / IST30XX_DATA_LEN;

	for (i = 0; i < len; i++) {
		ret = ist30xx_write_cmd(client, waddr, *buf32++);
		if (ret)
			return ret;

		waddr += IST30XX_DATA_LEN;
	}
	buf32 += (0x10 / IST30XX_DATA_LEN);

	tmp32 = buf32;
	tsp_verb("%08x %08x %08x %08x\n", tmp32[0], tmp32[1], tmp32[2], tmp32[3]);

	waddr = cmcs->addr.sensor3;
	len = cmcs->sensor3_size / IST30XX_DATA_LEN;

	for (i = 0; i < len; i++) {
		ret = ist30xx_write_cmd(client, waddr, *buf32++);
		if (ret)
			return ret;

		waddr += IST30XX_DATA_LEN;
	}

	return 0;
}
void timer_handler(unsigned long data)
{
	int event_ms;
	int curr_ms;

	if (get_event_mode) {
		if ((ts_data->status.power == 1) && (ts_data->status.update != 1)) {
			ktime_get_ts(&t_current);

			curr_ms = t_current.tv_sec * 1000 + t_current.tv_nsec / 1000000;
			event_ms = t_event.tv_sec * 1000 + t_event.tv_nsec / 1000000;

			tsp_verb("event_ms %d, current: %d\n", event_ms, curr_ms);

			if (ts_data->status.calib == 1) {
				if (curr_ms - event_ms >= 2000) {   // 2second
					ts_data->status.calib = 0;
					tsp_debug("calibration timeout over 3sec\n");
					schedule_delayed_work(&work_reset_check, 0);
					ktime_get_ts(&t_event);
				}
			}
#if IST30XX_NOISE_MODE
			else if (curr_ms - event_ms >= 5000) {  // 5second
				tsp_warn("idle timeout over 5sec\n");
				schedule_delayed_work(&work_reset_check, 0);
			}
#endif                  // IST30XX_NOISE_MODE
		}
	}

	mod_timer(&idle_timer, get_jiffies_64() + EVENT_TIMER_INTERVAL);
}
/* sysfs: /sys/class/touch/cmcs/info */
ssize_t ist30xx_cmcs_info_show(struct device *dev, struct device_attribute *attr,
			       char *buf)
{
	int count;
	char msg[128];

	CMCS_INFO *cmcs = (CMCS_INFO *)&ts_cmcs->cmcs;

	if (cmcs_ready == CMCS_NOT_READY)
		return sprintf(buf, "CMCS test is not work!!\n");

	if (cmcs == NULL)
		return sprintf(buf, "Unknown cmcs bin\n");

	/* Mode */
	count = sprintf(msg, "%d ", cmcs->cmd.mode);
	strcat(buf, msg);

	/* Channel */
	count += sprintf(msg, "%d %d %d %d %d %d %d %d ",
			 cmcs->ch.tx_num, cmcs->ch.rx_num, cmcs->ch.key_rx, cmcs->ch.key1,
			 cmcs->ch.key2, cmcs->ch.key3, cmcs->ch.key4, cmcs->ch.key5);
	strcat(buf, msg);

	/* Slope */
	count += sprintf(msg, "%d %d %d %d %d %d",
			 cmcs->slope.x_min, cmcs->slope.x_max,
			 cmcs->slope.y_min, cmcs->slope.y_max,
			 cmcs->slope.key_min, cmcs->slope.key_max);
	strcat(buf, msg);

	/* CM */
	count += sprintf(msg, "%d %d %d %d ",
			 cmcs->spec_cm.screen_min, cmcs->spec_cm.screen_max,
			 cmcs->spec_cm.key_min, cmcs->spec_cm.key_max);
	strcat(buf, msg);

	/* CS0 */
	count += sprintf(msg, "%d %d %d %d ",
			 cmcs->spec_cs0.screen_min, cmcs->spec_cs0.screen_max,
			 cmcs->spec_cs0.key_min, cmcs->spec_cs0.key_max);
	strcat(buf, msg);

	/* CS1 */
	count += sprintf(msg, "%d %d %d %d ",
			 cmcs->spec_cs1.screen_min, cmcs->spec_cs1.screen_max,
			 cmcs->spec_cs1.key_min, cmcs->spec_cs1.key_max);
	strcat(buf, msg);

	/* CR */
	count += sprintf(msg, "%d %d %d %d ",
			 cmcs->spec_cr.screen_min, cmcs->spec_cr.screen_max,
			 cmcs->spec_cr.key_min, cmcs->spec_cr.key_max);
	strcat(buf, msg);

	tsp_verb("%s\n", buf);

	return count;
}
/* sysfs: /sys/class/touch/tracking/track_cnt */
ssize_t ist30xx_track_cnt_show(struct device *dev, struct device_attribute *attr,
			       char *buf)
{
	u32 val = (u32)ist30xx_get_track_cnt();

	tsp_verb("tracking cnt: %d\n", val);

	return sprintf(buf, "%08x", val);
}
/* sysfs: /sys/class/touch/cmcs/cs1 */
ssize_t ist30xx_cs1_show(struct device *dev, struct device_attribute *attr,
			 char *buf)
{
	CMCS_INFO *cmcs = (CMCS_INFO *)&ts_cmcs->cmcs;

	if (cmcs_ready == CMCS_NOT_READY)
		return sprintf(buf, "CMCS test is not work!!\n");

	if ((cmcs->cmd.mode) && !(cmcs->cmd.mode & FLAG_ENABLE_CS))
		return 0;

	tsp_verb("CS1 (%d * %d)\n", cmcs->ch.tx_num, cmcs->ch.rx_num);

	return print_cmcs(ts_cmcs_buf->cs1, buf);
}
/* sysfs: /sys/class/touch/cmcs/cs0 */
ssize_t ist30xx_cs0_show(struct device *dev, struct device_attribute *attr,
			 char *buf)
{
	struct ist30xx_data *data = dev_get_drvdata(dev);
	CMCS_INFO *cmcs = (CMCS_INFO *)&data->cmcs->cmcs;

	if (data->cmcs_ready == CMCS_NOT_READY)
		return sprintf(buf, "CMCS test is not work!!\n");

	if ((cmcs->cmd.mode) && !(cmcs->cmd.mode & FLAG_ENABLE_CS))
		return 0;

	tsp_verb("CS0 (%d * %d)\n", cmcs->ch.tx_num, cmcs->ch.rx_num);

	return print_cmcs(data, data->cmcs_buf->cs0, buf);
}
int ist30xx_parse_cmcs_bin(const u8 *buf, const u32 size)
{
	int ret = -EPERM;
	CMCS_INFO *cmcs = (CMCS_INFO *)&ts_cmcs->cmcs;

	memcpy(ts_cmcs->magic1, buf, sizeof(ts_cmcs->magic1));
	memcpy(ts_cmcs->magic2, &buf[size - sizeof(ts_cmcs->magic2)],
	       sizeof(ts_cmcs->magic2));
	memcpy(cmcs, &buf[sizeof(ts_cmcs->magic1)], sizeof(ts_cmcs->cmcs));

	if (!strncmp(ts_cmcs->magic1, IST30XX_CMCS_MAGIC, sizeof(ts_cmcs->magic1))
	    && !strncmp(ts_cmcs->magic2, IST30XX_CMCS_MAGIC, sizeof(ts_cmcs->magic2))) {
		int idx;

		idx = sizeof(ts_cmcs->magic1) + sizeof(ts_cmcs->cmcs);
		ts_cmcs->buf_cmcs = (u8 *)&buf[idx];

		idx += cmcs->cmd.cmcs_size;
		ts_cmcs->buf_sensor = (u32 *)&buf[idx];

		idx += (cmcs->sensor1_size + cmcs->sensor2_size + cmcs->sensor3_size);
		ts_cmcs->buf_node = (u16 *)&buf[idx];

		ret = 0;
	}

	tsp_verb("Magic1: %s, Magic2: %s\n", ts_cmcs->magic1, ts_cmcs->magic2);
	tsp_verb(" mode: 0x%x, base(screen: %d, key: %d)\n",
		 cmcs->cmd.mode, cmcs->cmd.base_screen, cmcs->cmd.base_key);
	tsp_verb(" start_cp (cm: %d, cs: %d), vcmp (cm: %d, cs: %d)\n",
		 cmcs->cmd.start_cp_cm, cmcs->cmd.start_cp_cs,
		 cmcs->cmd.vcmp_cm, cmcs->cmd.vcmp_cs);
	tsp_verb(" timeout: %d\n", cmcs->timeout);
	tsp_verb(" baseline scrn: 0x%08x, key: 0x%08x\n",
		 cmcs->addr.base_screen, cmcs->addr.base_key);
	tsp_verb(" start_cp: 0x%08x, vcmp: 0x%08x\n",
		 cmcs->addr.start_cp, cmcs->addr.vcmp);
	tsp_verb(" sensor 1: 0x%08x, 2: 0x%08x, 3: 0x%08x\n",
		 cmcs->addr.sensor1, cmcs->addr.sensor2, cmcs->addr.sensor3);
	tsp_verb(" tx: %d, rx:%d, key rx: %d, num(%d, %d, %d, %d, %d)\n",
		 cmcs->ch.tx_num, cmcs->ch.rx_num, cmcs->ch.key_rx, cmcs->ch.key1,
		 cmcs->ch.key2, cmcs->ch.key3, cmcs->ch.key4, cmcs->ch.key5);
	tsp_verb(" cr: screen(%4d, %4d), key(%4d, %4d)\n",
		 cmcs->spec_cr.screen_min, cmcs->spec_cr.screen_max,
		 cmcs->spec_cr.key_min, cmcs->spec_cr.key_max);
	tsp_verb(" cm: screen(%4d, %4d), key(%4d, %4d)\n",
		 cmcs->spec_cm.screen_min, cmcs->spec_cm.screen_max,
		 cmcs->spec_cm.key_min, cmcs->spec_cm.key_max);
	tsp_verb(" cs0: screen(%4d, %4d), key(%4d, %4d)\n",
		 cmcs->spec_cs0.screen_min, cmcs->spec_cs0.screen_max,
		 cmcs->spec_cs0.key_min, cmcs->spec_cs0.key_max);
	tsp_verb(" cs1: screen(%4d, %4d), key(%4d, %4d)\n",
		 cmcs->spec_cs1.screen_min, cmcs->spec_cs1.screen_max,
		 cmcs->spec_cs1.key_min, cmcs->spec_cs1.key_max);
	tsp_verb(" slope - x(%d, %d), y(%d, %d), key(%d, %d)\n",
		 cmcs->slope.x_min, cmcs->slope.x_max,
		 cmcs->slope.y_min, cmcs->slope.y_max,
		 cmcs->slope.key_min, cmcs->slope.key_max);
	tsp_verb(" size - cmcs(%d), sensor(%d, %d, %d)\n",
		 cmcs->cmd.cmcs_size, cmcs->sensor1_size,
		 cmcs->sensor2_size, cmcs->sensor3_size);
	tsp_verb(" checksum - cmcs: 0x%08x, sensor: 0x%08x\n",
		 cmcs->cmcs_chksum, cmcs->sensor_chksum);
	tsp_verb(" cmcs: %x, %x, %x, %x\n", ts_cmcs->buf_cmcs[0],
		 ts_cmcs->buf_cmcs[1], ts_cmcs->buf_cmcs[2], ts_cmcs->buf_cmcs[3]);
	tsp_verb(" sensor: %x, %x, %x, %x\n",
		 ts_cmcs->buf_sensor[0], ts_cmcs->buf_sensor[1],
		 ts_cmcs->buf_sensor[2], ts_cmcs->buf_sensor[3]);
	tsp_verb(" node: %x, %x, %x, %x\n",
		 ts_cmcs->buf_node[0], ts_cmcs->buf_node[1],
		 ts_cmcs->buf_node[2], ts_cmcs->buf_node[3]);

	return ret;
}
int ist30xx_cmcs_test(const u8 *buf, int size)
{
	int ret;
	int len;
	u32 chksum = 0;
	u32 *buf32;
	struct i2c_client *client = (struct i2c_client *)ts_data->client;
	CMCS_INFO *cmcs = (CMCS_INFO *)&ts_cmcs->cmcs;

	tsp_info("*** CM/CS test ***\n");
	tsp_info(" mode: 0x%x, baseline(screen: %d, key: %d)\n",
		 cmcs->cmd.mode, cmcs->cmd.base_screen, cmcs->cmd.base_key);
	tsp_info(" start_cp (cm: %d, cs: %d), vcmp (cm: %d, cs: %d)\n",
		 cmcs->cmd.start_cp_cm, cmcs->cmd.start_cp_cs,
		 cmcs->cmd.vcmp_cm, cmcs->cmd.vcmp_cs);

	ist30xx_disable_irq(ts_data);

	ist30xx_reset(false);

	ret = ist30xx_cmd_reg(client, CMD_ENTER_REG_ACCESS);
	cmcs_next_step(ret);

	/* Set sensor register */
	buf32 = ts_cmcs->buf_sensor;
	ret = ist30xx_set_cmcs_sensor(client, cmcs, buf32);
	cmcs_next_step(ret);

	/* Set command */
	ret = ist30xx_set_cmcs_cmd(client, cmcs);
	cmcs_next_step(ret);

	ret = ist30xx_cmd_reg(client, CMD_EXIT_REG_ACCESS);
	cmcs_next_step(ret);

	/* Load cmcs test code */
	ret = ist30xx_write_cmd(client, CMD_EXEC_MEM_CODE, 0);
	cmcs_next_step(ret);

	buf32 = (u32 *)ts_cmcs->buf_cmcs;
	len = cmcs->cmd.cmcs_size / IST30XX_DATA_LEN;
	tsp_verb("%08x %08x %08x %08x\n", buf32[0], buf32[1], buf32[2], buf32[3]);
	ret = ist30xx_write_buf(client, len, buf32, len);
	cmcs_next_step(ret);

	/* Check checksum */
	ret = ist30xx_read_cmd(client, CMD_DEFAULT, &chksum);
	cmcs_next_step(ret);
	if (chksum != IST30XX_CMCS_LOAD_END)
		goto end;
	tsp_info("CM/CS code ready!!\n");

	/* Check checksum */
	ret = ist30xx_read_cmd(client, CMD_DEFAULT, &chksum);
	cmcs_next_step(ret);
	tsp_info("CM/CS code chksum: %08x, %08x\n", chksum, cmcs->cmcs_chksum);

	ist30xx_enable_irq(ts_data);
	/* Wait CMCS test result */
	if (ist30xx_calib_wait() == 1)
		tsp_info("CM/CS test OK.\n");
	else
		tsp_info("CM/CS test fail.\n");
	ist30xx_disable_irq(ts_data);

	/* Read CM/CS data*/
	if (ENABLE_CM_MODE(cmcs->cmd.mode)) {
		/* Read CM data */
		memset(ts_cmcs_buf->cm, 0, sizeof(ts_cmcs_buf->cm));

		ret = ist30xx_get_cmcs_buf(client, cmcs, ts_cmcs_buf->cm);
		cmcs_next_step(ret);

		ret = ist30xx_apply_cmcs_slope(cmcs, ts_cmcs_buf);
	}

	if (ENABLE_CS_MODE(cmcs->cmd.mode)) {
		/* Read CS0 data */
		memset(ts_cmcs_buf->cs0, 0, sizeof(ts_cmcs_buf->cs0));
		memset(ts_cmcs_buf->cs1, 0, sizeof(ts_cmcs_buf->cs1));

		ret = ist30xx_get_cmcs_buf(client, cmcs, ts_cmcs_buf->cs0);
		cmcs_next_step(ret);

		/* Read CS1 data */
		ret = ist30xx_get_cmcs_buf(client, cmcs, ts_cmcs_buf->cs1);
		cmcs_next_step(ret);
	}

	ist30xx_reset(false);

	ist30xx_start(ts_data);

	cmcs_ready = CMCS_READY;

end:
	if (unlikely(ret)) {
		tsp_warn("CM/CS test Fail!, ret=%d\n", ret);
	} else if (unlikely(chksum != cmcs->cmcs_chksum)) {
		tsp_warn("Error CheckSum: %x(%x)\n", chksum, cmcs->cmcs_chksum);
		ret = -ENOEXEC;
	}

	ist30xx_enable_irq(ts_data);

	return ret;
}
int ist30xx_apply_cmcs_slope(CMCS_INFO *cmcs, CMCS_BUF *cmcs_buf)
{
	int i, j;
	int idx1, idx2;
	int ch_num = cmcs->ch.tx_num * cmcs->ch.rx_num;
	int width = cmcs->ch.rx_num;
	int height = cmcs->ch.tx_num;
	s16 *pcm = (s16 *)cmcs_buf->cm;
	s16 *pspec = (s16 *)cmcs_buf->spec;
	s16 *pslope0 = (s16 *)cmcs_buf->slope0;
	s16 *pslope1 = (s16 *)cmcs_buf->slope1;

	if (cmcs->ch.key_rx)
		width -= 1;
	else
		height -= 1;

	memset(cmcs_buf->slope0, 0, sizeof(cmcs_buf->slope0));
	memset(cmcs_buf->slope1, 0, sizeof(cmcs_buf->slope1));

	memcpy(cmcs_buf->spec, ts_cmcs->buf_node, (ch_num * sizeof(u16)));

	idx1 = 0;
#if CMCS_PARSING_DEBUG
	tsp_info("# Node specific\n");
	for (i = 0; i < cmcs->ch.tx_num; i++) {
		tsp_info(" ");
		for (j = 0; j < cmcs->ch.rx_num; j++)
			printk("%5d ", cmcs_buf->spec[idx1++]);
		printk("\n");
	}
#endif

	tsp_verb("# Apply slope0_x\n");
	for (i = 0; i < height; i++) {
		for (j = 0; j < width - 1; j++) {
			idx1 = (i * cmcs->ch.rx_num) + j;
			idx2 = idx1 + 1;

			pslope0[idx1] = (pcm[idx2] - pcm[idx1]);
			pslope0[idx1] += (pspec[idx1] - pspec[idx2]);
		}
	}

	tsp_verb("# Apply slope1_y\n");
	for (i = 0; i < height - 1; i++) {
		for (j = 0; j < width; j++) {
			idx1 = (i * cmcs->ch.rx_num) + j;
			idx2 = idx1 + cmcs->ch.rx_num;

			pslope1[idx1] = (pcm[idx2] - pcm[idx1]);
			pslope1[idx1] += (pspec[idx1] - pspec[idx2]);
		}
	}

#if CMCS_PARSING_DEBUG
	tsp_info("# slope0_x\n");
	for (i = 0; i < height; i++) {
		tsp_info(" ");
		for (j = 0; j < width; j++) {
			idx1 = (i * cmcs->ch.rx_num) + j;
			printk("%5d ", pslope0[idx1]);
		}
		printk("\n");
	}

	tsp_info("# slope1_y\n");
	for (i = 0; i < height; i++) {
		tsp_info(" ");
		for (j = 0; j < width; j++) {
			idx1 = (i * cmcs->ch.rx_num) + j;
			printk("%5d ", pslope1[idx1]);
		}
		printk("\n");
	}
#endif

	return 0;
}
static irqreturn_t ist30xx_irq_thread(int irq, void *ptr)
{
	int i, ret;
	int key_cnt, finger_cnt, read_cnt;
	struct ist30xx_data *data = ptr;
	u32 msg[IST30XX_MAX_MT_FINGERS];
	bool unknown_idle = false;

#if IST30XX_TRACKING_MODE
	u32 ms;
#endif

	if (!data->irq_enabled)
		return IRQ_HANDLED;

	memset(msg, 0, sizeof(msg));

	ret = ist30xx_get_position(data->client, msg, 1);
	if (ret)
		goto irq_err;

	tsp_verb("intr msg: 0x%08x\n", *msg);

	if (msg[0] == 0)
		return IRQ_HANDLED;

#if IST30XX_EVENT_MODE
	if ((data->status.update != 1) && (data->status.calib != 1))
		ktime_get_ts(&t_event);
#endif

#if IST30XX_TRACKING_MODE
	ms = t_event.tv_sec * 1000 + t_event.tv_nsec / 1000000;
    ist30xx_put_track(ms, msg[0]);
#endif

#if IST30XX_NOISE_MODE
	if (get_event_mode) {
		if ((msg[0] & 0xFFFF0000) == IST30XX_IDLE_STATUS) {
			if (msg[0] & IDLE_ALGORITHM_MODE)
				return IRQ_HANDLED;

			for (i = 0; i < IST30XX_MAX_MT_FINGERS; i++) {
				if (data->prev_fingers[i].bit_field.id == 0)
					continue;

				if (data->prev_fingers[i].bit_field.udmg & PRESS_MSG_MASK) {
					tsp_warn("prev_fingers: %08x\n",
						 data->prev_fingers[i].full_field);
					release_finger(&data->prev_fingers[i]);
					unknown_idle = true;
				}
			}

			for (i = 0; i < data->num_keys; i++) {
				if (data->prev_keys[i].bit_field.id == 0)
					continue;

				if (data->prev_keys[i].bit_field.w == PRESS_MSG_KEY) {
					tsp_warn("prev_keys: %08x\n",
						 data->prev_keys[i].full_field);
					release_key(&data->prev_keys[i], RELEASE_KEY);
					unknown_idle = true;
				}
			}

			if (unknown_idle) {
				schedule_delayed_work(&work_reset_check, 0);
				tsp_warn("Find unknown pressure\n");
			}

			return IRQ_HANDLED;
		}
	}
#endif  // IST30XX_NOISE_MODE

	if ((msg[0] & CALIB_MSG_MASK) == CALIB_MSG_VALID) {
		data->status.calib_msg = msg[0];
		tsp_info("calib status: 0x%08x\n", data->status.calib_msg);
		return IRQ_HANDLED;
	}

	for (i = 0; i < IST30XX_MAX_MT_FINGERS; i++)
		data->fingers[i].full_field = 0;

	key_cnt = 0;
	finger_cnt = 1;
	read_cnt = 1;
	data->fingers[0].full_field = msg[0];

	if (data->fingers[0].bit_field.udmg & MULTI_MSG_MASK) {
		key_cnt = data->fingers[0].bit_field.x;
		finger_cnt = data->fingers[0].bit_field.y;
		read_cnt = finger_cnt + key_cnt;

		if (finger_cnt > ist30xx_tsp_info.finger_num ||
		    key_cnt > ist30xx_tkey_info.key_num) {
			tsp_warn("Invalid touch count - finger: %d(%d), key: %d(%d)\n",
				 finger_cnt, ist30xx_tsp_info.finger_num,
				 key_cnt, ist30xx_tkey_info.key_num);
			goto irq_err;
		}

#if I2C_BURST_MODE
		ret = ist30xx_get_position(data->client, msg, read_cnt);
		if (ret)
			goto irq_err;

		for (i = 0; i < read_cnt; i++)
			data->fingers[i].full_field = msg[i];
#else
		for (i = 0; i < read_cnt; i++) {
			ret = ist30xx_get_position(data->client, &msg[i], 1);
			if (ret)
				goto irq_err;

			data->fingers[i].full_field = msg[i];
		}
#endif          // I2C_BURST_MODE

		for (i = 0; i < read_cnt; i++)
			tsp_verb("intr msg[%d]: 0x%08x\n", i, msg[i]);

#if IST30XX_TRACKING_MODE
		for (i = 0; i < read_cnt; i++)
			ist30xx_put_track(ms, msg[i]);
#endif
	}

	if (check_report_data(data, finger_cnt, key_cnt))
		return IRQ_HANDLED;

	if (read_cnt > 0)
		report_input_data(data, finger_cnt, key_cnt);

	return IRQ_HANDLED;

irq_err:
	tsp_err("intr msg[0]: 0x%08x, ret: %d\n", msg[0], ret);
	ist30xx_request_reset();
	return IRQ_HANDLED;
}