/* Himax Android Driver Sample Code for Himax chipset
*
* Copyright (C) 2015 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 "himax_debug.h"
#include "himax_ic.h"

/*struct himax_debug_data* debug_data;*/

#ifdef HX_TP_PROC_DIAG
#ifdef HX_TP_PROC_2T2R
int	HX_RX_NUM_2;
int	HX_TX_NUM_2;
#endif
int	touch_monitor_stop_flag;
int	touch_monitor_stop_limit	= 5;
uint8_t	g_diag_arr_num;
#endif

#ifdef HX_ESD_WORKAROUND
u8 HX_ESD_RESET_ACTIVATE;
#endif

#ifdef HX_SMART_WAKEUP
bool FAKE_POWER_KEY_SEND;
#endif

/*========================================================

Segment : Himax PROC Debug Function

==========================================================*/
#if defined(CONFIG_TOUCHSCREEN_HIMAX_DEBUG)

static ssize_t himax_vendor_read(struct file *file, char *buf,
	size_t len, loff_t *pos)
{
	ssize_t ret = 0;
	char *temp_buf;

	if (!HX_PROC_SEND_FLAG) {
		temp_buf = kzalloc(len, GFP_KERNEL);
		ret += snprintf(temp_buf, len,
		"%s_FW:%#x_CFG:%#x_SensorId:%#x\n",
		HIMAX_common_NAME, ic_data->vendor_fw_ver,
		ic_data->vendor_config_ver, ic_data->vendor_sensor_id);

		HX_PROC_SEND_FLAG = 1;

		if (copy_to_user(buf, temp_buf, len))
			I("%s,here:%d\n", __func__, __LINE__);

		kfree(temp_buf);
	} else
		HX_PROC_SEND_FLAG = 0;

	return ret;
}

const struct file_operations himax_proc_vendor_ops = {
	.owner = THIS_MODULE,
	.read = himax_vendor_read,
};

static ssize_t himax_attn_read(struct file *file, char *buf,
	size_t len, loff_t *pos)
{
	ssize_t ret = 0;
	struct himax_ts_data *ts_data;
	char *temp_buf;

	ts_data = private_ts;

	if (!HX_PROC_SEND_FLAG) {
		temp_buf = kzalloc(len, GFP_KERNEL);
		ret += snprintf(temp_buf, len, "attn = %x\n",
		himax_int_gpio_read(ts_data->pdata->gpio_irq));

		if (copy_to_user(buf, temp_buf, len))
			I("%s,here:%d\n", __func__, __LINE__);

		kfree(temp_buf);
		HX_PROC_SEND_FLAG = 1;
	} else
		HX_PROC_SEND_FLAG = 0;

	return ret;
}

const struct file_operations himax_proc_attn_ops = {
	.owner = THIS_MODULE,
	.read = himax_attn_read,
};

static ssize_t himax_int_en_read(struct file *file, char *buf,
	size_t len, loff_t *pos)
{
	struct himax_ts_data *ts = private_ts;
	size_t ret = 0;
	char *temp_buf;

	if (!HX_PROC_SEND_FLAG) {
		temp_buf = kzalloc(len, GFP_KERNEL);
		ret += snprintf(temp_buf, len-1, "%d ", ts->irq_enabled);
		ret += snprintf(temp_buf, 1, "\n");

		if (copy_to_user(buf, temp_buf, len))
			I("%s,here:%d\n", __func__, __LINE__);

		kfree(temp_buf);
		HX_PROC_SEND_FLAG = 1;
	} else
		HX_PROC_SEND_FLAG = 0;
	return ret;
}

static ssize_t himax_int_en_write(struct file *file, const char *buff,
	size_t len, loff_t *pos)
{
	struct himax_ts_data *ts = private_ts;
	char buf_tmp[12] = {0};
	int value, ret = 0;

	if (len >= 12) {
		I("%s: no command exceeds 12 chars.\n", __func__);
		return -EFAULT;
	}
	if (copy_from_user(buf_tmp, buff, len))
		return -EFAULT;

	if (buf_tmp[0] == '0')
		value = false;
	else if (buf_tmp[0] == '1')
		value = true;
	else
		return -EINVAL;

	if (value) {
		if (ic_data->HX_INT_IS_EDGE) {
#ifdef MTK
#ifdef CONFIG_OF_TOUCH
			himax_int_enable(ts->client->irq, 1);
#else
			/*mt_eint_set_sens(CUST_EINT_TOUCH_PANEL_NUM,
			CUST_EINT_TOUCH_PANEL_TYPE);
			mt_eint_set_hw_debounce(CUST_EINT_TOUCH_PANEL_NUM,
			CUST_EINT_TOUCH_PANEL_DEBOUNCE_CN);*/
			mt_eint_registration(ts->client->irq,
			EINTF_TRIGGER_FALLING, tpd_eint_interrupt_handler, 1);
#endif
#endif
#ifdef QCT
			ret = request_threaded_irq(ts->client->irq,
					NULL, himax_ts_thread,
					IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
					ts->client->name, ts);
#endif
		} else {
#ifdef MTK
#ifdef CONFIG_OF_TOUCH
			himax_int_enable(ts->client->irq, 1);
#else
			/*mt_eint_set_sens(CUST_EINT_TOUCH_PANEL_NUM,
			CUST_EINT_TOUCH_PANEL_TYPE);
			mt_eint_set_hw_debounce(CUST_EINT_TOUCH_PANEL_NUM,
			CUST_EINT_TOUCH_PANEL_DEBOUNCE_CN);*/
			mt_eint_registration(ts->client->irq,
			EINTF_TRIGGER_LOW, tpd_eint_interrupt_handler, 1);
#endif
#endif
#ifdef QCT
			ret = request_threaded_irq(ts->client->irq,
					NULL, himax_ts_thread,
					IRQF_TRIGGER_LOW | IRQF_ONESHOT,
					ts->client->name, ts);
#endif
		}
		if (ret == 0) {
			ts->irq_enabled = 1;
			irq_enable_count = 1;
		}
	} else {
		himax_int_enable(ts->client->irq, 0);
		free_irq(ts->client->irq, ts);
		ts->irq_enabled = 0;
	}

	return len;
}

const struct file_operations himax_proc_int_en_ops = {
	.owner = THIS_MODULE,
	.read = himax_int_en_read,
	.write = himax_int_en_write,
};

static ssize_t himax_layout_read(struct file *file, char *buf,
	size_t len, loff_t *pos)
{
	struct himax_ts_data *ts = private_ts;
	size_t ret = 0;
	char *temp_buf;

	if (!HX_PROC_SEND_FLAG) {
		temp_buf = kzalloc(len, GFP_KERNEL);
		ret += snprintf(temp_buf, len, "%d ", ts->pdata->abs_x_min);
		ret += snprintf(temp_buf, len, "%d ", ts->pdata->abs_x_max);
		ret += snprintf(temp_buf, len, "%d ", ts->pdata->abs_y_min);
		ret += snprintf(temp_buf, len, "%d ", ts->pdata->abs_y_max);
		ret += snprintf(temp_buf, len, "\n");

		if (copy_to_user(buf, temp_buf, len))
			I("%s,here:%d\n", __func__, __LINE__);

		kfree(temp_buf);
		HX_PROC_SEND_FLAG = 1;
	} else
		HX_PROC_SEND_FLAG = 0;

	return ret;
}

static ssize_t himax_layout_write(struct file *file, const char *buff,
	size_t len, loff_t *pos)
{
	struct himax_ts_data *ts = private_ts;
	char buf_tmp[5];
	int i = 0, j = 0, k = 0, ret;
	unsigned long value;
	int layout[4] = {0};
	char buf[80] = {0};

	if (len >= 80) {
		I("%s: no command exceeds 80 chars.\n", __func__);
		return -EFAULT;
	}
	if (copy_from_user(buf, buff, len))
		return -EFAULT;

	for (i = 0 ; i < 20 ; i++) {
		if (buf[i] == ',' || buf[i] == '\n') {
			memset(buf_tmp, 0x0, sizeof(buf_tmp));
			if (i - j <= 5)
				memcpy(buf_tmp, buf + j, i - j);
			else {
				I("buffer size is over 5 char\n");
				return len;
			}
			j = i + 1;
			if (k < 4) {
				ret = kstrtoul(buf_tmp, 10, &value);
				layout[k++] = value;
			}
		}
	}
	if (k == 4) {
		ts->pdata->abs_x_min = layout[0];
		ts->pdata->abs_x_max = layout[1];
		ts->pdata->abs_y_min = layout[2];
		ts->pdata->abs_y_max = layout[3];
		I("%d, %d, %d, %d\n", ts->pdata->abs_x_min,
		ts->pdata->abs_x_max, ts->pdata->abs_y_min,
		ts->pdata->abs_y_max);
		input_unregister_device(ts->input_dev);
		himax_input_register(ts);
	} else {
		I("ERR@%d, %d, %d, %d\n", ts->pdata->abs_x_min,
		ts->pdata->abs_x_max, ts->pdata->abs_y_min,
		ts->pdata->abs_y_max);
	}
	return len;
}

const struct file_operations himax_proc_layout_ops = {
	.owner = THIS_MODULE,
	.read = himax_layout_read,
	.write = himax_layout_write,
};

static ssize_t himax_debug_level_read(struct file *file, char *buf,
	size_t len, loff_t *pos)
{
	struct himax_ts_data *ts_data;
	size_t ret = 0;
	char *temp_buf;

	ts_data = private_ts;

	if (!HX_PROC_SEND_FLAG) {
		temp_buf = kzalloc(len, GFP_KERNEL);
		ret += snprintf(temp_buf, len, "%d\n",
		ts_data->debug_log_level);

		if (copy_to_user(buf, temp_buf, len))
			I("%s,here:%d\n", __func__, __LINE__);

		kfree(temp_buf);
		HX_PROC_SEND_FLAG = 1;
	} else
		HX_PROC_SEND_FLAG = 0;

	return ret;
}

static ssize_t himax_debug_level_write(struct file *file, const char *buff,
	size_t len, loff_t *pos)
{
	struct himax_ts_data *ts;
	char buf_tmp[11];
	int i;

	ts = private_ts;

	if (len >= 12) {
		I("%s: no command exceeds 12 chars.\n", __func__);
		return -EFAULT;
	}
	if (copy_from_user(buf_tmp, buff, len))
		return -EFAULT;

	ts->debug_log_level = 0;
	for (i = 0 ; i < len - 1 ; i++) {
		if (buf_tmp[i] >= '0' && buf_tmp[i] <= '9')
			ts->debug_log_level |= (buf_tmp[i] - '0');
		else if (buf_tmp[i] >= 'A' && buf_tmp[i] <= 'F')
			ts->debug_log_level |= (buf_tmp[i]-'A' + 10);
		else if (buf_tmp[i] >= 'a' && buf_tmp[i] <= 'f')
			ts->debug_log_level |= (buf_tmp[i] - 'a' + 10);

		if (i != len - 2)
			ts->debug_log_level <<= 4;
	}

	if (ts->debug_log_level & BIT(3)) {
		if (ts->pdata->screenWidth > 0 && ts->pdata->screenHeight > 0 &&
		 (ts->pdata->abs_x_max - ts->pdata->abs_x_min) > 0 &&
		 (ts->pdata->abs_y_max - ts->pdata->abs_y_min) > 0) {
			ts->widthFactor =
			(ts->pdata->screenWidth << SHIFTBITS)
			/ (ts->pdata->abs_x_max - ts->pdata->abs_x_min);
			ts->heightFactor =
			(ts->pdata->screenHeight << SHIFTBITS)
			/ (ts->pdata->abs_y_max - ts->pdata->abs_y_min);
			if (ts->widthFactor > 0 && ts->heightFactor > 0)
				ts->useScreenRes = 1;
			else {
				ts->heightFactor = 0;
				ts->widthFactor = 0;
				ts->useScreenRes = 0;
			}
		} else
			I("Enable finger debug with raw position mode!\n");
	} else {
		ts->useScreenRes = 0;
		ts->widthFactor = 0;
		ts->heightFactor = 0;
	}

	return len;
}

const struct file_operations himax_proc_debug_level_ops = {
	.owner = THIS_MODULE,
	.read = himax_debug_level_read,
	.write = himax_debug_level_write,
};

#ifdef HX_TP_PROC_REGISTER
static ssize_t himax_proc_register_read(struct file *file, char *buf,
	size_t len, loff_t *pos)
{
	int ret = 0;
	uint16_t loop_i;
	uint8_t data[128];
	char *temp_buf;

	memset(data, 0x00, sizeof(data));

	I("himax_register_show: %x,%x,%x,%x\n", register_command[0],
	register_command[1], register_command[2], register_command[3]);

	if (!HX_PROC_SEND_FLAG) {
		temp_buf = kzalloc(len, GFP_KERNEL);
		himax_register_read(private_ts->client,
		register_command, 1, data);

		ret += snprintf(temp_buf, len, "command: %x,%x,%x,%x\n",
		register_command[0], register_command[1],
		register_command[2], register_command[3]);

		for (loop_i = 0 ; loop_i < 128 ; loop_i++) {
			ret += snprintf(temp_buf + ret,
			sizeof(data[loop_i]), "0x%2.2X ", data[loop_i]);
			if ((loop_i % 16) == 15)
				ret += snprintf(temp_buf + ret, 1, "\n");
		}
		ret += snprintf(temp_buf + ret, len, "\n");
		HX_PROC_SEND_FLAG = 1;

		if (copy_to_user(buf, temp_buf, len))
			I("%s,here:%d\n", __func__, __LINE__);

		kfree(temp_buf);
	} else
		HX_PROC_SEND_FLAG = 0;
	return ret;
}

static ssize_t himax_proc_register_write(struct file *file, const char *buff,
	size_t len, loff_t *pos)
{
	char buf_tmp[16], length = 0;
	unsigned long result    = 0;
	uint8_t loop_i          = 0;
	uint16_t base           = 5;
	uint8_t write_da[128];
	char buf[80] = {0};

	if (len >= 80) {
		I("%s: no command exceeds 80 chars.\n", __func__);
		return -EFAULT;
	}
	if (copy_from_user(buf, buff, len))
		return -EFAULT;

	memset(buf_tmp, 0x0, sizeof(buf_tmp));
	memset(write_da, 0x0, sizeof(write_da));

	I("himax %s\n", buf);

	if ((buf[0] == 'r' || buf[0] == 'w') && buf[1] == ':') {

		if (buf[2] == 'x') {
			memcpy(buf_tmp, buf + 3, 8);
			if (!kstrtoul(buf_tmp, 16, &result)) {
					register_command[0] =
					(uint8_t)result;
					register_command[1] =
					(uint8_t)(result >> 8);
					register_command[2] =
					(uint8_t)(result >> 16);
					register_command[3] =
					(uint8_t)(result >> 24);
			}
			base = 11;
			I("CMD: %x,%x,%x,%x\n", register_command[0],
			register_command[1], register_command[2],
			register_command[3]);

			for (loop_i = 0 ; loop_i < 128 ; loop_i++) {
				if (buf[base] == '\n') {
					if (buf[0] == 'w') {
						himax_register_write
						(private_ts->client,
						register_command
						, 1, write_da);
						I("CMD:%x, %x, %x, %x,len=%d\n",
						write_da[0], write_da[1],
						write_da[2], write_da[3],
						length);
					}
					I("\n");
					return len;
				}
				if (buf[base + 1] == 'x') {
					buf_tmp[10] = '\n';
					buf_tmp[11] = '\0';
					memcpy(buf_tmp, buf + base + 2, 8);
					if (!kstrtoul(buf_tmp, 16, &result)) {
						write_da[loop_i] =
						(uint8_t)result;
						write_da[loop_i+1] =
						(uint8_t)(result >> 8);
						write_da[loop_i+2] =
						(uint8_t)(result >> 16);
						write_da[loop_i+3] =
						(uint8_t)(result >> 24);
					}
					length += 4;
				}
				base += 10;
			}
		}
	}
	return len;
}

const struct file_operations himax_proc_register_ops = {
	.owner = THIS_MODULE,
	.read = himax_proc_register_read,
	.write = himax_proc_register_write,
};
#endif

#ifdef HX_TP_PROC_DIAG
int16_t *getMutualBuffer(void)
{
	return diag_mutual;
}
int16_t *getMutualNewBuffer(void)
{
	return diag_mutual_new;
}
int16_t *getMutualOldBuffer(void)
{
	return diag_mutual_old;
}
int16_t *getSelfBuffer(void)
{
	return &diag_self[0];
}
uint8_t getXChannel(void)
{
	return x_channel;
}
uint8_t getYChannel(void)
{
	return y_channel;
}
uint8_t getDiagCommand(void)
{
	return diag_command;
}
void setXChannel(uint8_t x)
{
	x_channel = x;
}
void setYChannel(uint8_t y)
{
	y_channel = y;
}
void setMutualBuffer(void)
{
	diag_mutual = kzalloc
	(x_channel * y_channel * sizeof(int16_t), GFP_KERNEL);
}
void setMutualNewBuffer(void)
{
	diag_mutual_new = kzalloc
	(x_channel * y_channel * sizeof(int16_t), GFP_KERNEL);
}
void setMutualOldBuffer(void)
{
	diag_mutual_old = kzalloc
	(x_channel * y_channel * sizeof(int16_t), GFP_KERNEL);
}

#ifdef HX_TP_PROC_2T2R
int16_t *getMutualBuffer_2(void)
{
	return diag_mutual_2;
}
uint8_t getXChannel_2(void)
{
	return x_channel_2;
}
uint8_t getYChannel_2(void)
{
	return y_channel_2;
}
void setXChannel_2(uint8_t x)
{
	x_channel_2 = x;
}
void setYChannel_2(uint8_t y)
{
	y_channel_2 = y;
}
void setMutualBuffer_2(void)
{
	diag_mutual_2 = kzalloc
	(x_channel_2 * y_channel_2 * sizeof(int16_t), GFP_KERNEL);
}
#endif

static ssize_t himax_diag_arrange_write(struct file *file, const char *buff,
	size_t len, loff_t *pos)
{
	/*struct himax_ts_data *ts = private_ts;*/
	char buf[80] = {0};

	if (len >= 80) {
		I("%s: no command exceeds 80 chars.\n", __func__);
		return -EFAULT;
	}
	if (copy_from_user(buf, buff, len))
		return -EFAULT;

	g_diag_arr_num = buf[0] - '0';
	I("%s: g_diag_arr_num = %d\n", __func__, g_diag_arr_num);

	return len;
}

const struct file_operations himax_proc_diag_arrange_ops = {
	.owner = THIS_MODULE,
	.write = himax_diag_arrange_write,
};

static void himax_diag_arrange_print
(struct seq_file *s, int i, int j, int transpose)
{
	if (transpose)
		seq_printf(s, "%6d", diag_mutual[j + i * x_channel]);
	else
		seq_printf(s, "%6d", diag_mutual[i + j * x_channel]);
}

static void himax_diag_arrange_inloop
(struct seq_file *s, int in_init, bool transpose, int j)
{
	int i;
	int in_max = 0;

	if (transpose)
		in_max = y_channel;
	else
		in_max = x_channel;

	if (in_init > 0) {
		for (i = in_init - 1 ; i >= 0 ; i--)
			himax_diag_arrange_print(s, i, j, transpose);
	} else {
		for (i = 0 ; i < in_max ; i++)
			himax_diag_arrange_print(s, i, j, transpose);
	}
}

static void himax_diag_arrange_outloop
(struct seq_file *s, int transpose, int out_init, int in_init)
{
	int j;
	int out_max = 0;

	if (transpose)
		out_max = x_channel;
	else
		out_max = y_channel;

	if (out_init > 0) {
		for (j = out_init - 1 ; j >= 0 ; j--) {
			himax_diag_arrange_inloop(s, in_init, transpose, j);
			seq_printf(s, " %5d\n", diag_self[j]);
		}
	} else {
		for (j = 0 ; j < out_max ; j++) {
			himax_diag_arrange_inloop(s, in_init, transpose, j);
			seq_printf(s, " %5d\n", diag_self[j]);
		}
	}
}

static void himax_diag_arrange(struct seq_file *s)
{
	int bit2, bit1, bit0;
	int i;

	bit2 = g_diag_arr_num >> 2;
	bit1 = g_diag_arr_num >> 1 & 0x1;
	bit0 = g_diag_arr_num & 0x1;

	if (g_diag_arr_num < 4) {
		himax_diag_arrange_outloop(s,
		bit2, bit1 * y_channel, bit0 * x_channel);

		for (i = y_channel ; i < x_channel + y_channel ; i++)
			seq_printf(s, "%6d", diag_self[i]);

	} else {
		himax_diag_arrange_outloop(s,
		bit2, bit1 * x_channel, bit0 * y_channel);

		for (i = x_channel ; i < x_channel + y_channel ; i++)
			seq_printf(s, "%6d", diag_self[i]);

	}
}

static void *himax_diag_seq_start(struct seq_file *s, loff_t *pos)
{
	if (*pos >= 1)
		return NULL;
	return (void *)((unsigned long) *pos + 1);
}

static void *himax_diag_seq_next(struct seq_file *s, void *v, loff_t *pos)
{
	return NULL;
}
static void himax_diag_seq_stop(struct seq_file *s, void *v)
{
}
static int himax_diag_seq_read(struct seq_file *s, void *v)
{
	size_t count = 0;
	int32_t loop_i;/*loop_j*/
	uint16_t mutual_num, self_num, width;

#ifdef HX_TP_PROC_2T2R
	if (Is_2T2R && diag_command == 4) {
		mutual_num	= x_channel_2 * y_channel_2;
		/*don't add KEY_COUNT*/
		self_num	= x_channel_2 + y_channel_2;
		width		= x_channel_2;
		seq_printf(s, "ChannelStart: %4d, %4d\n\n",
		x_channel_2, y_channel_2);
	} else
#endif
	{
		mutual_num	= x_channel * y_channel;
		/*don't add KEY_COUNT*/
		self_num	= x_channel + y_channel;
		width		= x_channel;
		seq_printf(s, "ChannelStart: %4d, %4d\n\n",
		x_channel, y_channel);
	}

	/* start to show out the raw data in adb shell*/
	if (diag_command >= 1 && diag_command <= 6) {
		if (diag_command <= 3) {
			himax_diag_arrange(s);
			seq_puts(s, "\n\n");
#ifdef HX_EN_SEL_BUTTON
			seq_putc(s, '\n');
			for (loop_i = 0 ; loop_i < HX_BT_NUM ; loop_i++)
				seq_printf(s, "%6d",
				diag_self[HX_RX_NUM + HX_TX_NUM + loop_i]);
#endif
#ifdef HX_TP_PROC_2T2R
		} else if (Is_2T2R && diag_command == 4) {
			for (loop_i = 0 ; loop_i < mutual_num ; loop_i++) {
				seq_printf(s, "%4d", diag_mutual_2[loop_i]);
				if ((loop_i % width) == (width - 1))
					seq_printf(s, " %6d\n",
					diag_self[width + loop_i / width]);
			}
			seq_putc(s, '\n');
			for (loop_i = 0 ; loop_i < width ; loop_i++) {
				seq_printf(s, "%6d", diag_self[loop_i]);
				if (((loop_i) % width) == (width - 1))
					seq_putc(s, '\n');
			}
#ifdef HX_EN_SEL_BUTTON
			seq_putc(s, '\n');
			for (loop_i = 0 ; loop_i < HX_BT_NUM ; loop_i++) {
				seq_printf(s, "%4d",
				diag_self[HX_RX_NUM_2 + HX_TX_NUM_2 + loop_i]);
			}
#endif
#endif
		} else if (diag_command > 4) {
			for (loop_i = 0 ; loop_i < self_num ; loop_i++) {
				seq_printf(s, "%4d", diag_self[loop_i]);
				if (((loop_i - mutual_num) % width)
				== (width - 1)) {
					seq_putc(s, '\n');
				}
			}
		} else {
			for (loop_i = 0 ; loop_i < mutual_num ; loop_i++) {
				seq_printf(s, "%4d", diag_mutual[loop_i]);
				if ((loop_i % width) == (width - 1))
					seq_putc(s, '\n');
			}
		}
		seq_puts(s, "ChannelEnd");
		seq_putc(s, '\n');
	} else if (diag_command == 7) {
		for (loop_i = 0; loop_i < 128 ; loop_i++) {
			if ((loop_i % 16) == 0)
				seq_puts(s, "LineStart:");
				seq_printf(s, "%4d", diag_coor[loop_i]);
			if ((loop_i % 16) == 15)
				seq_putc(s, '\n');
		}
	} else if (diag_command == 9 ||
	diag_command == 91 || diag_command == 92) {

		himax_diag_arrange(s);
		seq_putc(s, '\n');
	}

	return count;
}
const struct seq_operations himax_diag_seq_ops = {
	.start	= himax_diag_seq_start,
	.next	= himax_diag_seq_next,
	.stop	= himax_diag_seq_stop,
	.show	= himax_diag_seq_read,
};
static int himax_diag_proc_open(struct inode *inode, struct file *file)
{
	return seq_open(file, &himax_diag_seq_ops);
};
bool DSRAM_Flag = false;

/*DSRAM thread*/
void himax_ts_diag_func(void)
{
	int i = 0, j = 0;
	unsigned int index = 0;
	int total_size = ic_data->HX_TX_NUM * ic_data->HX_RX_NUM * 2;
	uint8_t  info_data[total_size];
	int16_t *mutual_data;
	int16_t *mutual_data_new;
	int16_t *mutual_data_old;
	int16_t new_data;

	himax_burst_enable(private_ts->client, 1);
	if (diag_command == 9 || diag_command == 91) {
		mutual_data = getMutualBuffer();
	} else if (diag_command == 92) {
		mutual_data = getMutualBuffer();
		mutual_data_new = getMutualNewBuffer();
		mutual_data_old = getMutualOldBuffer();
	}
	himax_get_DSRAM_data(private_ts->client, info_data);

	index = 0;
	for (i = 0 ; i < ic_data->HX_TX_NUM ; i++) {
		for (j = 0 ; j < ic_data->HX_RX_NUM ; j++) {
			new_data = (short)(info_data[index + 1]
			<< 8 | info_data[index]);
			if (diag_command == 9) {
				mutual_data[i * ic_data->HX_RX_NUM + j]
				= new_data;
			/*Keep max data for 100 frame*/
			} else if (diag_command == 91) {
				if (mutual_data[i * ic_data->HX_RX_NUM + j]
				< new_data) {
					mutual_data[i * ic_data->HX_RX_NUM + j]
					= new_data;
				}
			/*Cal data for [N]-[N-1] frame*/
			} else if (diag_command == 92) {
				mutual_data_new[i * ic_data->HX_RX_NUM + j]
				= new_data;

				mutual_data[i * ic_data->HX_RX_NUM + j] =
				mutual_data_new[i * ic_data->HX_RX_NUM + j] -
				mutual_data_old[i * ic_data->HX_RX_NUM + j];
			}
			index += 2;
		}
	}
	/*copy N data to N-1 array*/
	if (diag_command == 92) {
		memcpy(mutual_data_old, mutual_data_new,
		x_channel * y_channel * sizeof(int16_t));
	}

	diag_max_cnt++;
	if (diag_command == 9 || diag_command == 92) {
		queue_delayed_work(private_ts->himax_diag_wq,
		&private_ts->himax_diag_delay_wrok, 1/10*HZ);
	} else if (diag_command == 91) {
		if (diag_max_cnt > 100) {/*count for 100 frame*/
			/*Clear DSRAM flag*/
			DSRAM_Flag = false;

			/*Enable ISR*/
			himax_int_enable(private_ts->client->irq, 1);

			/*=====================================
			test result command : 0x8002_0324 ==> 0x00
			=====================================*/
			himax_diag_register_set(private_ts->client, 0x00);
		} else {
			queue_delayed_work(private_ts->himax_diag_wq,
			&private_ts->himax_diag_delay_wrok, 1 / 10 * HZ);
		}
	}
}

static ssize_t himax_diag_write
(struct file *filp, const char __user *buff, size_t len, loff_t *data)
{
	char messages[80] = {0};

	uint8_t command[2] = {0x00, 0x00};
	uint8_t receive[1];

	memset(receive, 0x00, sizeof(receive));

	if (len >= 80) {
		I("%s: no command exceeds 80 chars.\n", __func__);
		return -EFAULT;
	}
	if (copy_from_user(messages, buff, len))
		return -EFAULT;

	if (messages[1] == 0x0A)
		diag_command = messages[0] - '0';
	else
		diag_command = (messages[0] - '0') * 10 + (messages[1] - '0');


	I("[Himax]diag_command=0x%x\n", diag_command);
	if (diag_command < 0x04) {
		if (DSRAM_Flag) {
			/*1. Clear DSRAM flag*/
			DSRAM_Flag = false;

			/*2. Stop DSRAM thread*/
			cancel_delayed_work_sync
			(&private_ts->himax_diag_delay_wrok);

			/*3. Enable ISR*/
			himax_int_enable(private_ts->client->irq, 1);
		}
		command[0] = diag_command;
		himax_diag_register_set(private_ts->client, command[0]);
	/*coordinate dump start*/
	} else if (diag_command == 0x09 ||
	diag_command == 91 || diag_command == 92) {

		diag_max_cnt = 0;
		 /*Set data 0 everytime*/
		memset(diag_mutual, 0x00,
		x_channel * y_channel * sizeof(int16_t));

		/*1. Disable ISR*/
		himax_int_enable(private_ts->client->irq, 0);

		/*2. Start DSRAM thread*/
		/*himax_diag_register_set(private_ts->client, 0x0A);*/

		queue_delayed_work(private_ts->himax_diag_wq,
		&private_ts->himax_diag_delay_wrok, 2 * HZ / 100);

		I("%s: Start get raw data in DSRAM\n", __func__);

		/*3. Set DSRAM flag*/
		DSRAM_Flag = true;
	} else {
		command[0] = 0x00;
		himax_diag_register_set(private_ts->client, command[0]);
		E("[Himax]Diag command error!diag_command=0x%x\n",
		diag_command);
	}
	return len;
}

const struct file_operations himax_proc_diag_ops = {
	.owner = THIS_MODULE,
	.open = himax_diag_proc_open,
	.read = seq_read,
	.write = himax_diag_write,
};
#endif

#ifdef HX_TP_PROC_RESET
static ssize_t himax_reset_write(struct file *file, const char *buff,
	size_t len, loff_t *pos)
{
	char buf_tmp[12];

	if (len >= 12) {
		I("%s: no command exceeds 12 chars.\n", __func__);
		return -EFAULT;
	}
	if (copy_from_user(buf_tmp, buff, len))
		return -EFAULT;

	/*if (buf_tmp[0] == '1')
		ESD_HW_REST();*/

	return len;
}

const struct file_operations himax_proc_reset_ops = {
	.owner = THIS_MODULE,
	.write = himax_reset_write,
};
#endif

#ifdef HX_TP_PROC_DEBUG
static ssize_t himax_debug_read(struct file *file, char *buf,
	size_t len, loff_t *pos)
{
	size_t count = 0;
	char *temp_buf;

	if (!HX_PROC_SEND_FLAG) {
		temp_buf = kzalloc(len, GFP_KERNEL);
		if (debug_level_cmd == 't') {
			if (fw_update_complete) {
				count += snprintf(temp_buf, len,
				"FW Update Complete ");
			} else {
				count += snprintf(temp_buf, len,
				"FW Update Fail ");
			}

		} else if (debug_level_cmd == 'h') {
			if (handshaking_result == 0) {
				count += snprintf(temp_buf, len,
				"Handshaking Result = %d (MCU Running)\n",
				handshaking_result);
			} else if (handshaking_result == 1) {
				count += snprintf(temp_buf, len,
				"Handshaking Result = %d (MCU Stop)\n",
				handshaking_result);
			} else if (handshaking_result == 2) {
				count += snprintf(temp_buf, len,
				"Handshaking Result = %d (I2C Error)\n",
				handshaking_result);
			} else {
				count += snprintf(temp_buf, len,
				"Handshaking Result = error\n");
			}
		} else if (debug_level_cmd == 'v') {
			count += snprintf(temp_buf + count, len,
			"FW_VER = ");
			count += snprintf(temp_buf + count, len,
			"0x%2.2X\n", ic_data->vendor_fw_ver);
			count += snprintf(temp_buf + count, len,
			"CONFIG_VER = ");
			count += snprintf(temp_buf + count, len,
			"0x%2.2X\n", ic_data->vendor_config_ver);
			count += snprintf(temp_buf + count, len,
			"\n");
		} else if (debug_level_cmd == 'd') {
			count += snprintf(temp_buf + count, len,
			"Himax Touch IC Information :\n");
			if (IC_TYPE == HX_85XX_D_SERIES_PWON) {
				count += snprintf(temp_buf + count, len,
				"IC Type : D\n");
			} else if (IC_TYPE == HX_85XX_E_SERIES_PWON) {
				count += snprintf(temp_buf + count, len,
				"IC Type : E\n");
			} else if (IC_TYPE == HX_85XX_ES_SERIES_PWON) {
				count += snprintf(temp_buf + count, len,
				"IC Type : ES\n");
			} else if (IC_TYPE == HX_85XX_F_SERIES_PWON) {
				count += snprintf(temp_buf + count, len,
				"IC Type : F\n");
			} else {
				count += snprintf(temp_buf + count, len,
				"IC Type error.\n");
			}
			if (IC_CHECKSUM == HX_TP_BIN_CHECKSUM_SW) {
				count += snprintf(temp_buf + count, len,
				"IC Checksum : SW\n");
			} else if (IC_CHECKSUM == HX_TP_BIN_CHECKSUM_HW) {
				count += snprintf(temp_buf + count, len,
				"IC Checksum : HW\n");
			} else if (IC_CHECKSUM == HX_TP_BIN_CHECKSUM_CRC) {
				count += snprintf(temp_buf + count, len,
				"IC Checksum : CRC\n");
			} else {
				count += snprintf(temp_buf + count, len,
				"IC Checksum error.\n");
			}
			if (ic_data->HX_INT_IS_EDGE) {
				count += snprintf(temp_buf + count, len,
				"Interrupt : EDGE TIRGGER\n");
			} else {
				count += snprintf(temp_buf + count, len,
				"Interrupt : LEVEL TRIGGER\n");
			}
			count += snprintf(temp_buf + count, len,
			"RX Num : %d\n", ic_data->HX_RX_NUM);
			count += snprintf(temp_buf + count, len,
			"TX Num : %d\n", ic_data->HX_TX_NUM);
			count += snprintf(temp_buf + count, len,
			"BT Num : %d\n", ic_data->HX_BT_NUM);
			count += snprintf(temp_buf + count, len,
			"X Resolution : %d\n", ic_data->HX_X_RES);
			count += snprintf(temp_buf + count, len,
			"Y Resolution : %d\n", ic_data->HX_Y_RES);
			count += snprintf(temp_buf + count, len,
			"Max Point : %d\n", ic_data->HX_MAX_PT);
			count += snprintf(temp_buf + count, len,
			"XY reverse : %d\n", ic_data->HX_XY_REVERSE);
	#ifdef HX_TP_PROC_2T2R
			if (Is_2T2R) {
				count += snprintf(temp_buf + count, len,
				"2T2R panel\n");
				count += snprintf(temp_buf + count, len,
				"RX Num_2 : %d\n", HX_RX_NUM_2);
				count += snprintf(temp_buf + count, len,
				"TX Num_2 : %d\n", HX_TX_NUM_2);
			}
	#endif
		} else if (debug_level_cmd == 'i') {
			count += snprintf(temp_buf + count, len,
			"Himax Touch Driver Version:\n");
			count += snprintf(temp_buf + count, len,
			"%s\n", HIMAX_DRIVER_VER);
		}
		if (copy_to_user(buf, temp_buf, len))
			I("%s,here:%d\n", __func__, __LINE__);

		kfree(temp_buf);
		HX_PROC_SEND_FLAG = 1;
	} else
		HX_PROC_SEND_FLAG = 0;
	return count;
}

static ssize_t himax_debug_write(struct file *file, const char *buff,
	size_t len, loff_t *pos)
{
	int result = 0;
	char fileName[128];
	char buf[80] = {0};
	const struct firmware *fw = NULL;

	if (len >= 80) {
		I("%s: no command exceeds 80 chars.\n", __func__);
		return -EFAULT;
	}
	if (copy_from_user(buf, buff, len))
		return -EFAULT;

	if (buf[0] == 'h') {/*handshaking*/
		debug_level_cmd = buf[0];

		himax_int_enable(private_ts->client->irq, 0);

		/*0:Running, 1:Stop, 2:I2C Fail*/
		handshaking_result = himax_hand_shaking(private_ts->client);

		himax_int_enable(private_ts->client->irq, 1);

		return len;
	} else if (buf[0] == 'v') { /*firmware version*/
		debug_level_cmd = buf[0];
		himax_int_enable(private_ts->client->irq, 0);
#ifdef HX_RST_PIN_FUNC
		himax_HW_reset(false, false);
#endif
		himax_read_FW_ver(private_ts->client);
		/*himax_check_chip_version();*/
#ifdef HX_RST_PIN_FUNC
	himax_HW_reset(true, false);
#endif
	himax_int_enable(private_ts->client->irq, 1);
		return len;
	} else if (buf[0] == 'd') { /*ic information*/

		debug_level_cmd = buf[0];
		return len;
	} else if (buf[0] == 'i') {/*driver version*/

		debug_level_cmd = buf[0];
		return len;
	} else if (buf[0] == 't') {

		himax_int_enable(private_ts->client->irq, 0);
		debug_level_cmd = buf[0];
		fw_update_complete = false;

		result = himax_load_CRC_bin_file(private_ts->client);
		if (result < 0) {
			E("%s: himax_load_CRC_bin_file fail Error Code=%d.\n",
			__func__, result);
			return result;
		}

		memset(fileName, 0, 128);
/* parse the file name*/
		snprintf(fileName, len-4, "%s", &buf[4]);
		I("%s: upgrade from file(%s) start!\n", __func__, fileName);
		result = request_firmware(&fw, fileName, private_ts->dev);
		if (result < 0) {
			I("fail to request_firmware fwpath: %s (ret:%d)\n",
			fileName, result);
			return result;
		}
		I("%s: FW image: %02X, %02X, %02X, %02X ret=%d\n", __func__,
		fw->data[0], fw->data[1], fw->data[2], fw->data[3], result);
		if (result >= 0) {
			/*start to upgrade*/
			himax_int_enable(private_ts->client->irq, 0);

			if ((buf[1] == '6') && (buf[2] == '0')) {
				if (fts_ctpm_fw_upgrade_with_sys_fs_60k
				(private_ts->client, (unsigned char *)fw->data,
				fw->size, false) == 0) {
					E("%s: TP upgrade error, line: %d\n",
					__func__, __LINE__);
					fw_update_complete = false;
				} else {
					I("%s: TP upgrade OK, line: %d\n",
					__func__, __LINE__);
					fw_update_complete = true;
				}
			} else if ((buf[1] == '6') && (buf[2] == '4')) {
				if (fts_ctpm_fw_upgrade_with_sys_fs_64k
				(private_ts->client, (unsigned char *)fw->data,
				fw->size, false) == 0) {
					E("%s: TP upgrade error, line: %d\n",
					__func__, __LINE__);
					fw_update_complete = false;
				} else {
					I("%s: TP upgrade OK, line: %d\n",
					__func__, __LINE__);
					fw_update_complete = true;
				}
			} else if ((buf[1] == '2') && (buf[2] == '4')) {
				if (fts_ctpm_fw_upgrade_with_sys_fs_124k
				(private_ts->client, (unsigned char *)fw->data,
				fw->size, false) == 0) {
					E("%s: TP upgrade error, line: %d\n",
					__func__, __LINE__);
					fw_update_complete = false;
				} else {
					I("%s: TP upgrade OK, line: %d\n",
					__func__, __LINE__);
					fw_update_complete = true;
				}
			} else if ((buf[1] == '2') && (buf[2] == '8')) {
				if (fts_ctpm_fw_upgrade_with_sys_fs_128k
				(private_ts->client, (unsigned char *)fw->data,
				fw->size, false) == 0) {
					E("%s: TP upgrade error, line: %d\n",
					__func__, __LINE__);
					fw_update_complete = false;
				} else {
					I("%s: TP upgrade OK, line: %d\n",
					__func__, __LINE__);
					fw_update_complete = true;
				}
			} else {
				E("%s: Flash command fail: %d\n",
				__func__, __LINE__);
				fw_update_complete = false;
			}
			release_firmware(fw);
			goto firmware_upgrade_done;
			/*return count;*/
		}
	}

firmware_upgrade_done:

#ifdef HX_RST_PIN_FUNC
	himax_HW_reset(true, false);
#endif

	himax_sense_on(private_ts->client, 0x01);
	msleep(120);
#ifdef HX_ESD_WORKAROUND
	HX_ESD_RESET_ACTIVATE = 1;
#endif
	himax_int_enable(private_ts->client->irq, 1);

	/*todo himax_chip->tp_firmware_upgrade_proceed = 0;
	todo himax_chip->suspend_state = 0;
	todo enable_irq(himax_chip->irq);*/
	return len;
}

const struct file_operations himax_proc_debug_ops = {
	.owner = THIS_MODULE,
	.read = himax_debug_read,
	.write = himax_debug_write,
};

#endif

#ifdef HX_TP_PROC_FLASH_DUMP

static uint8_t getFlashCommand(void)
{
	return flash_command;
}

static uint8_t getFlashDumpProgress(void)
{
	return flash_progress;
}

static uint8_t getFlashDumpComplete(void)
{
	return flash_dump_complete;
}

static uint8_t getFlashDumpFail(void)
{
	return flash_dump_fail;
}

uint8_t getSysOperation(void)
{
	return sys_operation;
}

static uint8_t getFlashReadStep(void)
{
	return flash_read_step;
}
/*
static uint8_t getFlashDumpSector(void)
{
	return flash_dump_sector;
}

static uint8_t getFlashDumpPage(void)
{
	return flash_dump_page;
}
*/
bool getFlashDumpGoing(void)
{
	return flash_dump_going;
}

void setFlashBuffer(void)
{
	flash_buffer = kzalloc
	(Flash_Size * sizeof(uint8_t), GFP_KERNEL);
	memset(flash_buffer, 0x00, Flash_Size);
}

void setSysOperation(uint8_t operation)
{
	sys_operation = operation;
}

static void setFlashDumpProgress(uint8_t progress)
{
	flash_progress = progress;
	/*I("setFlashDumpProgress : progress = %d ,
	flash_progress = %d\n",progress,flash_progress);*/
}

static void setFlashDumpComplete(uint8_t status)
{
	flash_dump_complete = status;
}

static void setFlashDumpFail(uint8_t fail)
{
	flash_dump_fail = fail;
}

static void setFlashCommand(uint8_t command)
{
	flash_command = command;
}

static void setFlashReadStep(uint8_t step)
{
	flash_read_step = step;
}

static void setFlashDumpSector(uint8_t sector)
{
	flash_dump_sector = sector;
}

static void setFlashDumpPage(uint8_t page)
{
	flash_dump_page = page;
}

static void setFlashDumpGoing(bool going)
{
	flash_dump_going = going;
}

static ssize_t himax_proc_flash_read(struct file *file, char *buf,
	size_t len, loff_t *pos)
{
	int ret = 0;
	int loop_i;
	uint8_t local_flash_read_step = 0;
	uint8_t local_flash_complete = 0;
	uint8_t local_flash_progress = 0;
	uint8_t local_flash_command = 0;
	uint8_t local_flash_fail = 0;
	char *temp_buf;

	local_flash_complete = getFlashDumpComplete();
	local_flash_progress = getFlashDumpProgress();
	local_flash_command = getFlashCommand();
	local_flash_fail = getFlashDumpFail();

	I("flash_progress = %d\n", local_flash_progress);
	if (!HX_PROC_SEND_FLAG) {
		temp_buf = kzalloc(len, GFP_KERNEL);
		if (local_flash_fail) {
			ret += snprintf(temp_buf + ret, len,
			"FlashStart:Fail\n");
			ret += snprintf(temp_buf + ret, len,
			"FlashEnd");
			ret += snprintf(temp_buf + ret, len,
			"\n");

			if (copy_to_user(buf, temp_buf, len))
				I("%s,here:%d\n", __func__, __LINE__);

			kfree(temp_buf);
			HX_PROC_SEND_FLAG = 1;
			return ret;
		}

		if (!local_flash_complete) {
			ret += snprintf(temp_buf+ret, len,
			"FlashStart:Ongoing:0x%2.2x\n", flash_progress);
			ret += snprintf(temp_buf + ret, len, "FlashEnd");
			ret += snprintf(temp_buf + ret, len, "\n");

			if (copy_to_user(buf, temp_buf, len))
				I("%s,here:%d\n", __func__, __LINE__);

			kfree(temp_buf);
			HX_PROC_SEND_FLAG = 1;
			return ret;
		}

		if (local_flash_command == 1 && local_flash_complete) {
			ret += snprintf(temp_buf+ret, len,
			"FlashStart:Complete\n");
			ret += snprintf(temp_buf + ret, len, "FlashEnd");
			ret += snprintf(temp_buf + ret, len, "\n");

			if (copy_to_user(buf, temp_buf, len))
				I("%s,here:%d\n", __func__, __LINE__);

			kfree(temp_buf);
			HX_PROC_SEND_FLAG = 1;
			return ret;
		}

		if (local_flash_command == 3 && local_flash_complete) {
			ret += snprintf(temp_buf+ret, len, "FlashStart:\n");
			for (loop_i = 0 ; loop_i < 128 ; loop_i++) {
				ret += snprintf(temp_buf + ret, len,
				"x%2.2x", flash_buffer[loop_i]);
				if ((loop_i % 16) == 15)
					ret += snprintf(temp_buf + ret, len,
					"\n");
			}
			ret += snprintf(temp_buf + ret, len, "FlashEnd");
			ret += snprintf(temp_buf + ret, len, "\n");

			if (copy_to_user(buf, temp_buf, len))
				I("%s,here:%d\n", __func__, __LINE__);

			kfree(temp_buf);
			HX_PROC_SEND_FLAG = 1;
			return ret;
		}

		/*flash command == 0 , report the data*/
		local_flash_read_step = getFlashReadStep();

		ret += snprintf(temp_buf + ret, len,
		"FlashStart:%2.2x\n", local_flash_read_step);

		for (loop_i = 0 ; loop_i < 1024 ; loop_i++) {
			ret += snprintf(temp_buf + ret, len, "x%2.2X",
			flash_buffer[local_flash_read_step * 1024 + loop_i]);

			if ((loop_i % 16) == 15)
				ret += snprintf(temp_buf + ret, len, "\n");
		}

		ret += snprintf(temp_buf + ret, len, "FlashEnd");
		ret += snprintf(temp_buf + ret, len, "\n");
		if (copy_to_user(buf, temp_buf, len))
			I("%s,here:%d\n", __func__, __LINE__);

		kfree(temp_buf);
		HX_PROC_SEND_FLAG = 1;
	} else
		HX_PROC_SEND_FLAG = 0;
	return ret;
}

static ssize_t himax_proc_flash_write(struct file *file,
const char *buff, size_t len, loff_t *pos)
{
	char buf_tmp[6];
	unsigned long result = 0;
	uint8_t loop_i = 0;
	int base = 0;
	char buf[80] = {0};

	if (len >= 80) {
		I("%s: no command exceeds 80 chars.\n", __func__);
		return -EFAULT;
	}
	if (copy_from_user(buf, buff, len))
		return -EFAULT;
	memset(buf_tmp, 0x0, sizeof(buf_tmp));

	I("%s: buf[0] = %s\n", __func__, buf);

	if (getSysOperation() == 1) {
		E("%s: PROC is busy , return!\n", __func__);
		return len;
	}

	if (buf[0] == '0') {
		setFlashCommand(0);
		if (buf[1] == ':' && buf[2] == 'x') {
			memcpy(buf_tmp, buf + 3, 2);
			I("%s: read_Step = %s\n", __func__, buf_tmp);
			if (!kstrtoul(buf_tmp, 16, &result)) {
				I("%s: read_Step = %lu\n", __func__, result);
				setFlashReadStep(result);
			}
		}
	/* 1_60,1_64,1_24,1_28 for flash size 60k,64k,124k,128k*/
	} else if (buf[0] == '1') {

		setSysOperation(1);
		setFlashCommand(1);
		setFlashDumpProgress(0);
		setFlashDumpComplete(0);
		setFlashDumpFail(0);
		if ((buf[1] == '_') && (buf[2] == '6')) {
			if (buf[3] == '0')
				Flash_Size = FW_SIZE_60k;
			else if (buf[3] == '4')
				Flash_Size = FW_SIZE_64k;

		} else if ((buf[1] == '_') && (buf[2] == '2')) {
			if (buf[3] == '4')
				Flash_Size = FW_SIZE_124k;
			else if (buf[3] == '8')
				Flash_Size = FW_SIZE_128k;
		}
		queue_work(private_ts->flash_wq, &private_ts->flash_work);
	/* 2_60,2_64,2_24,2_28 for flash size 60k,64k,124k,128k*/
	} else if (buf[0] == '2') {
		setSysOperation(1);
		setFlashCommand(2);
		setFlashDumpProgress(0);
		setFlashDumpComplete(0);
		setFlashDumpFail(0);
		if ((buf[1] == '_') && (buf[2] == '6')) {
			if (buf[3] == '0')
				Flash_Size = FW_SIZE_60k;
			else if (buf[3] == '4')
				Flash_Size = FW_SIZE_64k;

		} else if ((buf[1] == '_') && (buf[2] == '2')) {
			if (buf[3] == '4')
				Flash_Size = FW_SIZE_124k;
			else if (buf[3] == '8')
				Flash_Size = FW_SIZE_128k;

		}
		queue_work(private_ts->flash_wq, &private_ts->flash_work);
	} else if (buf[0] == '3') {
		setSysOperation(1);
		setFlashCommand(3);
		setFlashDumpProgress(0);
		setFlashDumpComplete(0);
		setFlashDumpFail(0);

		memcpy(buf_tmp, buf + 3, 2);
		if (!kstrtoul(buf_tmp, 16, &result))
			setFlashDumpSector(result);

		memcpy(buf_tmp, buf + 7, 2);
		if (!kstrtoul(buf_tmp, 16, &result))
			setFlashDumpPage(result);

		queue_work(private_ts->flash_wq, &private_ts->flash_work);
	} else if (buf[0] == '4') {
		I("%s: command 4 enter.\n", __func__);
		setSysOperation(1);
		setFlashCommand(4);
		setFlashDumpProgress(0);
		setFlashDumpComplete(0);
		setFlashDumpFail(0);

		memcpy(buf_tmp, buf + 3, 2);
		if (!kstrtoul(buf_tmp, 16, &result))
			setFlashDumpSector(result);
		else
			E("%s: command 4 , sector error.\n", __func__);
			return len;


		memcpy(buf_tmp, buf + 7, 2);
		if (!kstrtoul(buf_tmp, 16, &result))
			setFlashDumpPage(result);
		else
			E("%s: command 4 , page error.\n", __func__);
			return len;

		base = 11;

		I("=========Himax flash page buffer start=========\n");
		for (loop_i = 0 ; loop_i < 128 ; loop_i++) {
			memcpy(buf_tmp, buf + base, 2);
			if (!kstrtoul(buf_tmp, 16, &result)) {
				flash_buffer[loop_i] = result;
				I("%d ", flash_buffer[loop_i]);
				if (loop_i % 16 == 15)
					I("\n");
			}
			base += 3;
		}
		I("=========Himax flash page buffer end=========\n");

		queue_work(private_ts->flash_wq, &private_ts->flash_work);
	}
	return len;
}

const struct file_operations himax_proc_flash_ops = {
	.owner = THIS_MODULE,
	.read = himax_proc_flash_read,
	.write = himax_proc_flash_write,
};

void himax_ts_flash_func(void)
{
	uint8_t local_flash_command = 0;

	himax_int_enable(private_ts->client->irq, 0);
	setFlashDumpGoing(true);

	/*sector = getFlashDumpSector();*/
	/*page = getFlashDumpPage();*/

	local_flash_command = getFlashCommand();

	msleep(100);

	I("%s: local_flash_command = %d enter.\n",
	__func__, local_flash_command);

	if ((local_flash_command == 1 || local_flash_command == 2)
		|| (local_flash_command == 0x0F)) {
		himax_flash_dump_func(private_ts->client,
		local_flash_command, Flash_Size, flash_buffer);
	}


	I("Complete~~~~~~~~~~~~~~~~~~~~~~~\n");

	if (local_flash_command == 2) {
		struct file *fn;
		struct filename *vts_name;

		vts_name = getname_kernel(FLASH_DUMP_FILE);
		fn = file_open_name(vts_name, O_CREAT | O_WRONLY, 0);
		if (!IS_ERR(fn)) {
			I("%s create file and ready to write\n", __func__);
			fn->f_op->write(fn, flash_buffer,
			Flash_Size * sizeof(uint8_t), &fn->f_pos);

			filp_close(fn, NULL);
		}
	}

	himax_int_enable(private_ts->client->irq, 1);
	setFlashDumpGoing(false);

	setFlashDumpComplete(1);
	setSysOperation(0);
	return;

/*	Flash_Dump_i2c_transfer_error:

	himax_int_enable(private_ts->client->irq, 1);
	setFlashDumpGoing(false);
	setFlashDumpComplete(0);
	setFlashDumpFail(1);
	setSysOperation(0);
	return;
*/
}

#endif

#ifdef HX_TP_PROC_SELF_TEST
static ssize_t himax_self_test_read(struct file *file, char *buf,
	size_t len, loff_t *pos)
{
	int val = 0x00;
	int ret = 0;
	char *temp_buf;

	I("%s:enter, %d\n", __func__, __LINE__);
	if (!HX_PROC_SEND_FLAG) {
		temp_buf = kzalloc(len, GFP_KERNEL);
		himax_int_enable(private_ts->client->irq, 0);/*disable irq*/
		val = himax_chip_self_test(private_ts->client);
#ifdef HX_ESD_WORKAROUND
		HX_ESD_RESET_ACTIVATE = 1;
#endif
		himax_int_enable(private_ts->client->irq, 1);/*enable irq*/

		if (val == 0x01) {
			ret += snprintf(temp_buf + ret, len,
			"Self_Test Pass\n");
		} else {
			ret += snprintf(temp_buf + ret, len,
			"Self_Test Fail\n");
		}
		if (copy_to_user(buf, temp_buf, len))
			I("%s,here:%d\n", __func__, __LINE__);

		kfree(temp_buf);
		HX_PROC_SEND_FLAG = 1;
	} else
		HX_PROC_SEND_FLAG = 0;
	return ret;
}

/*
static ssize_t himax_chip_self_test_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
	char buf_tmp[2];
	unsigned long result = 0;

	memset(buf_tmp, 0x0, sizeof(buf_tmp));
	memcpy(buf_tmp, buf, 2);
	if (!kstrtoul(buf_tmp, 16, &result))
		{
			sel_type = (uint8_t)result;
		}
	I("sel_type = %x \r\n", sel_type);
	return count;
}
*/

const struct file_operations himax_proc_self_test_ops = {
	.owner = THIS_MODULE,
	.read = himax_self_test_read,
};
#endif

#ifdef HX_TP_PROC_SENSE_ON_OFF
static ssize_t himax_sense_on_off_write(struct file *file, const char *buff,
	size_t len, loff_t *pos)
{
	char buf[80] = {0};

	if (len >= 80) {
		I("%s: no command exceeds 80 chars.\n", __func__);
		return -EFAULT;
	}
	if (copy_from_user(buf, buff, len))
		return -EFAULT;

	if (buf[0] == '0') {
		himax_sense_off(private_ts->client);
		I("Sense off\n");
	} else if (buf[0] == '1') {
		if (buf[1] == '1') {
			himax_sense_on(private_ts->client, 0x01);
			I("Sense on re-map off, run flash\n");
		} else if (buf[1] == '0') {
			himax_sense_on(private_ts->client, 0x00);
			I("Sense on re-map on, run sram\n");
		} else {
			I("Do nothing\n");
		}
	} else {
		I("Do nothing\n");
	}
	return len;
}

const struct file_operations himax_proc_sense_on_off_ops = {
	.owner = THIS_MODULE,
	.write = himax_sense_on_off_write,
};
#endif

#ifdef HX_HIGH_SENSE
static ssize_t himax_HSEN_read(struct file *file, char *buf,
	size_t len, loff_t *pos)
{
	struct himax_ts_data *ts = private_ts;
	size_t count = 0;
	char *temp_buf;

	if (!HX_PROC_SEND_FLAG) {
		temp_buf = kzalloc(len, GFP_KERNEL);
		count = snprintf(temp_buf, len, "%d\n", ts->HSEN_enable);
		HX_PROC_SEND_FLAG = 1;

		if (copy_to_user(buf, temp_buf, len))
			I("%s,here:%d\n", __func__, __LINE__);


		kfree(temp_buf);
	} else
		HX_PROC_SEND_FLAG = 0;
	return count;
}

static ssize_t himax_HSEN_write(struct file *file, const char *buff,
	size_t len, loff_t *pos)
{
	struct himax_ts_data *ts = private_ts;
	char buf[80] = {0};


	if (len >= 80) {
		I("%s: no command exceeds 80 chars.\n", __func__);
		return -EFAULT;
	}
	if (copy_from_user(buf, buff, len))
		return -EFAULT;

	if (buf[0] == '0')
		ts->HSEN_enable = 0;
	else if (buf[0] == '1')
		ts->HSEN_enable = 1;
	else
		return -EINVAL;

	himax_set_HSEN_func(ts->client, ts->HSEN_enable);

	I("%s: HSEN_enable = %d.\n", __func__, ts->HSEN_enable);

	return len;
}

const struct file_operations himax_proc_HSEN_ops = {
	.owner = THIS_MODULE,
	.read = himax_HSEN_read,
	.write = himax_HSEN_write,
};
#endif

#ifdef HX_SMART_WAKEUP
static ssize_t himax_SMWP_read(struct file *file, char *buf,
	size_t len, loff_t *pos)
{
	size_t count = 0;
	struct himax_ts_data *ts = private_ts;
	char *temp_buf;

	if (!HX_PROC_SEND_FLAG) {
		temp_buf = kzalloc(len, GFP_KERNEL);
		count = snprintf(temp_buf, "%d\n", len, ts->SMWP_enable);

		if (copy_to_user(buf, temp_buf, len))
			I("%s,here:%d\n", __func__, __LINE__);

		kfree(temp_buf);
		HX_PROC_SEND_FLAG = 1;
	} else
		HX_PROC_SEND_FLAG = 0;

	return count;
}

static ssize_t himax_SMWP_write(struct file *file, const char *buff,
	size_t len, loff_t *pos)
{
	struct himax_ts_data *ts = private_ts;
	char buf[80] = {0};

	if (len >= 80) {
		I("%s: no command exceeds 80 chars.\n", __func__);
		return -EFAULT;
	}
	if (copy_from_user(buf, buff, len))
		return -EFAULT;

	if (buf[0] == '0')
		ts->SMWP_enable = 0;
	else if (buf[0] == '1')
		ts->SMWP_enable = 1;
	else
		return -EINVAL;

	himax_set_SMWP_func(ts->client, ts->SMWP_enable);
	HX_SMWP_EN = ts->SMWP_enable;
	I("%s: SMART_WAKEUP_enable = %d.\n", __func__, HX_SMWP_EN);

	return len;
}

const struct file_operations himax_proc_SMWP_ops = {
	.owner = THIS_MODULE,
	.read = himax_SMWP_read,
	.write = himax_SMWP_write,
};

static ssize_t himax_GESTURE_read(struct file *file,
char *buf, size_t len, loff_t *pos)
{
	struct himax_ts_data *ts = private_ts;
	int i = 0;
	int ret = 0;
	char *temp_buf;

	if (!HX_PROC_SEND_FLAG) {
		temp_buf = kzalloc(len, GFP_KERNEL);
		for (i = 0 ; i < 16 ; i++)
			ret += snprintf(temp_buf + ret, len,
			"ges_en[%d]=%d\n", i, ts->gesture_cust_en[i]);

		HX_PROC_SEND_FLAG = 1;
		if (copy_to_user(buf, temp_buf, len))
			I("%s,here:%d\n", __func__, __LINE__);

		kfree(temp_buf);
		HX_PROC_SEND_FLAG = 1;
	} else {
		HX_PROC_SEND_FLAG = 0;
		ret = 0;
	}
	return ret;
}

static ssize_t himax_GESTURE_write(struct file *file, const char *buff,
	size_t len, loff_t *pos)
{
	struct himax_ts_data *ts = private_ts;
	int i = 0;
	char buf[80] = {0};

	if (len >= 80) {
		I("%s: no command exceeds 80 chars.\n", __func__);
		return -EFAULT;
	}
	if (copy_from_user(buf, buff, len))
		return -EFAULT;

	I("himax_GESTURE_store= %s\n", buf);
	for (i = 0 ; i < 16 ; i++) {
		if (buf[i] == '0')
			ts->gesture_cust_en[i] = 0;
		else if (buf[i] == '1')
			ts->gesture_cust_en[i] = 1;
		else
			ts->gesture_cust_en[i] = 0;
		I("gesture en[%d]=%d\n", i, ts->gesture_cust_en[i]);
	}
	return len;
}

const struct file_operations himax_proc_Gesture_ops = {
	.owner = THIS_MODULE,
	.read = himax_GESTURE_read,
	.write = himax_GESTURE_write,
};
#endif

int himax_touch_proc_init(void)
{
	himax_touch_proc_dir = proc_mkdir(HIMAX_PROC_TOUCH_FOLDER, NULL);
	if (himax_touch_proc_dir == NULL) {
		E(" %s: himax_touch_proc_dir file create failed!\n", __func__);
		return -ENOMEM;
	}

	himax_proc_debug_level_file = proc_create(HIMAX_PROC_DEBUG_LEVEL_FILE,
	(S_IWUSR | S_IRUGO), himax_touch_proc_dir, &himax_proc_debug_level_ops);

	if (himax_proc_debug_level_file == NULL) {
		E(" %s: proc debug_level file create failed!\n", __func__);
		goto fail_1;
	}

	himax_proc_vendor_file = proc_create(HIMAX_PROC_VENDOR_FILE,
	(S_IRUGO), himax_touch_proc_dir, &himax_proc_vendor_ops);

	if (himax_proc_vendor_file == NULL) {
		E(" %s: proc vendor file create failed!\n", __func__);
		goto fail_2;
	}

	himax_proc_attn_file = proc_create(HIMAX_PROC_ATTN_FILE,
	(S_IRUGO), himax_touch_proc_dir, &himax_proc_attn_ops);

	if (himax_proc_attn_file == NULL) {
		E(" %s: proc attn file create failed!\n", __func__);
		goto fail_3;
	}

	himax_proc_int_en_file = proc_create(HIMAX_PROC_INT_EN_FILE,
	(S_IWUSR | S_IRUGO), himax_touch_proc_dir, &himax_proc_int_en_ops);

	if (himax_proc_int_en_file == NULL) {
		E(" %s: proc int en file create failed!\n", __func__);
		goto fail_4;
	}

	himax_proc_layout_file = proc_create(HIMAX_PROC_LAYOUT_FILE,
	(S_IWUSR | S_IRUGO), himax_touch_proc_dir, &himax_proc_layout_ops);

	if (himax_proc_layout_file == NULL) {
		E(" %s: proc layout file create failed!\n", __func__);
		goto fail_5;
	}

#ifdef HX_TP_PROC_RESET
	himax_proc_reset_file = proc_create(HIMAX_PROC_RESET_FILE,
	(S_IWUSR), himax_touch_proc_dir, &himax_proc_reset_ops);

	if (himax_proc_reset_file == NULL) {
		E(" %s: proc reset file create failed!\n", __func__);
		goto fail_6;
	}
#endif

#ifdef HX_TP_PROC_DIAG
	himax_proc_diag_file = proc_create(HIMAX_PROC_DIAG_FILE,
	(S_IWUSR | S_IRUGO), himax_touch_proc_dir, &himax_proc_diag_ops);

	if (himax_proc_diag_file == NULL) {
		E(" %s: proc diag file create failed!\n", __func__);
		goto fail_7;
	}
	himax_proc_diag_arrange_file = proc_create(HIMAX_PROC_DIAG_ARR_FILE,
	(S_IWUSR | S_IRUGO),
	himax_touch_proc_dir, &himax_proc_diag_arrange_ops);

	if (himax_proc_diag_arrange_file == NULL) {
		E(" %s: proc diag file create failed!\n", __func__);
		goto fail_7_1;
	}
#endif

#ifdef HX_TP_PROC_REGISTER
	himax_proc_register_file = proc_create(HIMAX_PROC_REGISTER_FILE,
	(S_IWUSR | S_IRUGO), himax_touch_proc_dir, &himax_proc_register_ops);

	if (himax_proc_register_file == NULL) {
		E(" %s: proc register file create failed!\n", __func__);
		goto fail_8;
	}
#endif

#ifdef HX_TP_PROC_DEBUG
	himax_proc_debug_file = proc_create(HIMAX_PROC_DEBUG_FILE,
	(S_IWUSR | S_IRUGO), himax_touch_proc_dir, &himax_proc_debug_ops);

	if (himax_proc_debug_file == NULL) {
		E(" %s: proc debug file create failed!\n", __func__);
		goto fail_9;
	}
#endif

#ifdef HX_TP_PROC_FLASH_DUMP
	himax_proc_flash_dump_file = proc_create(HIMAX_PROC_FLASH_DUMP_FILE,
	(S_IWUSR | S_IRUGO), himax_touch_proc_dir, &himax_proc_flash_ops);

	if (himax_proc_flash_dump_file == NULL) {
		E(" %s: proc flash dump file create failed!\n", __func__);
		goto fail_10;
	}
#endif

#ifdef HX_TP_PROC_SELF_TEST
	himax_proc_self_test_file = proc_create(HIMAX_PROC_SELF_TEST_FILE,
	(S_IRUGO), himax_touch_proc_dir, &himax_proc_self_test_ops);

	if (himax_proc_self_test_file == NULL) {
		E(" %s: proc self_test file create failed!\n", __func__);
		goto fail_11;
	}
#endif

#ifdef HX_HIGH_SENSE
	himax_proc_HSEN_file = proc_create(HIMAX_PROC_HSEN_FILE,
	(S_IWUSR | S_IRUGO | S_IWUGO),
	himax_touch_proc_dir, &himax_proc_HSEN_ops);

	if (himax_proc_HSEN_file == NULL) {
		E(" %s: proc HSEN file create failed!\n", __func__);
		goto fail_12;
	}
#endif

#ifdef HX_SMART_WAKEUP
	himax_proc_SMWP_file = proc_create(HIMAX_PROC_SMWP_FILE,
	(S_IWUSR | S_IRUGO | S_IWUGO),
	himax_touch_proc_dir, &himax_proc_SMWP_ops);

	if (himax_proc_SMWP_file == NULL) {
		E(" %s: proc SMWP file create failed!\n", __func__);
		goto fail_13;
	}

	himax_proc_GESTURE_file = proc_create(HIMAX_PROC_GESTURE_FILE,
	(S_IWUSR | S_IRUGO | S_IWUGO),
	himax_touch_proc_dir, &himax_proc_Gesture_ops);

	if (himax_proc_GESTURE_file == NULL) {
		E(" %s: proc GESTURE file create failed!\n", __func__);
		goto fail_14;
	}
#endif

#ifdef HX_TP_PROC_SENSE_ON_OFF
	himax_proc_SENSE_ON_OFF_file = proc_create(HIMAX_PROC_SENSE_ON_OFF_FILE,
	(S_IWUSR | S_IRUGO | S_IWUGO),
	himax_touch_proc_dir, &himax_proc_sense_on_off_ops);

	if (himax_proc_SENSE_ON_OFF_file == NULL) {
		E(" %s: proc SENSE_ON_OFF file create failed!\n", __func__);
		goto fail_15;
	}
#endif

	return 0;

#ifdef HX_TP_PROC_SENSE_ON_OFF
fail_15:
#endif
#ifdef HX_SMART_WAKEUP
	remove_proc_entry(HIMAX_PROC_GESTURE_FILE, himax_touch_proc_dir);
fail_14:
	remove_proc_entry(HIMAX_PROC_SMWP_FILE, himax_touch_proc_dir);
fail_13:
#endif
#ifdef HX_HIGH_SENSE
	remove_proc_entry(HIMAX_PROC_HSEN_FILE, himax_touch_proc_dir);
fail_12:
#endif
#ifdef HX_TP_PROC_SELF_TEST
	remove_proc_entry(HIMAX_PROC_SELF_TEST_FILE, himax_touch_proc_dir);
fail_11:
#endif
#ifdef HX_TP_PROC_FLASH_DUMP
	remove_proc_entry(HIMAX_PROC_FLASH_DUMP_FILE, himax_touch_proc_dir);
fail_10:
#endif
#ifdef HX_TP_PROC_DEBUG
	remove_proc_entry(HIMAX_PROC_DEBUG_FILE, himax_touch_proc_dir);
fail_9:
#endif
#ifdef HX_TP_PROC_REGISTER
	remove_proc_entry(HIMAX_PROC_REGISTER_FILE, himax_touch_proc_dir);
fail_8:
#endif
#ifdef HX_TP_PROC_DIAG
	remove_proc_entry(HIMAX_PROC_DIAG_FILE, himax_touch_proc_dir);
fail_7:
	remove_proc_entry(HIMAX_PROC_DIAG_ARR_FILE, himax_touch_proc_dir);
fail_7_1:
#endif
#ifdef HX_TP_PROC_RESET
	remove_proc_entry(HIMAX_PROC_RESET_FILE, himax_touch_proc_dir);
fail_6:
#endif
	remove_proc_entry(HIMAX_PROC_LAYOUT_FILE, himax_touch_proc_dir);
fail_5: remove_proc_entry(HIMAX_PROC_INT_EN_FILE, himax_touch_proc_dir);
fail_4: remove_proc_entry(HIMAX_PROC_ATTN_FILE, himax_touch_proc_dir);
fail_3: remove_proc_entry(HIMAX_PROC_VENDOR_FILE, himax_touch_proc_dir);
fail_2: remove_proc_entry(HIMAX_PROC_DEBUG_LEVEL_FILE, himax_touch_proc_dir);
fail_1: remove_proc_entry(HIMAX_PROC_TOUCH_FOLDER, NULL);
	return -ENOMEM;
}

void himax_touch_proc_deinit(void)
{
#ifdef HX_TP_PROC_SENSE_ON_OFF
	remove_proc_entry(HIMAX_PROC_SENSE_ON_OFF_FILE, himax_touch_proc_dir);
#endif
#ifdef HX_SMART_WAKEUP
	remove_proc_entry(HIMAX_PROC_GESTURE_FILE, himax_touch_proc_dir);
	remove_proc_entry(HIMAX_PROC_SMWP_FILE, himax_touch_proc_dir);
#endif
#ifdef HX_DOT_VIEW
	remove_proc_entry(HIMAX_PROC_HSEN_FILE, himax_touch_proc_dir);
#endif
#ifdef HX_TP_PROC_SELF_TEST
	remove_proc_entry(HIMAX_PROC_SELF_TEST_FILE, himax_touch_proc_dir);
#endif
#ifdef HX_TP_PROC_FLASH_DUMP
	remove_proc_entry(HIMAX_PROC_FLASH_DUMP_FILE, himax_touch_proc_dir);
#endif
#ifdef HX_TP_PROC_DEBUG
	remove_proc_entry(HIMAX_PROC_DEBUG_FILE, himax_touch_proc_dir);
#endif
#ifdef HX_TP_PROC_REGISTER
	remove_proc_entry(HIMAX_PROC_REGISTER_FILE, himax_touch_proc_dir);
#endif
#ifdef HX_TP_PROC_DIAG
	remove_proc_entry(HIMAX_PROC_DIAG_FILE, himax_touch_proc_dir);
#endif
#ifdef HX_TP_PROC_RESET
	remove_proc_entry(HIMAX_PROC_RESET_FILE, himax_touch_proc_dir);
#endif
	remove_proc_entry(HIMAX_PROC_LAYOUT_FILE, himax_touch_proc_dir);
	remove_proc_entry(HIMAX_PROC_INT_EN_FILE, himax_touch_proc_dir);
	remove_proc_entry(HIMAX_PROC_ATTN_FILE, himax_touch_proc_dir);
	remove_proc_entry(HIMAX_PROC_VENDOR_FILE, himax_touch_proc_dir);
	remove_proc_entry(HIMAX_PROC_DEBUG_LEVEL_FILE, himax_touch_proc_dir);
	remove_proc_entry(HIMAX_PROC_TOUCH_FOLDER, NULL);
}
#endif
