/* raydium_driver.c
 *
 * Raydium TouchScreen driver.
 *
 * Copyright (c) 2021  Raydium tech Ltd.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 */

#include <linux/i2c.h>
#include <linux/input.h>
#include <linux/input/mt.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/mutex.h>
#include <linux/module.h>
#include <linux/gpio.h>
#include <linux/unistd.h>
#include <linux/uaccess.h>
#include <linux/string.h>
#include <linux/timer.h>
#include <linux/regulator/consumer.h>
#include <linux/device.h>
#include <linux/kprobes.h>
#include <asm/traps.h>
#include <linux/firmware.h>
#include <linux/of_gpio.h>
#include <linux/err.h>
#include <linux/of_device.h>
#include "raydium_driver.h"
#include <glink_interface.h>
#include <linux/remoteproc/qcom_rproc.h>
#if defined(CONFIG_FB)
#include <linux/notifier.h>
#include <linux/fb.h>
#elif defined(CONFIG_HAS_EARLYSUSPEND)
#include <linux/earlysuspend.h>
#endif /*end of CONFIG_FB*/
#if defined(CONFIG_PANEL_NOTIFIER)
#include <linux/soc/qcom/panel_event_notifier.h>
#endif

struct raydium_slot_status {
	unsigned char pt_id;      /*Occupied point ID*/
	unsigned char need_update;         /*Mark as info need to be updated*/
	unsigned char pt_report_offset;    /*point info offset in report*/
};
/*The first 3 elements are currently occupied. therest is new coming points*/
struct raydium_slot_status gst_slot[MAX_TOUCH_NUM * 2];
struct raydium_slot_status gst_slot_init = {0xFF, 0, 0};

static int raydium_enable_regulator(struct raydium_ts_data *cd, bool en);

#if (defined(CONFIG_RM_SYSFS_DEBUG))
const struct attribute_group raydium_attr_group;
#endif /*end of CONFIG_RM_SYSFS_DEBUG*/

#if defined(CONFIG_DRM) || defined(CONFIG_PANEL_NOTIFIER)
	static struct drm_panel *active_panel;
#endif

unsigned char g_u8_addr;
unsigned char g_u8_raydium_flag;
unsigned char g_u8_i2c_mode;
unsigned char g_u8_upgrade_type;
unsigned char g_u8_raw_data_type;
unsigned int g_u32_raw_data_len;    /* 128 bytes*/
unsigned long g_u32_addr;
unsigned int g_u32_length;
unsigned int g_u32_driver_version;
unsigned char *g_rad_fw_image, *g_rad_init_image;
unsigned char *g_rad_boot_image, *g_rad_para_image;
unsigned char *g_rad_testfw_image, *g_rad_testpara_image;
unsigned char g_u8_table_setting, g_u8_table_init;
unsigned char g_u8_resetflag;
unsigned char g_u8_wakeup_flag;
#ifdef ESD_SOLUTION_EN
unsigned char g_u8_checkflag;
#endif
unsigned char g_u8_log_level;
struct raydium_ts_data *g_raydium_ts;

/*******************************************************************************
 *  Name: raydium_variable_init
 *  Brief:
 *  Input:
 *  Output:
 *  Return:
 *******************************************************************************/
static void raydium_variable_init(void)
{
	g_u8_addr = RAYDIUM_PDA2_PDA_CFG_ADDR;
	g_u8_raydium_flag = NORMAL_MODE;
	g_u8_i2c_mode = PDA2_MODE;
	g_u8_upgrade_type = 0;
	g_u8_raw_data_type = RAYDIUM_FT_UPDATE;
	g_u32_raw_data_len = 64 * 2;    /* 128 bytes*/
	g_u32_addr = RAYDIUM_CHK_I2C_CMD;
	g_u32_length = 1;
	g_u8_table_setting = 0;
	g_u8_table_init = 0;
	g_rad_fw_image = NULL;
	g_rad_init_image = NULL;
	g_rad_boot_image = NULL;
	g_rad_para_image = NULL;
	g_rad_testfw_image = NULL;
	g_rad_testpara_image = NULL;
	g_u32_driver_version = ((RAD_MAIN_VERSION <<  24) |
				(RAD_MINOR_VERSION << 16) |
				(RAD_CUSTOMER_VERSION));
	g_u8_resetflag = false;
	g_u8_wakeup_flag = false;
#ifdef ESD_SOLUTION_EN
	g_u8_checkflag = false;
#endif
	g_u8_log_level = LOG_INFO;
}


/*******************************************************************************
 *  Name: raydium_gpio_configure
 *  Brief:
 *  Input:
 *  Output:
 *  Return:
 *******************************************************************************/

static int raydium_gpio_configure(bool on)
{
	int i32_err = 0;

	if (on) {
		if (gpio_is_valid(g_raydium_ts->irq_gpio)) {
			i32_err = gpio_request(g_raydium_ts->irq_gpio,
					       "raydium_irq_gpio");
			if (i32_err) {
				LOGD(LOG_ERR, "[touch]irq gpio request failed");
				goto err_irq_gpio_req;
			}

			i32_err = gpio_direction_input(g_raydium_ts->irq_gpio);
			if (i32_err) {
				LOGD(LOG_ERR, "[touch]set_direction for irq gpio failed\n");
				goto err_irq_gpio_dir;
			}
		}
		if (gpio_is_valid(g_raydium_ts->rst_gpio)) {
			i32_err = gpio_request(g_raydium_ts->rst_gpio,
					       "raydium_rst_gpio");
			if (i32_err) {
				LOGD(LOG_ERR,  "[touch]rst gpio request failed");
				goto err_irq_gpio_req;
			}

			i32_err = gpio_direction_output(g_raydium_ts->rst_gpio, 0);
			msleep(RAYDIUM_RESET_INTERVAL_10MSEC);
			if (i32_err) {
				LOGD(LOG_ERR,
				     "[touch]set_direction for rst gpio failed\n");
				goto err_rst_gpio_dir;
			}

			i32_err = gpio_direction_output(g_raydium_ts->rst_gpio, 1);
			if (i32_err) {
				LOGD(LOG_ERR,
				     "[touch]set_direction for irq gpio failed\n");
				goto err_rst_gpio_dir;
			}
		}
	} else {
		if (gpio_is_valid(g_raydium_ts->irq_gpio))
			gpio_free(g_raydium_ts->irq_gpio);
	}
	return 0;
err_rst_gpio_dir:
	if (gpio_is_valid(g_raydium_ts->rst_gpio))
		gpio_free(g_raydium_ts->rst_gpio);
	return i32_err;
err_irq_gpio_dir:
	if (gpio_is_valid(g_raydium_ts->irq_gpio))
		gpio_free(g_raydium_ts->irq_gpio);
err_irq_gpio_req:
	return i32_err;
}

/*******************************************************************************
 *  Name: raydium_ts_pinctrl_init
 *  Brief:
 *  Input:
 *  Output:
 *  Return:
 *******************************************************************************/
#ifdef MSM_NEW_VER
static int raydium_ts_pinctrl_init(void)
{
	int i32_ret;

	/* Get pinctrl if target uses pinctrl */
	g_raydium_ts->ts_pinctrl = devm_pinctrl_get(&(g_raydium_ts->client->dev));
	if (IS_ERR_OR_NULL(g_raydium_ts->ts_pinctrl)) {
		i32_ret = PTR_ERR(g_raydium_ts->ts_pinctrl);
		LOGD(LOG_ERR, "[touch]target does not use pinctrl %d\n", i32_ret);
		goto err_pinctrl_get;
	}

	g_raydium_ts->pinctrl_state_active
		= pinctrl_lookup_state(g_raydium_ts->ts_pinctrl, PINCTRL_STATE_ACTIVE);
	if (IS_ERR_OR_NULL(g_raydium_ts->pinctrl_state_active)) {
		i32_ret = PTR_ERR(g_raydium_ts->pinctrl_state_active);
		LOGD(LOG_ERR, "[touch]Can not lookup %s pinstate %d\n",
		     PINCTRL_STATE_ACTIVE, i32_ret);
		goto err_pinctrl_lookup;
	}

	g_raydium_ts->pinctrl_state_suspend
		= pinctrl_lookup_state(g_raydium_ts->ts_pinctrl,
				       PINCTRL_STATE_SUSPEND);
	if (IS_ERR_OR_NULL(g_raydium_ts->pinctrl_state_suspend)) {
		i32_ret = PTR_ERR(g_raydium_ts->pinctrl_state_suspend);
		LOGD(LOG_ERR, "[touch]Can not lookup %s pinstate %d\n",
		     PINCTRL_STATE_SUSPEND, i32_ret);
		goto err_pinctrl_lookup;
	}

	g_raydium_ts->pinctrl_state_release
		= pinctrl_lookup_state(g_raydium_ts->ts_pinctrl,
				       PINCTRL_STATE_RELEASE);
	if (IS_ERR_OR_NULL(g_raydium_ts->pinctrl_state_release)) {
		i32_ret = PTR_ERR(g_raydium_ts->pinctrl_state_release);
		LOGD(LOG_ERR, "[touch]Can not lookup %s pinstate %d\n",
		     PINCTRL_STATE_RELEASE, i32_ret);
	}

	return 0;

err_pinctrl_lookup:
	devm_pinctrl_put(g_raydium_ts->ts_pinctrl);
err_pinctrl_get:
	g_raydium_ts->ts_pinctrl = NULL;
	return i32_ret;
}
#endif/*end of MSM_NEW_VER*/
#ifdef ESD_SOLUTION_EN
static int raydium_hw_reset_fun(struct i2c_client *client)
{
	int i32_ret = SUCCESS;

	LOGD(LOG_INFO, "[touch]HW reset\n");
	g_u8_raydium_flag |= ENG_MODE;

	g_u8_resetflag = true;
	/*HW reset*/
	gpio_set_value(g_raydium_ts->rst_gpio, 1);
	gpio_set_value(g_raydium_ts->rst_gpio, 0);
	msleep(RAYDIUM_RESET_INTERVAL_MSEC);
	gpio_set_value(g_raydium_ts->rst_gpio, 1);

	g_u8_i2c_mode = PDA2_MODE;

	i32_ret = wait_irq_state(client, 300, 2000);
	if (i32_ret != ERROR)
		msleep(35);

	g_u8_raydium_flag &= ~ENG_MODE;

	LOGD(LOG_INFO, "[touch]Raydium HW reset : %d\n", i32_ret);
	return i32_ret;
}
#endif

int raydium_i2c_write_pda_via_pda2(struct i2c_client *client,
				   unsigned int u32_addr, unsigned char *u8_w_data,
				   unsigned short u16_length)
{
	int i32_ret = -1;
	/*unsigned char u8_retry;*/
	unsigned char u8_mode = 0x00;
	unsigned char u8_buf[MAX_WRITE_PACKET_SIZE + 6];

	struct i2c_msg msg[] = {
		{
			.addr = RAYDIUM_I2C_NID,
			.flags = RAYDIUM_I2C_WRITE,
			.len = u16_length + 6,
			.buf = u8_buf,
		},
	};
	if (u16_length > MAX_WRITE_PACKET_SIZE)
		return -EINVAL;


	/*I2C access for register need to word mode*/

	if ((u16_length == 4) &&
	    ((u32_addr & 0x50000000) || (u32_addr & 0x40000000)))
		u8_mode = I2C_PDA2_WORD_MODE;
	else
		u8_mode = I2C_PDA2_BYTE_MODE;

	if (u16_length > MAX_WRITE_PACKET_SIZE)
		return -EINVAL;
	g_u8_i2c_mode = PDA2_MODE;

	u8_buf[0] = RAYDIUM_I2C_PDA_CMD;
	u8_buf[1] = (unsigned char)u32_addr;
	u8_buf[2] = (unsigned char)(u32_addr >> 8);
	u8_buf[3] = (unsigned char)(u32_addr >> 16);
	u8_buf[4] = (unsigned char)(u32_addr >> 24);
	u8_buf[5] = u8_mode;

	memcpy(&u8_buf[6], u8_w_data, u16_length);

	/*for (u8_retry = 0; u8_retry < SYN_I2C_RETRY_TIMES; u8_retry++) {*/
	if (i2c_transfer(client->adapter, msg, 1) == 1) {
		i32_ret = u16_length;
		/*break;*/
	}
	i32_ret = u16_length;
	/*usleep_range(500, 1500);*/
	/*}*/

	/*if (u8_retry == SYN_I2C_RETRY_TIMES) {*/
	/*	LOGD(LOG_ERR, "[touch]%s: I2C write over retry limit\n", __func__);*/
	/*	i32_ret = -EIO;*/
	/*}*/

	return i32_ret;

}
int raydium_i2c_read_pda_via_pda2(struct i2c_client *client,
				  unsigned int u32_addr, unsigned char *u8_r_data,
				  unsigned short u16_length)
{
	int i32_ret;
	/*unsigned char u8_retry;*/
	unsigned char u8_mode = 0x00;
	unsigned char u8_buf[6];

	struct i2c_msg msg[] = {
		{
			.addr = RAYDIUM_I2C_NID,
			.flags = RAYDIUM_I2C_WRITE,
			.len = 6,
			.buf = u8_buf,
		},
		{
			.addr = RAYDIUM_I2C_NID,
			.flags = RAYDIUM_I2C_READ,
			.len = u16_length,
			.buf = u8_r_data,
		},
	};

	if ((u32_addr & 0x50000000) || (u32_addr & 0x40000000))
		u8_mode = I2C_PDA2_WORD_MODE;
	else
		u8_mode = I2C_PDA2_BYTE_MODE;

	g_u8_i2c_mode = PDA2_MODE;
	u8_buf[0] = RAYDIUM_I2C_PDA_CMD;
	u8_buf[1] = (unsigned char)u32_addr;
	u8_buf[2] = (unsigned char)(u32_addr >> 8);
	u8_buf[3] = (unsigned char)(u32_addr >> 16);
	u8_buf[4] = (unsigned char)(u32_addr >> 24);
	u8_buf[5] = u8_mode;

	/*for (u8_retry = 0; u8_retry < SYN_I2C_RETRY_TIMES; u8_retry++) {*/
	if (i2c_transfer(g_raydium_ts->client->adapter, msg, 2) == 2) {
		i32_ret = u16_length;
		/*break;*/
	}
	i32_ret = u16_length;
	/*usleep_range(500, 1500);*/
	/*}*/

	/*if (u8_retry == SYN_I2C_RETRY_TIMES) {*/
	/*	LOGD(LOG_ERR, "[touch]%s: I2C read over retry limit\n", __func__);*/
	/*	i32_ret = -EIO;*/
	/*}*/

	return i32_ret;
}
int raydium_i2c_pda_set_address(unsigned int u32_address,
				unsigned char u8_mode)
{
	int i32_ret = 0;
	unsigned char u8_retry;
	unsigned char u8_buf[RAD_I2C_PDA_ADDRESS_LENGTH];
	struct i2c_client *client = g_raydium_ts->client;

	client->addr = RAYDIUM_I2C_EID;
	u8_buf[0] = (u32_address & 0x0000FF00) >> 8;
	u8_buf[1] = (u32_address & 0x00FF0000) >> 16;
	u8_buf[2] = (u32_address & 0xFF000000) >> 24;
	u8_buf[3] = u8_mode;

	for (u8_retry = 0; u8_retry < SYN_I2C_RETRY_TIMES; u8_retry++) {
		i32_ret = i2c_master_send(client, u8_buf,
					  RAD_I2C_PDA_ADDRESS_LENGTH);
		if (i32_ret != RAD_I2C_PDA_ADDRESS_LENGTH) {
			LOGD(LOG_ERR, "[touch]%s: I2C retry %d\n",
			     __func__, u8_retry + 1);
			usleep_range(500, 1500);
		} else {
			break;
		}
	}

	return (i32_ret == RAD_I2C_PDA_ADDRESS_LENGTH) ? i32_ret : -EIO;
}

/*device attribute raydium_i2c_pda2_mode used*/
int raydium_i2c_pda_read(struct i2c_client *client,
			 unsigned int u32_addr, unsigned char *u8_r_data,
			 unsigned short u16_length)
{
	int i32_ret;
	unsigned char u8_retry;
	unsigned char u8_mode = 0x00;
	unsigned char u8_buf;

	struct i2c_msg msg[] = {
		{
			.addr = RAYDIUM_I2C_NID,
			.flags = RAYDIUM_I2C_WRITE,
			.len = 1,
			.buf = &u8_buf,
		},
		{
			.addr = RAYDIUM_I2C_NID,
			.flags = RAYDIUM_I2C_READ,
			.len = u16_length,
			.buf = u8_r_data,
		},
	};

	if (u16_length == 4)
		u8_mode |= RAD_I2C_PDA_MODE_ENABLE |
			   RAD_I2C_PDA_2_MODE_DISABLE |
			   RAD_I2C_PDA_MODE_WORD_MODE;
	else
		u8_mode |= RAD_I2C_PDA_MODE_ENABLE |
			   RAD_I2C_PDA_2_MODE_DISABLE;

	u8_mode |= 0x03;

	u8_buf = u32_addr & MASK_8BIT;

	i32_ret = raydium_i2c_pda_set_address(u32_addr, u8_mode);
	if (i32_ret != RAD_I2C_PDA_ADDRESS_LENGTH)
		goto exit;
	usleep_range(50, 80);

	for (u8_retry = 0; u8_retry < SYN_I2C_RETRY_TIMES; u8_retry++) {
		if (i2c_transfer(g_raydium_ts->client->adapter, msg, 2) == 2) {
			i32_ret = u16_length;
			break;
		}
		LOGD(LOG_ERR, "%s: I2C retry %d\n", __func__, u8_retry + 1);
		usleep_range(500, 1500);
	}

	if (u8_retry == SYN_I2C_RETRY_TIMES) {
		LOGD(LOG_ERR, "%s: I2C read over retry limit\n", __func__);
		i32_ret = -EIO;
	}
exit:
	return i32_ret;
}

int raydium_i2c_pda_write(struct i2c_client *client,
			  unsigned int u32_addr, unsigned char *u8_w_data,
			  unsigned short u16_length)
{
	int i32_ret;
	unsigned char u8_retry;
	unsigned char u8_mode = 0x00;
	unsigned char u8_buf[MAX_WRITE_PACKET_SIZE + 1];

	struct i2c_msg msg[] = {
		{
			.addr = RAYDIUM_I2C_NID,
			.flags = RAYDIUM_I2C_WRITE,
			.len = u16_length + 1,
			.buf = u8_buf,
		},
	};

	if (u16_length > MAX_WRITE_PACKET_SIZE)
		return -EINVAL;

	if (u16_length == 4)
		u8_mode |= RAD_I2C_PDA_MODE_ENABLE |
			   RAD_I2C_PDA_2_MODE_DISABLE |
			   RAD_I2C_PDA_MODE_WORD_MODE;
	else
		u8_mode |= RAD_I2C_PDA_MODE_ENABLE |
			   RAD_I2C_PDA_2_MODE_DISABLE;

	u8_buf[0] = u32_addr & MASK_8BIT;
	memcpy(&u8_buf[1], u8_w_data, u16_length);

	i32_ret = raydium_i2c_pda_set_address(u32_addr, u8_mode);
	if (i32_ret != RAD_I2C_PDA_ADDRESS_LENGTH)
		goto exit;
	usleep_range(50, 80);

	for (u8_retry = 0; u8_retry < SYN_I2C_RETRY_TIMES; u8_retry++) {
		if (i2c_transfer(client->adapter, msg, 1) == 1) {
			i32_ret = u16_length;
			break;
		}
		LOGD(LOG_ERR, "[touch]%s: I2C retry %d\n", __func__, u8_retry + 1);
		usleep_range(500, 1500);
	}

	if (u8_retry == SYN_I2C_RETRY_TIMES) {
		LOGD(LOG_ERR, "[touch]%s: I2C write over retry limit\n", __func__);
		i32_ret = -EIO;
	}
exit:
	return i32_ret;
}

int handle_i2c_pda_read(struct i2c_client *client,
			unsigned int u32_addr, unsigned char *u8_r_data,
			unsigned short u16_length)
{
	if ((g_u8_i2c_mode & PDA_MODE) != 0)  {
		if (raydium_i2c_pda_read(client, u32_addr, u8_r_data, u16_length) == ERROR) {
			LOGD(LOG_ERR, "[touch] handle_ic_write I2C NG!\r\n");
			return ERROR;
		}
	} else {
		if (raydium_i2c_read_pda_via_pda2(client, u32_addr, u8_r_data, u16_length) == ERROR) {
			LOGD(LOG_ERR, "[touch] handle_ic_write I2C via_pda2 NG!\r\n");
			return ERROR;
		}
	}
	return SUCCESS;
}

int handle_i2c_pda_write(struct i2c_client *client,
			 unsigned int u32_addr, unsigned char *u8_w_data,
			 unsigned short u16_length)
{
	if ((g_u8_i2c_mode & PDA_MODE) != 0)  {
		if (raydium_i2c_pda_write(client, u32_addr, u8_w_data, u16_length) == ERROR) {
			LOGD(LOG_ERR, "[touch] handle_ic_write I2C NG!\r\n");
			return ERROR;
		}
	} else {
		if (raydium_i2c_write_pda_via_pda2(client, u32_addr, u8_w_data, u16_length) == ERROR) {
			LOGD(LOG_ERR, "[touch] handle_ic_write I2C via_pda2 NG!\r\n");
			return ERROR;
		}
	}
	return SUCCESS;
}
int raydium_i2c_pda2_set_page(struct i2c_client *client,
			      unsigned int is_suspend,
			      unsigned char u8_page)
{
	int i32_ret = -1;
	unsigned char u8_retry;
	unsigned int u8_ret = (is_suspend) ? 10 : 2;
	unsigned char u8_buf[RAYDIUM_I2C_PDA2_PAGE_LENGTH];

	struct i2c_msg msg[] = {
		{
			.addr = RAYDIUM_I2C_NID,
			.flags = RAYDIUM_I2C_WRITE,
			.len = RAYDIUM_I2C_PDA2_PAGE_LENGTH,
			.buf = u8_buf,
		},
	};

	u8_buf[0] = RAYDIUM_PDA2_PAGE_ADDR;
	u8_buf[1] = u8_page;
	for (; u8_ret > 0; u8_ret--) {
		for (u8_retry = 0; u8_retry < SYN_I2C_RETRY_TIMES; u8_retry++) {
			if (i2c_transfer(client->adapter, msg, 1) == 1) {
				i32_ret = RAYDIUM_I2C_PDA2_PAGE_LENGTH;
				break;
			}
			usleep_range(500, 1500);
		}
		if (i32_ret == RAYDIUM_I2C_PDA2_PAGE_LENGTH)
			break;
		usleep_range(2000, 5000);
	}

	if (u8_ret == 0) {
		LOGD(LOG_ERR, "[touch]%s: I2C write over retry limit\n", __func__);
		i32_ret = -EIO;
	}

	return i32_ret;
}

int raydium_i2c_pda2_read(struct i2c_client *client,
			  unsigned char u8_addr,
			  unsigned char *u8_r_data,
			  unsigned short u16_length)
{
	int i32_ret = -1;
	unsigned char u8_retry;

	struct i2c_msg msg[] = {
		{
			.addr = RAYDIUM_I2C_NID,
			.flags = RAYDIUM_I2C_WRITE,
			.len = 1,
			.buf = &u8_addr,
		},
		{
			.addr = RAYDIUM_I2C_NID,
			.flags = RAYDIUM_I2C_READ,
			.len = u16_length,
			.buf = u8_r_data,
		},
	};
	g_u8_i2c_mode = PDA2_MODE;
	for (u8_retry = 0; u8_retry < SYN_I2C_RETRY_TIMES; u8_retry++) {
		if (i2c_transfer(g_raydium_ts->client->adapter, msg, 2) == 2) {
			i32_ret = u16_length;
			break;
		}
		usleep_range(500, 1500);
	}

	if (u8_retry == SYN_I2C_RETRY_TIMES) {
		LOGD(LOG_ERR, "[touch]%s: I2C read over retry limit\n", __func__);
		i32_ret = -EIO;
	}

	return i32_ret;
}

int raydium_i2c_pda2_write(struct i2c_client *client,
			   unsigned char u8_addr,
			   unsigned char *u8_w_data,
			   unsigned short u16_length)
{
	int i32_ret = -1;
	unsigned char u8_retry;
	unsigned char u8_buf[MAX_WRITE_PACKET_SIZE + 1];

	struct i2c_msg msg[] = {
		{
			.addr = RAYDIUM_I2C_NID,
			.flags = RAYDIUM_I2C_WRITE,
			.len = u16_length + 1,
			.buf = u8_buf,
		},
	};

	if (u16_length > MAX_WRITE_PACKET_SIZE)
		return -EINVAL;
	g_u8_i2c_mode = PDA2_MODE;
	u8_buf[0] = u8_addr;
	memcpy(&u8_buf[1], u8_w_data, u16_length);

	for (u8_retry = 0; u8_retry < SYN_I2C_RETRY_TIMES; u8_retry++) {
		if (i2c_transfer(client->adapter, msg, 1) == 1) {
			i32_ret = u16_length;
			break;
		}
		usleep_range(500, 1500);
	}

	if (u8_retry == SYN_I2C_RETRY_TIMES) {
		LOGD(LOG_ERR, "[touch]%s: I2C write over retry limit\n", __func__);
		i32_ret = -EIO;
	}

	return i32_ret;
}

void raydium_irq_control(bool enable)
{
	if (enable) {
		if (g_raydium_ts->irq_enabled) {
			/*mutex_unlock(&ts->lock);*/
			LOGD(LOG_INFO, "[touch]Already enable irq\n");
			return;
		}

		/* Clear interrupts first */
#if defined(CONFIG_PANEL_NOTIFIER)
		if (g_raydium_ts->blank != DRM_PANEL_EVENT_BLANK) {
#else
		if (g_raydium_ts->blank != DRM_PANEL_BLANK_POWERDOWN) {
#endif
			if (g_u8_i2c_mode == PDA2_MODE) {
				mutex_lock(&g_raydium_ts->lock);
				if (raydium_i2c_pda2_set_page(g_raydium_ts->client,
								g_raydium_ts->is_suspend,
								RAYDIUM_PDA2_PAGE_0) < 0)
					LOGD(LOG_ERR, "[touch]set page fail%s\n", __func__);
				mutex_unlock(&g_raydium_ts->lock);
				usleep_range(500, 1500);
			}
		}
		while (g_raydium_ts->irq_desc->depth > 0) {
			LOGD(LOG_INFO, "[touch]irq enable\n");
			g_raydium_ts->irq_enabled = true;
			enable_irq(g_raydium_ts->irq);
		}
	} else {
		if (g_raydium_ts->irq_enabled) {
			if (g_raydium_ts->irq_desc->depth == 0) {
				disable_irq(g_raydium_ts->irq);
				g_raydium_ts->irq_enabled = false;
				LOGD(LOG_INFO, "[touch]irq disable\n");
			}
		}
	}
}

unsigned char raydium_disable_i2c_deglitch(void)
{
	unsigned int u32_buf = 0;
	unsigned char u8_retry = 3, u8_comfirm_time = 3;
	unsigned char u8_check = 0, u8_i = 0;
	unsigned int u32_i2c_deglitch = 0x07060000;
	unsigned char u8_buf[4];

	while (u8_retry--) {
		u32_buf = 0;
		handle_i2c_pda_read(g_raydium_ts->client, RAYDIUM_CHK_I2C_CMD,
				    (unsigned char *)(&u32_buf), 4);
		if ((u32_buf & 0xFFFF0000) == 0xF3030000)
			u8_check++;
	}
	if (u8_check == 3) {
		LOGD(LOG_INFO, "[touch]PDA2 OK\r\n");
		return SUCCESS;
	}

	g_u8_i2c_mode = PDA_MODE;
	u8_retry = 100;
	while (u8_retry--) {
		u8_check = 0;
		for (u8_i = 0; u8_i < u8_comfirm_time; u8_i++) {
			/*check I2C*/
			u32_buf = 0;
			if (handle_i2c_pda_read(g_raydium_ts->client,
						RAYDIUM_PDA_I2CENG,
						(unsigned char *)(&u32_buf), 4) == ERROR) {
				LOGD(LOG_ERR, "[touch]%s: 1.handle_ic_read I2C NG!\r\n", __func__);
				break;
			}

			if (u32_buf == u32_i2c_deglitch)
				u8_check++;
			else
				break;
		}

		if (u8_check == u8_comfirm_time)
			break;

		if (handle_i2c_pda_write(g_raydium_ts->client, RAYDIUM_PDA_I2CENG,
					 (unsigned char *)(&u32_i2c_deglitch), 4) == ERROR) {
			LOGD(LOG_ERR, "[touch]%s:handle_ic_write I2C NG!\r\n", __func__);
			continue;
		}

		u8_check = 0;
		for (u8_i = 0; u8_i < u8_comfirm_time; u8_i++) {
			/*check I2C*/
			u32_buf = 0;
			if (handle_i2c_pda_read(g_raydium_ts->client,
						RAYDIUM_PDA_I2CENG,
						(unsigned char *)(&u32_buf), 4) == ERROR) {
				LOGD(LOG_ERR, "[touch]%s:2.handle_ic_read I2C NG!\r\n", __func__);
				break;
			}

			if (u32_buf == u32_i2c_deglitch)
				u8_check++;
			else
				break;
		}

		if (u8_check == u8_comfirm_time)
			break;
	}

	if (u8_retry == 0)
		return ERROR;

	u32_buf = 0x03;
	if (handle_i2c_pda_write(g_raydium_ts->client, RAYDIUM_REG_GPIO_DEGLITCH,
				 (unsigned char *)(&u32_buf), 4) == ERROR) {
		LOGD(LOG_ERR, "[touch]%s:3.handle_ic_write I2C NG!\r\n", __func__);
		return ERROR;
	}

	/*Disable PDA*/
	handle_i2c_pda_read(g_raydium_ts->client, RAYDIUM_PDA_I2CREG, u8_buf, 4);
	u8_buf[0] |= RAD_ENABLE_PDA2 | RAD_ENABLE_SI2;
	handle_i2c_pda_write(g_raydium_ts->client, RAYDIUM_PDA_I2CREG, u8_buf, 4);
	raydium_i2c_pda_set_address(0x50000628, DISABLE);

	g_u8_i2c_mode = PDA2_MODE;

	return SUCCESS;
}

#ifdef CONFIG_RM_SYSFS_DEBUG

int raydium_i2c_mode_control(struct i2c_client *client,
			     unsigned char u8_mode)
{
	unsigned char u8_buf[4];

	switch (u8_mode) {
	case 0:	/* Disable INT flag */
		LOGD(LOG_INFO, "[touch]RAD INT flag : %d\n", g_raydium_ts->irq_enabled);
		disable_irq(g_raydium_ts->irq);
		g_raydium_ts->irq_enabled = false;
		LOGD(LOG_INFO, "[touch]RAD irq disable\n");
		break;
	case 1:	/* Enable INT flag */
		LOGD(LOG_INFO, "[touch]RAD INT flag : %d\n", g_raydium_ts->irq_enabled);
		enable_irq(g_raydium_ts->irq);
		g_raydium_ts->irq_enabled = true;
		LOGD(LOG_INFO, "[touch]RAD irq enable\n");
		break;
	case 2: /* Disable INT by raydium_irq_control */
		raydium_irq_control(DISABLE);
		break;
	case 3: /* Enable INT by raydium_irq_control */
		raydium_irq_control(ENABLE);
		break;
	case 4: /* Show RAD INT depth */
		LOGD(LOG_INFO, "[touch]RAD INT depth : %d\n", g_raydium_ts->irq_desc->depth);
		break;
	case 7:
		raydium_i2c_pda2_set_page(client,
					  g_raydium_ts->is_suspend, RAYDIUM_PDA2_2_PDA);
		g_u8_i2c_mode = PDA_MODE;
		LOGD(LOG_INFO, "[touch]Disable PDA2_MODE\n");
		break;
	case 8:
		raydium_i2c_pda_read(client, RAYDIUM_PDA_I2CREG, u8_buf, 4);
		u8_buf[0] |= RAD_ENABLE_PDA2 | RAD_ENABLE_SI2;
		raydium_i2c_pda_write(client, RAYDIUM_PDA_I2CREG, u8_buf, 4);
		raydium_i2c_pda_set_address(RAYDIUM_PDA_I2CREG, DISABLE);

		g_u8_i2c_mode = PDA2_MODE;
		LOGD(LOG_INFO, "[touch]Enable PDA2_MODE\n");
		break;
	}
	return 0;
}


const struct attribute_group raydium_attr_group = {
	.attrs = raydium_attributes
};

/*create sysfs for debug update firmware*/
static int raydium_create_sysfs(struct i2c_client *client)
{
	int ret = -1;

	ret = sysfs_create_group(&(client->dev.kobj), &raydium_attr_group);
	if (ret) {
		LOGD(LOG_ERR, "[touch]failed to register sysfs\n");
		sysfs_remove_group(&client->dev.kobj, &raydium_attr_group);
		ret = -EIO;
	} else {
		LOGD(LOG_DEBUG, "[touch]create raydium sysfs attr_group successful\n");
	}
	return ret;
}

static void raydium_release_sysfs(struct i2c_client *client)
{
	sysfs_remove_group(&client->dev.kobj, &raydium_attr_group);
}
#endif /*end of CONFIG_RM_SYSFS_DEBUG*/

#ifdef ESD_SOLUTION_EN
int raydium_esd_check(void)
{
	int i32_ret = 0;
	unsigned char u8_esd_status[MAX_TCH_STATUS_PACKET_SIZE];

	mutex_lock(&g_raydium_ts->lock);
	if (g_u8_i2c_mode == PDA2_MODE) {
		i32_ret = raydium_i2c_pda2_set_page(g_raydium_ts->client,
						    g_raydium_ts->is_suspend,
						    RAYDIUM_PDA2_PAGE_0);
		if (i32_ret < 0)
			goto exit;
		/*read esd status*/
		i32_ret = raydium_i2c_pda2_read(g_raydium_ts->client,
						RAYDIUM_PDA2_TCH_RPT_STATUS_ADDR,
						u8_esd_status, MAX_TCH_STATUS_PACKET_SIZE);
		if (i32_ret < 0) {
			LOGD(LOG_ERR, "[touch]%s: failed to read data: %d\n",
			     __func__, __LINE__);
			goto exit;
		}

		if (u8_esd_status[POS_FW_STATE] != 0x1A &&
		    u8_esd_status[POS_FW_STATE] != 0xAA) {
			if (g_u8_resetflag == true) {
				LOGD(LOG_ERR, "[touch]%s -> filter abnormal irq\n"
				     , __func__);
				goto exit;
			}
			LOGD(LOG_ERR, "[touch]%s -> abnormal irq, FW state = 0x%x\n",
			     __func__, u8_esd_status[POS_FW_STATE]);
			g_u8_resetflag = false;
			i32_ret = -1;
			goto exit;

		}
		g_u8_resetflag = false;
	}
exit:
	mutex_unlock(&g_raydium_ts->lock);
	LOGD(LOG_INFO, "[touch]%s\n", __func__);
	return i32_ret;
}
#endif




static int raydium_touch_report(unsigned char *p_u8_buf,
				unsigned char u8_points_amount)
{
	unsigned char u8_i, u8_j, u8_offset = 0, u8_pt_id;
	signed short i16_wx, i16_wy;
	/* number of touch points */
	unsigned char u8_touch_count = 0;
	//DECLARE_BITMAP(ids, g_raydium_ts->u8_max_touchs);
	unsigned long *ids = NULL;

	ids = kzalloc(sizeof(*ids)*BITS_TO_LONGS(g_raydium_ts->u8_max_touchs), GFP_KERNEL);
	if (!ids)
		return -ENOMEM;

	bitmap_zero(ids, g_raydium_ts->u8_max_touchs);

	for (u8_i = 0; u8_i < (g_raydium_ts->u8_max_touchs * 2); u8_i++) {
		gst_slot[u8_i].need_update = 0;
		gst_slot[u8_i].pt_report_offset = 0;
	}

	/*Check incoming point info*/
	for (u8_i = 0; u8_i < u8_points_amount; u8_i++) {
		u8_pt_id = p_u8_buf[POS_PT_ID + u8_i * LEN_PT];
		/* Current*/
		for (u8_j = 0; u8_j < g_raydium_ts->u8_max_touchs; u8_j++) {
			if (u8_pt_id == gst_slot[u8_j].pt_id) {
				gst_slot[u8_j].need_update = 1;
				gst_slot[u8_j].pt_report_offset = u8_i;
				break;
			}
		}
		/* New coming*/
		if (u8_j == g_raydium_ts->u8_max_touchs) {
			for (u8_j = g_raydium_ts->u8_max_touchs;
			     u8_j < (g_raydium_ts->u8_max_touchs * 2); u8_j++) {
				if (!gst_slot[u8_j].need_update) {
					gst_slot[u8_j].pt_id = u8_pt_id;
					gst_slot[u8_j].need_update = 1;
					gst_slot[u8_j].pt_report_offset = u8_i;
					LOGD(LOG_DEBUG, "[touch]x:%d,y:%d\n",
					     p_u8_buf[POS_X_L + u8_offset] |
					     p_u8_buf[POS_X_H + u8_offset] << 8,
					     p_u8_buf[POS_Y_L + u8_offset] |
					     p_u8_buf[POS_Y_H + u8_offset] << 8);
					break;
				}
			}
		}
	}

	/*Release slot with non-occupied point*/
	for (u8_i = 0; u8_i < g_raydium_ts->u8_max_touchs; u8_i++) {
		if (!gst_slot[u8_i].need_update) {
			input_mt_slot(g_raydium_ts->input_dev, u8_i);
			input_mt_report_slot_state(g_raydium_ts->input_dev,
						   MT_TOOL_FINGER, false);
			gst_slot[u8_i].pt_id = 0xFF;
			gst_slot[u8_i].pt_report_offset = 0;
			gst_slot[u8_i].need_update = 0;
		}
	}
	/*Assign new one to non-occupied slot*/
	for (u8_i = g_raydium_ts->u8_max_touchs;
	     u8_i < (g_raydium_ts->u8_max_touchs * 2); u8_i++) {
		if (gst_slot[u8_i].need_update) {
			for (u8_j = 0; u8_j < g_raydium_ts->u8_max_touchs; u8_j++) {
				if (!gst_slot[u8_j].need_update) {
					gst_slot[u8_j] = gst_slot[u8_i];
					gst_slot[u8_i] = gst_slot_init;
					break;
				}
			}
		} else {
			break;
		}
	}
	for (u8_i = 0; u8_i < g_raydium_ts->u8_max_touchs; u8_i++) {
		if (gst_slot[u8_i].need_update) {
			u8_offset = gst_slot[u8_i].pt_report_offset * LEN_PT;
			g_raydium_ts->x_pos[u8_i] = p_u8_buf[POS_X_L + u8_offset] |
						    p_u8_buf[POS_X_H + u8_offset] << BYTE_SHIFT;
			g_raydium_ts->y_pos[u8_i] = p_u8_buf[POS_Y_L + u8_offset] |
						    p_u8_buf[POS_Y_H + u8_offset] << BYTE_SHIFT;
			g_raydium_ts->pressure = p_u8_buf[POS_PRESSURE_L + u8_offset] |
						 p_u8_buf[POS_PRESSURE_H + u8_offset] << BYTE_SHIFT;
			i16_wx = p_u8_buf[POS_WX_L + u8_offset] |
				 p_u8_buf[POS_WX_H + u8_offset] << BYTE_SHIFT;
			i16_wy = p_u8_buf[POS_WY_L + u8_offset] |
				 p_u8_buf[POS_WY_H + u8_offset] << BYTE_SHIFT;

			input_mt_slot(g_raydium_ts->input_dev, u8_i);
			input_mt_report_slot_state(g_raydium_ts->input_dev,
						   MT_TOOL_FINGER, true);
			__set_bit(u8_i, ids);

			input_report_abs(g_raydium_ts->input_dev,
					 ABS_MT_POSITION_X, g_raydium_ts->x_pos[u8_i]);
			input_report_abs(g_raydium_ts->input_dev,
					 ABS_MT_POSITION_Y, g_raydium_ts->y_pos[u8_i]);
			input_report_abs(g_raydium_ts->input_dev,
					 ABS_MT_PRESSURE, g_raydium_ts->pressure);
			input_report_abs(g_raydium_ts->input_dev,
					 ABS_MT_TOUCH_MAJOR, max(i16_wx, i16_wy));
			input_report_abs(g_raydium_ts->input_dev,
					 ABS_MT_TOUCH_MINOR, min(i16_wx, i16_wy));
			LOGD(LOG_DEBUG, "[touch:%d]x:%d,y:%d\n",
			     u8_i,
			     p_u8_buf[POS_X_L + u8_offset] |
			     p_u8_buf[POS_X_H + u8_offset] << 8,
			     p_u8_buf[POS_Y_L + u8_offset] |
			     p_u8_buf[POS_Y_H + u8_offset] << 8);
			u8_touch_count++;
		}
	}
	input_report_key(g_raydium_ts->input_dev,
			 BTN_TOUCH, u8_touch_count > 0);
	input_report_key(g_raydium_ts->input_dev,
			 BTN_TOOL_FINGER, u8_touch_count > 0);

	for (u8_i = 0; u8_i < g_raydium_ts->u8_max_touchs; u8_i++) {
		if (test_bit(u8_i, ids))
			continue;
		input_mt_slot(g_raydium_ts->input_dev, u8_i);
		input_mt_report_slot_state(g_raydium_ts->input_dev,
					   MT_TOOL_FINGER, false);
	}

	input_sync(g_raydium_ts->input_dev);
	kfree(ids);

	return 0;
}


int raydium_read_touchdata(unsigned char *p_u8_tp_status,  unsigned char *p_u8_buf)
{

	int i32_ret = 0;
	unsigned char u8_points_amount;
	static unsigned char u8_seq_no;
	unsigned char u8_retry;
	unsigned char u8_read_size;
	unsigned char u8_read_buf[MAX_REPORT_PACKET_SIZE];
	u8_retry = 100;

	mutex_lock(&g_raydium_ts->lock);
	while (u8_retry != 0) {
		i32_ret = raydium_i2c_pda2_set_page(g_raydium_ts->client,
						    g_raydium_ts->is_suspend, RAYDIUM_PDA2_PAGE_0);
		if (i32_ret < 0) {
			msleep(250);
			u8_retry--;
		} else
			break;
	}
	if (u8_retry == 0) {
		LOGD(LOG_ERR, "[touch]%s: failed to set page\n", __func__);

		goto reset_error;
	}

	memset(u8_read_buf, 0, MAX_REPORT_PACKET_SIZE);
	memset(p_u8_buf, 0, MAX_REPORT_PACKET_SIZE);
	memset(p_u8_tp_status, 0, MAX_TCH_STATUS_PACKET_SIZE);
	u8_read_size = 4 + MAX_TOUCH_NUM * LEN_PT + 1;
	/*read touch point information*/
	i32_ret = raydium_i2c_pda2_read(g_raydium_ts->client,
					RAYDIUM_PDA2_TCH_RPT_STATUS_ADDR,
					u8_read_buf, u8_read_size);
	if (i32_ret < 0) {
		LOGD(LOG_ERR, "[touch]%s: failed to read data: %d\n",
		     __func__, __LINE__);
		goto exit_error;
	}
	memcpy(p_u8_tp_status, &u8_read_buf[0], MAX_TCH_STATUS_PACKET_SIZE);

#ifdef ESD_SOLUTION_EN
	if (p_u8_tp_status[POS_FW_STATE] != 0x1A &&
	    p_u8_tp_status[POS_FW_STATE] != 0xAA) {
		if (g_u8_resetflag == true) {
			LOGD(LOG_ERR, "[touch]%s -> filter irq, FW state = 0x%x\n",
			     __func__, p_u8_tp_status[POS_FW_STATE]);
			i32_ret = -1;
			g_u8_resetflag = false;
			goto exit_error;
		}
		LOGD(LOG_ERR, "[touch]%s -> abnormal irq, FW state = 0x%x\n",
		     __func__, p_u8_tp_status[POS_FW_STATE]);
		i32_ret = -1;
		goto reset_error;

	}
#endif
	/* inform IC to prepare next report*/
	if (u8_seq_no == p_u8_tp_status[POS_SEQ]) {
		p_u8_tp_status[POS_SEQ] = 0;
		i32_ret = raydium_i2c_pda2_write(g_raydium_ts->client,
						 RAYDIUM_PDA2_TCH_RPT_STATUS_ADDR, p_u8_tp_status, 1);
		if (i32_ret < 0) {
			LOGD(LOG_ERR, "[touch]%s: write data failed: %d\n", __func__, i32_ret);
			goto exit_error;
		}
		LOGD(LOG_DEBUG, "[touch]%s -> report not updated.\n", __func__);
		goto exit_error;
	}
	u8_seq_no = p_u8_tp_status[POS_SEQ];
	p_u8_tp_status[POS_SEQ] = 0;
	i32_ret = raydium_i2c_pda2_write(g_raydium_ts->client,
					 RAYDIUM_PDA2_TCH_RPT_STATUS_ADDR, p_u8_tp_status, 1);
	if (i32_ret < 0) {
		LOGD(LOG_ERR, "[touch]%s: write data failed: %d\n", __func__, i32_ret);
		goto exit_error;
	}

	u8_points_amount = p_u8_tp_status[POS_PT_AMOUNT];

	if (u8_points_amount > MAX_TOUCH_NUM)
		goto exit_error;
	memcpy(p_u8_buf, &u8_read_buf[4], u8_points_amount * LEN_PT);

	raydium_touch_report(p_u8_buf, u8_points_amount);

exit_error:
	mutex_unlock(&g_raydium_ts->lock);

	return i32_ret;

reset_error:
	mutex_unlock(&g_raydium_ts->lock);
#ifdef ESD_SOLUTION_EN
	u8_retry = 3;
	while (u8_retry != 0) {
		i32_ret = raydium_hw_reset_fun(g_raydium_ts->client);
		LOGD(LOG_ERR, "[touch]%s: HW reset\n", __func__);
		if (i32_ret < 0) {
			msleep(100);
			u8_retry--;
		} else
			break;
	}
#endif
	return i32_ret;
}

static void raydium_work_handler(struct work_struct *work)
{
	int i32_ret = 0;
	unsigned char u8_tp_status[MAX_TCH_STATUS_PACKET_SIZE] = {0};
	unsigned char u8_buf[MAX_REPORT_PACKET_SIZE] = {0};

#ifdef GESTURE_EN
	unsigned char u8_i;
	LOGD(LOG_DEBUG, "[touch]ts->blank:%x, g_u8_i2c_mode:%x\n",
			g_raydium_ts->blank, g_u8_i2c_mode);
	LOGD(LOG_DEBUG, "[touch]u8_tp_status:%x, g_raydium_ts->is_palm:%x\n",
			u8_tp_status[POS_GES_STATUS], g_raydium_ts->is_palm);

	if (g_u8_i2c_mode == PDA2_MODE) {
		i32_ret = raydium_read_touchdata(u8_tp_status, u8_buf);
		if (i32_ret < 0) {
			LOGD(LOG_ERR, "[touch]%s, read_touchdata error, ret:%d\n",
			     __func__, i32_ret);
			return;
		}
	}
#if defined(CONFIG_PANEL_NOTIFIER)
	if (g_raydium_ts->blank == DRM_PANEL_EVENT_BLANK_LP ||
	g_raydium_ts->blank == DRM_PANEL_EVENT_BLANK || g_raydium_ts->fb_state == FB_OFF) {
#else
	if (g_raydium_ts->blank == DRM_PANEL_BLANK_LP ||
	g_raydium_ts->blank == DRM_PANEL_BLANK_POWERDOWN || g_raydium_ts->fb_state == FB_OFF) {
#endif
		LOGD(LOG_DEBUG, "[touch] elseif u8_tp_status:%x\n", u8_tp_status[POS_GES_STATUS]);
		/*need check small area*/
		if (u8_tp_status[POS_GES_STATUS] == RAD_WAKE_UP
		 && g_u8_wakeup_flag == false) {
		/*if (u8_tp_status[POS_GES_STATUS] == 0)	{*/
			input_report_key(g_raydium_ts->input_dev, KEY_WAKEUP, true);
			usleep_range(9500, 10500);
			input_sync(g_raydium_ts->input_dev);

			input_report_key(g_raydium_ts->input_dev, KEY_WAKEUP, false);
			input_sync(g_raydium_ts->input_dev);
			LOGD(LOG_DEBUG, "[touch]display wake up with g_u8_resetflag true\n");
			/*goto exit;*/
		}
	}
	/*when display on can use palm to suspend*/
#if defined(CONFIG_PANEL_NOTIFIER)
	else if (g_raydium_ts->blank == DRM_PANEL_EVENT_UNBLANK) {
#else
	else if (g_raydium_ts->blank == DRM_PANEL_BLANK_UNBLANK) {
#endif
		if (u8_tp_status[POS_GES_STATUS] == RAD_PALM_ENABLE) {
			if (g_raydium_ts->is_palm == 0) {
				/* release all touches*/
				for (u8_i = 0; u8_i < g_raydium_ts->u8_max_touchs;
				     u8_i++) {
					input_mt_slot(g_raydium_ts->input_dev,
						      u8_i);
					input_mt_report_slot_state(
						g_raydium_ts->input_dev,
						MT_TOOL_FINGER, false);
				}
				input_mt_report_pointer_emulation(
					g_raydium_ts->input_dev,
					false);
				/*press sleep key*/
				input_report_key(g_raydium_ts->input_dev,
						 KEY_SLEEP, true);
				input_sync(g_raydium_ts->input_dev);

				LOGD(LOG_INFO, "[touch]palm_status = %d.\n",
				     u8_tp_status[POS_GES_STATUS]);

				g_raydium_ts->is_palm = 1;
				/*goto exit;*/
			}
		} else if ((u8_tp_status[POS_GES_STATUS]
			    == RAD_PALM_DISABLE)
			   && (g_raydium_ts->is_palm == 1)) {
			LOGD(LOG_INFO, "[touch]leave palm mode.\n");
			input_report_key(g_raydium_ts->input_dev,
					 KEY_SLEEP, false);
			input_sync(g_raydium_ts->input_dev);

			/*raydium_irq_control(raydium_ts, DISABLE);*/
			g_raydium_ts->is_palm = 0;
			/*goto exit;*/
		}
	}
#else
	if (g_u8_i2c_mode == PDA2_MODE) {
		i32_ret = raydium_read_touchdata(u8_tp_status, u8_buf);
		if (i32_ret < 0) {
			LOGD(LOG_ERR, "[touch]%s, read_touchdata error, ret:%d\n",
			     __func__, i32_ret);
		}
	}
#endif
}


/*The raydium device will signal the host about TRIGGER_FALLING.
 *Processed when the interrupt is asserted.
 */
static irqreturn_t raydium_ts_interrupt(int irq, void *dev_id)
{
	bool result = false;

	LOGD(LOG_DEBUG, "[touch]%s\n", __func__);

	/*For bootloader wrt/erase flash and software reset interrupt*/
	if ((g_u8_raydium_flag & ENG_MODE) != 0) {
		LOGD(LOG_INFO, "[touch]RAD_ENG_MODE\n");
		g_u8_raydium_flag |= INT_FLAG;
	} else {
		if (!work_pending(&g_raydium_ts->work)) {
			/* Clear interrupts*/
			if (g_raydium_ts->workqueue) {
				result = queue_work(g_raydium_ts->workqueue,
						&g_raydium_ts->work);
			}

			if (!result) {
				/*queue_work fail*/
				LOGD(LOG_ERR, "[touch]queue_work fail.\n");
			}


		} else {
			/*work pending*/
			mutex_lock(&g_raydium_ts->lock);
			if (raydium_i2c_pda2_set_page(g_raydium_ts->client,
						      g_raydium_ts->is_suspend,
						      RAYDIUM_PDA2_PAGE_0) < 0) {

				LOGD(LOG_ERR, "[touch]%s: failed to set page in work_pending\n",
				     __func__);
			}
			mutex_unlock(&g_raydium_ts->lock);

			LOGD(LOG_DEBUG, "[touch]work_pending\n");
		}
	}
	return IRQ_HANDLED;
}

static int raydium_check_i2c_ready(unsigned short *u16_i2c_data)
{
	unsigned char u8_buf[4];
	int i32_ret = ERROR;

	mutex_lock(&g_raydium_ts->lock);

	if (g_u8_i2c_mode == PDA2_MODE) {
		i32_ret = handle_i2c_pda_read(g_raydium_ts->client,
					      RAYDIUM_CHK_I2C_CMD, u8_buf, 4);
		if (i32_ret < 0)
			goto exit_error;

		if (u8_buf[3] != 0xF3) {
			LOGD(LOG_ERR, "[touch]PDA2 read i2c fail\n");
			g_u8_i2c_mode = PDA_MODE;
			i32_ret = handle_i2c_pda_read(g_raydium_ts->client,
						      RAYDIUM_CHK_I2C_CMD, u8_buf, 4);
			if (i32_ret < 0)
				goto exit_error;
		}
	} else {
		i32_ret = handle_i2c_pda_read(g_raydium_ts->client,
					      RAYDIUM_CHK_I2C_CMD, u8_buf, 4);
		if (i32_ret < 0)
			goto exit_error;

	}

	*u16_i2c_data = u8_buf[3] << 8 | u8_buf[2];

	LOGD(LOG_DEBUG, "[touch]RAD check I2C : 0x%02X%02X\n", u8_buf[3], u8_buf[2]);

exit_error:
	mutex_unlock(&g_raydium_ts->lock);
	return i32_ret;
}

#if defined(CONFIG_PM)
static void raydium_ts_do_suspend(void)
{
	unsigned char u8_i = 0;

	LOGD(LOG_INFO, "[touch]%s.\n", __func__);

	if (g_u8_raw_data_type == 0)
		g_u8_resetflag = false;
	if (g_raydium_ts->is_suspend == 1 && (pm_suspend_via_firmware() == false)) {
		LOGD(LOG_WARNING, "[touch]Already in suspend state\n");
		return;
	}
	/*#ifndef GESTURE_EN*/
	raydium_irq_control(DISABLE);
	/*#endif*/

	/*clear workqueue*/
	if (!cancel_work_sync(&g_raydium_ts->work))
		LOGD(LOG_DEBUG, "[touch]workqueue is empty!\n");

	/* release all touches */
	for (u8_i = 0; u8_i < g_raydium_ts->u8_max_touchs; u8_i++) {
		input_mt_slot(g_raydium_ts->input_dev, u8_i);
		input_mt_report_slot_state(g_raydium_ts->input_dev,
					   MT_TOOL_FINGER,
					   false);
	}
	input_mt_report_pointer_emulation(g_raydium_ts->input_dev, false);
	input_sync(g_raydium_ts->input_dev);

#ifdef GESTURE_EN
	if (pm_suspend_via_firmware() == false)
	{
		if (device_may_wakeup(&g_raydium_ts->client->dev)) {
			LOGD(LOG_INFO, "[touch]Device may wakeup\n");
			if (!enable_irq_wake(g_raydium_ts->irq))
				g_raydium_ts->irq_wake = true;

		} else {
			LOGD(LOG_INFO, "[touch]Device not wakeup\n");
		}
		raydium_irq_control(ENABLE);
	}
#endif

	g_raydium_ts->is_suspend = 1;
}

static void raydium_ts_do_resume(void)
{
#ifdef ESD_SOLUTION_EN
	int i32_ret = 0;
	unsigned char u8_retry = 0;
#endif

	LOGD(LOG_INFO, "[touch]%s, %d.\n", __func__, g_raydium_ts->is_suspend);
	if (g_raydium_ts->is_suspend == 0) {
		LOGD(LOG_WARNING, "[touch]Already in resume state\n");
		return;
	}

	/* clear interrupts*/
	mutex_lock(&g_raydium_ts->lock);
	if (raydium_i2c_pda2_set_page(g_raydium_ts->client,
				      g_raydium_ts->is_suspend, RAYDIUM_PDA2_PAGE_0) < 0) {
		LOGD(LOG_ERR, "[touch]%s: failed to set page\n", __func__);
		mutex_unlock(&g_raydium_ts->lock);
		return;
	}
	mutex_unlock(&g_raydium_ts->lock);

	/* clear workqueue*/
	if (!cancel_work_sync(&g_raydium_ts->work))
		LOGD(LOG_DEBUG, "[ raydium ]workqueue is empty!\n");
#ifdef ESD_SOLUTION_EN
	if (g_u8_checkflag == true) {
		i32_ret = raydium_esd_check();
		if (i32_ret < 0) {
			u8_retry = 3;
			while (u8_retry != 0) {
				i32_ret = raydium_hw_reset_fun(g_raydium_ts->client);
				if (i32_ret < 0) {
					msleep(100);
					u8_retry--;
				} else
					break;
			}

		}
		g_u8_checkflag = false;
	}
#endif
	raydium_irq_control(ENABLE);
#ifdef GESTURE_EN
	if (device_may_wakeup(&g_raydium_ts->client->dev)) {
		LOGD(LOG_INFO, "[touch]Device may wakeup\n");
		if (g_raydium_ts->irq_wake) {
			disable_irq_wake(g_raydium_ts->irq);
			g_raydium_ts->irq_wake = false;
		}
	} else
		LOGD(LOG_INFO, "[touch]Device not wakeup\n");
#endif

	g_raydium_ts->is_suspend = 0;
}

static int raydium_ts_suspend(struct device *dev)
{
	raydium_ts_do_suspend();
	return 0;
}

static int raydium_ts_resume(struct device *dev)
{
	raydium_ts_do_resume();
	return 0;
}


static const struct dev_pm_ops raydium_ts_pm_ops = {
#if (!defined(CONFIG_FB) && !defined(CONFIG_HAS_EARLYSUSPEND))
	.suspend	= raydium_ts_suspend,
	.resume		= raydium_ts_resume,
#endif /*end of CONFIG_PM*/
};

/*used for touch lock feature*/
static int raydium_ts_open(struct input_dev *input_dev)
{
	//int i32_ret = 0;

	LOGD(LOG_DEBUG, "[touch]%s()+\n", __func__);

	LOGD(LOG_DEBUG, "[touch]ts->blank:%x\n", g_raydium_ts->blank);

	if (g_raydium_ts->is_sleep == 1) {
		mutex_lock(&g_raydium_ts->lock);
		if (gpio_is_valid(g_raydium_ts->rst_gpio)) {

			g_u8_resetflag = true;
			gpio_set_value(g_raydium_ts->rst_gpio, 1);
			gpio_set_value(g_raydium_ts->rst_gpio, 0);
			msleep(RAYDIUM_RESET_INTERVAL_MSEC);/*5ms*/
			gpio_set_value(g_raydium_ts->rst_gpio, 1);
			msleep(RAYDIUM_RESET_DELAY_MSEC);/*100ms*/
			g_u8_i2c_mode = PDA2_MODE;
		}
		mutex_unlock(&g_raydium_ts->lock);
		raydium_irq_control(ENABLE);
		g_raydium_ts->is_sleep = 0;
		LOGD(LOG_INFO, "[touch]disable touch lock.\n");
	}
	//return i32_ret;
	return 0;
}

static void raydium_ts_close(struct input_dev *input_dev)
{
	int i32_ret = 0;
	unsigned char u8_i = 0;
	unsigned char u8_wbuffer[1];

	LOGD(LOG_INFO, "[touch]%s()+\n", __func__);

	if (g_raydium_ts->is_sleep == 1) {
		LOGD(LOG_INFO, "[touch]touch lock already enabled.\n");
		return;
	}

	raydium_irq_control(DISABLE);

	for (u8_i = 0; u8_i < g_raydium_ts->u8_max_touchs; u8_i++) {
		input_mt_slot(g_raydium_ts->input_dev, u8_i);
		input_mt_report_slot_state(g_raydium_ts->input_dev,
					   MT_TOOL_FINGER,
					   false);
	}
	input_mt_report_pointer_emulation(g_raydium_ts->input_dev, false);
	input_sync(g_raydium_ts->input_dev);
	mutex_lock(&g_raydium_ts->lock);
	i32_ret = raydium_i2c_pda2_set_page(g_raydium_ts->client,
					    g_raydium_ts->is_suspend, RAYDIUM_PDA2_PAGE_0);
	if (i32_ret < 0) {
		LOGD(LOG_ERR, "[touch]ret:%d\n", i32_ret);
		goto exit_i2c_error;
	}
	u8_wbuffer[0] = RAYDIUM_HOST_CMD_PWR_SLEEP;
	i32_ret = raydium_i2c_pda2_write(g_raydium_ts->client,
					 RAYDIUM_PDA2_HOST_CMD_ADDR,
					 u8_wbuffer,
					 1);
	if (i32_ret < 0) {
		LOGD(LOG_ERR, "[touch]ret:%d\n", i32_ret);
		goto exit_i2c_error;
	}

	mutex_unlock(&g_raydium_ts->lock);
	g_raydium_ts->is_sleep = 1;
	LOGD(LOG_INFO, "[touch]enable touch lock.\n");
	return;

exit_i2c_error:
	mutex_unlock(&g_raydium_ts->lock);
	raydium_irq_control(ENABLE);
}

#else
static int raydium_ts_suspend(struct device *dev)
{
	return 0;
}

static int raydium_ts_resume(struct device *dev)
{
	return 0;
}
#endif /*end of CONFIG_FB*/

#if defined(CONFIG_PANEL_NOTIFIER)
static void panel_event_notifier_callback(enum panel_event_notifier_tag tag,
		struct panel_event_notification *notification, void *client_data)
{

	struct raydium_ts_data *g_raydium_ts = client_data;
	if(!notification)
	{
		LOGD(LOG_INFO, "%s: Invalid notification\n", __func__);
		return ;
	}

	LOGD(LOG_INFO, "%s: DRM notifier called!\n", __func__);

	LOGD(LOG_INFO, "%s: DRM event:%d fb_state %d ",
		__func__, notification->notif_type, g_raydium_ts->fb_state);
	LOGD(LOG_INFO, "%s: DRM Power - %d- FB state %d ",
		__func__, (notification->notif_type == DRM_PANEL_EVENT_UNBLANK)?"UP":"DOWN", g_raydium_ts->fb_state);

	if (notification->notif_type == DRM_PANEL_EVENT_UNBLANK) {
		LOGD(LOG_INFO, "%s: UNBLANK!\n", __func__);

		if (notification->notif_data.early_trigger) {
			LOGD(LOG_INFO, "%s: resume: event = %d not care\n",
				__func__, notification->notif_type);
		} else {
				LOGD(LOG_INFO, "%s: Resume notifier called!\n",
					__func__);
#ifdef GESTURE_EN
			/* clear palm status */
			g_raydium_ts->is_palm = 0;
#endif

#if defined(CONFIG_PM)
				raydium_ts_resume(&g_raydium_ts->client->dev);
#endif
				g_raydium_ts->fb_state = FB_ON;
			LOGD(LOG_INFO, "%s: Resume notified!\n", __func__);
		}
	} else if (notification->notif_type == DRM_PANEL_EVENT_BLANK_LP ||
		notification->notif_type == DRM_PANEL_EVENT_BLANK) {
		if (notification->notif_type == DRM_PANEL_EVENT_BLANK_LP) {
			LOGD(LOG_INFO, "%s: LOWPOWER!\n", __func__);
		} else {
			LOGD(LOG_INFO, "%s: BLANK!\n", __func__);
		}
		if (notification->notif_data.early_trigger) {
				LOGD(LOG_INFO, "%s: Suspend notifier called!\n",
					__func__);
#ifdef GESTURE_EN
			/* clear palm status */
			g_raydium_ts->is_palm = 0;
#endif

#if defined(CONFIG_PM)
				raydium_ts_suspend(&g_raydium_ts->client->dev);
#endif
				g_raydium_ts->fb_state = FB_OFF;
				LOGD(LOG_INFO, "%s: Suspend notified!\n", __func__);
		} else {
			LOGD(LOG_INFO, "%s: suspend: event = %d not care\n",
				__func__, notification->notif_type);
		}
	} else {
		LOGD(LOG_INFO, "%s: Undefined notif type (%d) do not need process\n",
			__func__, notification->notif_type);
	}
	return ;
}

/*******************************************************************************
 * FUNCTION: raydium_setup_drm_notifier
 *
 * SUMMARY: Set up call back function into drm notifier.
 *
 * PARAMETERS:
 * g_raydium_ts   - pointer to core data
 *******************************************************************************/
static void raydium_setup_panel_notifier(struct raydium_ts_data *g_raydium_ts)
{
	void *cookie = NULL;
	if (!active_panel)
                LOGD(LOG_ERR, "[touch]%s: Active panel not registered!\n", __func__);

	cookie = panel_event_notifier_register(PANEL_EVENT_NOTIFICATION_PRIMARY,
			PANEL_EVENT_NOTIFIER_CLIENT_PRIMARY_TOUCH,
			active_panel,&panel_event_notifier_callback, g_raydium_ts);
	g_raydium_ts->entry = cookie;
}

#elif defined(CONFIG_DRM)
/*******************************************************************************
 * FUNCTION: drm_notifier_callback
 *
 * SUMMARY: Call back function for DRM notifier to allow to call
 * resume/suspend attention list.
 *
 * RETURN:
 *   0 = success
 *
 * PARAMETERS:
 * self   - pointer to notifier_block structure
 * event  - event type of fb notifier
 * data   - pointer to fb_event structure
 ******************************************************************************/
static int drm_notifier_callback(struct notifier_block *self,
			unsigned long event, void *data)
{
	struct raydium_ts_data *g_raydium_ts =
		container_of(self, struct raydium_ts_data, fb_notif);
	struct drm_panel_notifier *evdata = data;
	int *blank;

	LOGD(LOG_INFO, "%s: DRM notifier called!\n", __func__);

	if (!evdata)
		goto exit;

	if (!(event == DRM_PANEL_EARLY_EVENT_BLANK ||
			event == DRM_PANEL_EVENT_BLANK)) {
		LOGD(LOG_INFO, "%s: Event(%lu) do not need process\n",
			__func__, event);
		goto exit;
	}

	blank = evdata->data;
	g_raydium_ts->blank = (*blank);
	LOGD(LOG_INFO, "%s: DRM event:%lu,blank:%d fb_state %d ",
		__func__, event, *blank, g_raydium_ts->fb_state);
	LOGD(LOG_INFO, "%s: DRM Power - %s - FB state %d ",
		__func__, (*blank == DRM_PANEL_BLANK_UNBLANK)?"UP":"DOWN", g_raydium_ts->fb_state);

	if (*blank == DRM_PANEL_BLANK_UNBLANK) {
		LOGD(LOG_INFO, "%s: UNBLANK!\n", __func__);

		if (event == DRM_PANEL_EARLY_EVENT_BLANK) {
			LOGD(LOG_INFO, "%s: resume: event = %lu, not care\n",
				__func__, event);
		} else if (event == DRM_PANEL_EVENT_BLANK) {
			if (g_raydium_ts->fb_state != FB_ON) {
				LOGD(LOG_INFO, "%s: Resume notifier called!\n",
					__func__);
#ifdef GESTURE_EN
			/* clear palm status */
			g_raydium_ts->is_palm = 0;
#endif

#if defined(CONFIG_PM)
				raydium_ts_resume(&g_raydium_ts->client->dev);
#endif
				g_raydium_ts->fb_state = FB_ON;
			LOGD(LOG_INFO, "%s: Resume notified!\n", __func__);
			}
		}
	} else if (*blank == DRM_PANEL_BLANK_LP || *blank == DRM_PANEL_BLANK_POWERDOWN
		|| *blank == DRM_PANEL_BLANK_FPS_CHANGE) {
		LOGD(LOG_INFO, "%s: LOWPOWER!\n", __func__);
		if (event == DRM_PANEL_EARLY_EVENT_BLANK) {
			if (g_raydium_ts->fb_state != FB_OFF) {
				LOGD(LOG_INFO, "%s: Suspend notifier called!\n",
					__func__);
#ifdef GESTURE_EN
			/* clear palm status */
			g_raydium_ts->is_palm = 0;
#endif

#if defined(CONFIG_PM)
				raydium_ts_suspend(&g_raydium_ts->client->dev);
#endif
				g_raydium_ts->fb_state = FB_OFF;
				LOGD(LOG_INFO, "%s: Suspend notified!\n", __func__);
			}
		} else if (event == DRM_PANEL_EVENT_BLANK) {
			LOGD(LOG_INFO, "%s: suspend: event = %lu, not care\n",
				__func__, event);
		}
	} else {
		LOGD(LOG_INFO, "%s: DRM BLANK(%d) do not need process\n",
			__func__, *blank);
	}
exit:
	return 0;
}

static void raydium_setup_drm_unregister_notifier(void)
{
	if (active_panel && drm_panel_notifier_unregister(active_panel,
				&g_raydium_ts->fb_notif) < 0)
		LOGD(LOG_ERR, "[touch]%s: DRM UnRegister notifier failed!\n", __func__);
}
/*******************************************************************************
 * FUNCTION: raydium_setup_drm_notifier
 *
 * SUMMARY: Set up call back function into drm notifier.
 *
 * PARAMETERS:
 * g_raydium_ts   - pointer to core data
 *******************************************************************************/
static void raydium_setup_drm_notifier(struct raydium_ts_data *g_raydium_ts)
{
	g_raydium_ts->fb_state = FB_ON;
	g_raydium_ts->fb_notif.notifier_call = drm_notifier_callback;
	LOGD(LOG_INFO, "[touch]%s: Setting up drm notifier\n", __func__);

	if (!active_panel)
		LOGD(LOG_ERR, "[touch]%s: Active panel not registered!\n", __func__);

	if (active_panel && drm_panel_notifier_register(active_panel,
		&g_raydium_ts->fb_notif) < 0)
		LOGD(LOG_ERR, "[touch]%s: Register notifier failed!\n", __func__);
}
#endif /*end of CONFIG_DRM*/

/*******************************************************************************
 * FUNCTION: raydium_setup_drm_notifier
 *
 * SUMMARY: Set up call back function into fb notifier.
 *
 * PARAMETERS:
 * g_raydium_ts   - pointer to core data
 *******************************************************************************/
#if defined(CONFIG_FB)
static int fb_notifier_callback(struct notifier_block *self,
				unsigned long event,
				void *data)
{
	struct fb_event *evdata = data;
	int *blank;

	if (evdata && evdata->data && event == FB_EVENT_BLANK &&
	    g_raydium_ts && g_raydium_ts->client) {
		blank = evdata->data;
		g_raydium_ts->blank = (*blank);
		switch (*blank) {

		/*screen on*/
		case FB_BLANK_UNBLANK:
			LOGD(LOG_INFO, "[touch]FB_BLANK_UNBLANK\n");
#ifdef GESTURE_EN

			/* clear palm status */

			g_raydium_ts->is_palm = 0;
#endif
			raydium_ts_resume(&g_raydium_ts->client->dev);
			break;

		/*screen off*/
		case FB_BLANK_POWERDOWN:
			LOGD(LOG_INFO, "[touch]FB_BLANK_POWERDOWN\n");
#ifdef GESTURE_EN

			/* clear palm status */

			g_raydium_ts->is_palm = 0;
#endif
			raydium_ts_suspend(&g_raydium_ts->client->dev);
			break;

		/*ambient mode*/
		case FB_BLANK_VSYNC_SUSPEND:
			LOGD(LOG_INFO, "[touch]FB_BLANK_VSYNC_SUSPEND\n");
#ifdef GESTURE_EN

			/* clear palm status */

			g_raydium_ts->is_palm = 0;
#endif

			raydium_ts_suspend(&g_raydium_ts->client->dev);
			break;

		default:
			break;
		}
	}

	return 0;
}

static void raydium_register_notifier(void)
{
	memset(&g_raydium_ts->fb_notif, 0, sizeof(g_raydium_ts->fb_notif));
	g_raydium_ts->fb_notif.notifier_call = fb_notifier_callback;

	/* register on the fb notifier and work with fb*/
	if (fb_register_client(&g_raydium_ts->fb_notif))
		LOGD(LOG_ERR, "[touch]register notifier failed\n");
}

static void raydium_unregister_notifier(void)
{
	fb_unregister_client(&g_raydium_ts->fb_notif);
}
#elif defined(CONFIG_HAS_EARLYSUSPEND)
static void raydium_ts_early_suspend(struct early_suspend *handler)
{

	raydium_ts_do_suspend();
}

static void raydium_ts_late_resume(struct early_suspend *handler)
{
	raydium_ts_do_resume();
}
#endif /*end of CONFIG_FB*/

#ifdef CONFIG_OF
static int raydium_get_dt_coords(struct device *dev, char *name,
				 struct raydium_ts_platform_data *pdata)
{
	u32 coords[COORDS_ARR_SIZE];
	struct property *prop;
	struct device_node *np = dev->of_node;
	int coords_size, rc;

	prop = of_find_property(np, name, NULL);
	if (!prop)
		return -EINVAL;

	if (!prop->value)
		return -ENODATA;


	coords_size = prop->length / sizeof(u32);
	if (coords_size != COORDS_ARR_SIZE) {
		LOGD(LOG_ERR, "[touch]invalid %s\n", name);
		return -EINVAL;
	}

	rc = of_property_read_u32_array(np, name, coords, coords_size);
	if (rc && (rc != -EINVAL)) {
		LOGD(LOG_ERR, "[touch]unable to read %s\n", name);
		return rc;
	}

	if (!strcmp(name, "raydium,display-coords")) {
		pdata->x_min = coords[0];
		pdata->y_min = coords[1];
		pdata->x_max = coords[2];
		pdata->y_max = coords[3];
	} else {
		LOGD(LOG_ERR, "[touch]unsupported property %s\n", name);
		return -EINVAL;
	}

	return 0;
}

/*******************************************************************************
 * FUNCTION: raydium_check_dsi_panel_dt
 *
 * SUMMARY: Get the DSI active panel information from dtsi
 *
 * RETURN:
 *   0 = success
 *   !0 = fail
 *
 * PARAMETERS:
 * np            -  pointer to device_node structure
 * active_panel  -  name of active DSI panel
 ******************************************************************************/

static int raydium_check_dsi_panel_dt(struct device_node *np, struct drm_panel **active_panel)
{
	int i = 0, rc = 0;
	int count = 0;
	struct device_node *node = NULL;
	struct drm_panel *panel;

	count = of_count_phandle_with_args(np, "panel", NULL);
	LOGD(LOG_INFO, "[touch]%s: Active panel count: %d\n", __func__, count);
	if (count <= 0)
		return 0;

	for (i = 0; i < count; i++) {
		node = of_parse_phandle(np, "panel", i);

		if (node != NULL)
			LOGD(LOG_ERR, "[touch]%s: Node handle successfully parsed !\n", __func__);
		panel = of_drm_find_panel(node);
		of_node_put(node);

		if (!IS_ERR(panel)) {
			LOGD(LOG_ERR, "[touch]%s: Active panel selected !\n", __func__);
			*active_panel = panel;
			return 0;
		}
	}
	LOGD(LOG_ERR, "[touch]%s: Active panel NOT selected !\n", __func__);
	rc = PTR_ERR(panel);
	return rc;
}

static int raydium_parse_dt(struct device *dev,
			    struct raydium_ts_platform_data *pdata)
{
	struct device_node *np = dev->of_node;
	struct drm_panel *active_panel = NULL;
	int rc = 0;
	u32 temp_val = 0;

	pdata->name = RAYDIUM_NAME;

	rc = raydium_get_dt_coords(dev, "raydium,display-coords", pdata);
	if (rc)
		return rc;


	/* reset, irq gpio info */
	pdata->reset_gpio = of_get_named_gpio_flags(np,
			    "raydium,reset-gpio",
			    0,
			    &pdata->reset_gpio_flags);
	//if (pdata->reset_gpio < 0)
	if ((s32)(pdata->reset_gpio) < 0)
		return pdata->reset_gpio;


	pdata->irq_gpio = of_get_named_gpio_flags(np,
			  "raydium,irq-gpio",
			  0,
			  &pdata->irq_gpio_flags);
	//if (pdata->irq_gpio < 0)
	if ((s32)(pdata->irq_gpio) < 0)
		return pdata->irq_gpio;

	rc = raydium_check_dsi_panel_dt(np, &active_panel);
	LOGD(LOG_ERR, "[touch]%s: Panel not selected, rc=%d\n", __func__, rc);
	if (rc) {
		LOGD(LOG_ERR, "[touch]%s: Panel not selected, rc=%d\n", __func__, rc);
		if (rc == -EPROBE_DEFER) {
			LOGD(LOG_ERR, "[touch]%s: Probe defer selected, rc=%d\n", __func__, rc);
			return rc;
		}
	}
	pdata->active_panel = active_panel;
	LOGD(LOG_ERR, "[touch]%s: Successful insert of active panel in core data\n", __func__);

	rc = of_property_read_u32(np,
				  "raydium,hard-reset-delay-ms", &temp_val);
	if (!rc)
		pdata->hard_rst_dly = temp_val;
	else
		return rc;


	rc = of_property_read_u32(np,
				  "raydium,soft-reset-delay-ms", &temp_val);
	if (!rc)
		pdata->soft_rst_dly = temp_val;
	else
		return rc;


	rc = of_property_read_u32(np, "raydium,num-max-touches", &temp_val);
	if (!rc)
		pdata->num_max_touches = temp_val;
	else
		return rc;
#ifdef FW_MAPPING_BYID_EN
	rc = of_property_read_u32(np, "raydium,fw_id", &temp_val);
	if (!rc)
		pdata->fw_id = temp_val;
	else
		return rc;
#endif
	return 0;
}
#else
static int raydium_parse_dt(struct device *dev,
			    struct raydium_ts_platform_data *pdata)
{
	return -ENODEV;
}
#endif /*end of CONFIG_OF*/

static void raydium_input_set(struct input_dev *input_dev)
{
	int ret = 0;
	unsigned char i;

	input_dev->name = "raydium_ts";/*name need same with .idc*/
	input_dev->id.bustype = BUS_I2C;
	input_dev->dev.parent = &g_raydium_ts->client->dev;
	input_dev->open = raydium_ts_open;/*touch lock*/
	input_dev->close = raydium_ts_close;
	input_set_drvdata(input_dev, g_raydium_ts);

	__set_bit(EV_KEY, input_dev->evbit);
	__set_bit(EV_ABS, input_dev->evbit);
	__set_bit(BTN_TOUCH, input_dev->keybit);
	__set_bit(INPUT_PROP_DIRECT, input_dev->propbit);
	LOGD(LOG_INFO, "[touch]set abs prarams x[%d], y[%d]\n",
	     g_raydium_ts->x_max, g_raydium_ts->y_max);

	/* Multitouch input params setup */
	input_set_abs_params(input_dev, ABS_MT_POSITION_X, 0,
			     g_raydium_ts->x_max, 0, 0);
	input_set_abs_params(input_dev, ABS_MT_POSITION_Y, 0,
			     g_raydium_ts->y_max, 0, 0);
	input_set_abs_params(input_dev, ABS_MT_PRESSURE, 0, PRESS_MAX, 0, 0);
	input_set_abs_params(input_dev,
			     ABS_MT_TOUCH_MAJOR, 0, WIDTH_MAX, 0, 0);
	input_set_abs_params(input_dev,
			     ABS_MT_TOUCH_MINOR, 0, WIDTH_MAX, 0, 0);

	ret = input_mt_init_slots(input_dev, MAX_TOUCH_NUM,
				  INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED);
	if (ret)
		LOGD(LOG_ERR, "[touch]failed to initialize MT slots: %d\n", ret);

	for (i = 0; i < (MAX_TOUCH_NUM * 2); i++)
		gst_slot[i] = gst_slot_init;

}

void touch_notify_glink_channel_state(bool state)
{
	LOGD(LOG_INFO, "%s:[touch] channel state: %d\n", __func__, state);
}

void glink_touch_rx_msg(void *data, int len)
{
	int rc = 0;

	LOGD(LOG_INFO, "%s:[touch]TOUCH_RX_MSG Start:\n", __func__);

	if (len > TOUCH_GLINK_INTENT_SIZE) {
		LOGD(LOG_ERR, "Invalid TOUCH glink intent size\n");
		return;
	}

	/* check SLATE response */
	slate_ack_resp = *(uint32_t *)&data[8];
	LOGD(LOG_INFO, "[touch]slate_ack_resp :%0x\n", slate_ack_resp);
	if (slate_ack_resp == 0x01) {
			LOGD(LOG_INFO,"Bad SLATE response\n");
			rc = -EINVAL;
			goto err_ret;
	}
	LOGD(LOG_INFO, "%s:[touch]TOUCH_RX_MSG End:\n", __func__);
err_ret:
return;
}

static int raydium_set_resolution(void)
{
	unsigned char u8_buf[4];
	int i32_ret = -1;
	unsigned int u32_x, u32_y;

	mutex_lock(&g_raydium_ts->lock);

	i32_ret = raydium_i2c_pda2_set_page(g_raydium_ts->client,
					    g_raydium_ts->is_suspend,
					    RAYDIUM_PDA2_PAGE_0);
	if (i32_ret < 0)
		goto exit_error;

	i32_ret = raydium_i2c_pda2_read(g_raydium_ts->client,
					RAYDIUM_PDA2_DISPLAY_INFO_ADDR,
					u8_buf, 4);
	if (i32_ret < 0)
		goto exit_error;

	u32_x = u8_buf[3] << 8 | u8_buf[2];
	u32_y = u8_buf[1] << 8 | u8_buf[0];

	LOGD(LOG_DEBUG, "[touch]RAD display info x:%d, y:%d\n", u32_x, u32_y);

	if (u32_x > 100 && u32_y > 100 &&
	    u32_x < 600 && u32_y < 600) {
		g_raydium_ts->x_max = u32_x - 1;
		g_raydium_ts->y_max = u32_y - 1;
	}

exit_error:
	mutex_unlock(&g_raydium_ts->lock);
	return i32_ret;
}
static int raydium_get_regulator(struct raydium_ts_data *cd, bool get)
{
	int rc;

	if (!get) {
		rc = 0;
		goto regulator_put;
	}
#ifdef VDD_ANALOG_ENABLE
	cd->vdd = regulator_get(&cd->client->dev, "vdd");
	if (IS_ERR(cd->vdd)) {
		rc = PTR_ERR(cd->vdd);
		dev_err(&cd->client->dev,
			"Regulator get failed vdd rc=%d\n", rc);
		goto regulator_put;
	}
#endif

	cd->vcc_i2c = regulator_get(&cd->client->dev, "vcc_i2c");
	if (IS_ERR(cd->vcc_i2c)) {
		rc = PTR_ERR(cd->vcc_i2c);
		dev_err(&cd->client->dev,
			"Regulator get failed vcc_i2c rc=%d\n", rc);
		goto regulator_put;
	}

	return 0;

regulator_put:
#ifdef VDD_ANALOG_ENABLE
	if (!IS_ERR(cd->vdd)) {
		dev_err(&cd->client->dev, "Regulator put vdd\n");
		regulator_put(cd->vdd);
		cd->vdd = NULL;
	}
#endif

	if (!IS_ERR(cd->vcc_i2c)) {
		dev_err(&cd->client->dev, "Regulator put vcc_i2c\n");
		regulator_put(cd->vcc_i2c);
		cd->vcc_i2c = NULL;
	}

	return rc;
}

static int raydium_enable_regulator(struct raydium_ts_data *cd, bool en)
{
	int rc;

	if (!en) {
		rc = 0;
		goto disable_vcc_i2c_reg;
	}
#ifdef VDD_ANALOG_ENABLE
	if (cd->vdd) {
		if (regulator_count_voltages(cd->vdd) > 0) {
			rc = regulator_set_voltage(cd->vdd, VTG_MIN_UV,
						VTG_MAX_UV);
			if (rc) {
				dev_err(&cd->client->dev,
					"Regulator set_vtg failed vdd rc=%d\n", rc);
				goto exit;
			}
		}

		rc = regulator_enable(cd->vdd);
		if (rc) {
			dev_err(&cd->client->dev,
				"Regulator vdd enable failed rc=%d\n", rc);
			goto exit;
		}
	}
#endif

	if (cd->vcc_i2c) {
		if (regulator_count_voltages(cd->vcc_i2c) > 0) {
			rc = regulator_set_voltage(cd->vcc_i2c, I2C_VTG_MIN_UV,
							I2C_VTG_MAX_UV);
			if (rc) {
				dev_err(&cd->client->dev,
					"Regulator set_vtg failed vcc_i2c rc=%d\n", rc);
				goto disable_vdd_reg;
			}
		}

		rc = regulator_enable(cd->vcc_i2c);
		if (rc) {
			dev_err(&cd->client->dev,
				"Regulator vcc_i2c enable failed rc=%d\n", rc);
			goto disable_vdd_reg;
		}
	}

	return 0;

disable_vcc_i2c_reg:
	if (cd->vcc_i2c) {
		if (regulator_count_voltages(cd->vcc_i2c) > 0)
			regulator_set_voltage(cd->vcc_i2c, I2C_VTG_MIN_UV,
						I2C_VTG_MAX_UV);

		regulator_disable(cd->vcc_i2c);
	}

disable_vdd_reg:
#ifdef VDD_ANALOG_ENABLE
	if (cd->vdd) {
		if (regulator_count_voltages(cd->vdd) > 0)
			regulator_set_voltage(cd->vdd, VTG_MIN_UV,
						VTG_MAX_UV);

		regulator_disable(cd->vdd);
	}
#endif

#ifdef VDD_ANALOG_ENABLE
exit:
#endif
	return rc;
}

static int raydium_ts_probe(struct i2c_client *client,
		const struct i2c_device_id *id)
{
	struct raydium_ts_platform_data *pdata =
		(struct raydium_ts_platform_data *)client->dev.platform_data;

	struct input_dev *input_dev;
	unsigned short u16_i2c_data;
	int ret = 0;

	LOGD(LOG_INFO, "[touch] probe\n");

	if (client->dev.of_node) {
		pdata = devm_kzalloc(&client->dev,
				     sizeof(struct raydium_ts_platform_data),
				     GFP_KERNEL);
		if (!pdata) {
			LOGD(LOG_ERR, "[touch]failed to allocate memory\n");
			return -ENOMEM;
		}

		ret = raydium_parse_dt(&client->dev, pdata);
		if (ret) {
			LOGD(LOG_ERR, "[touch]device tree parsing failed\n");
			goto parse_dt_failed;
		}
	} else
		pdata = client->dev.platform_data;

	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
		ret = -ENODEV;
		goto exit_check_functionality_failed;
	}

	g_raydium_ts = devm_kzalloc(&client->dev,
				    sizeof(struct raydium_ts_data),
				    GFP_KERNEL);
	if (!g_raydium_ts) {
		LOGD(LOG_ERR, "[touch]failed to allocate input driver data\n");
		return -ENOMEM;
	}

	raydium_variable_init();

	mutex_init(&g_raydium_ts->lock);

	i2c_set_clientdata(client, g_raydium_ts);
	g_raydium_ts->irq_enabled = false;
	g_raydium_ts->irq_wake = false;

	g_raydium_ts->irq_gpio = pdata->irq_gpio;
	g_raydium_ts->rst_gpio = pdata->reset_gpio;
	client->irq = g_raydium_ts->irq_gpio;
	g_raydium_ts->u8_max_touchs = pdata->num_max_touches;
	g_raydium_ts->client = client;
	g_raydium_ts->x_max = pdata->x_max - 1;
	g_raydium_ts->y_max = pdata->y_max - 1;
	g_raydium_ts->is_suspend = 0;
	g_raydium_ts->is_sleep = 0;


#ifdef GESTURE_EN
	g_raydium_ts->is_palm = 0;
#endif
	g_raydium_ts->fw_version = 0;
	device_init_wakeup(&client->dev, 1);

#ifdef MSM_NEW_VER
	ret = raydium_ts_pinctrl_init();
	if (!ret && g_raydium_ts->ts_pinctrl) {
		/*
		 * Pinctrl handle is optional. If pinctrl handle is found
		 * let pins to be configured in active state. If not
		 * found continue further without error.
		 */
		ret = pinctrl_select_state(g_raydium_ts->ts_pinctrl,
					   g_raydium_ts->pinctrl_state_active);
		if (ret < 0)
			LOGD(LOG_ERR, "[touch]failed to set pin to active state\n");
	}
#endif /*end of MSM_NEW_VER*/

	ret = raydium_get_regulator(g_raydium_ts, true);
	if (ret) {
		dev_err(&client->dev, "Failed to get voltage regulators\n");
		goto error_alloc_data;
	}

	ret = raydium_enable_regulator(g_raydium_ts, true);
	if (ret) {
		dev_err(&client->dev, "Failed to enable regulators: rc=%d\n", ret);
		goto error_get_regulator;
	}
	ret = raydium_gpio_configure(true);
	if (ret < 0) {
		LOGD(LOG_ERR, "[touch]failed to configure the gpios\n");
		goto err_gpio_req;
	}
	/*modify dtsi to 360*/
	msleep(pdata->soft_rst_dly);
	if (raydium_disable_i2c_deglitch() == ERROR) {
		LOGD(LOG_ERR, "[touch]disable i2c deglicth NG!\r\n");
		ret = -ENODEV;
		goto exit_check_i2c;
	}

	/*print touch i2c ready*/
	ret = raydium_check_i2c_ready(&u16_i2c_data);
	if (ret < 0 || (u16_i2c_data == 0)) {
		LOGD(LOG_ERR, "[touch]Check I2C failed\n");
		ret = -EPROBE_DEFER;
		goto exit_check_i2c;
	}

	glink_touch_channel_init(&touch_notify_glink_channel_state, &glink_touch_rx_msg);

#if defined(CONFIG_DRM) || defined(CONFIG_PANEL_NOTIFIER)
	/* Setup active dsi panel */
	active_panel = pdata->active_panel;
#endif
	/*input device initialization*/
	input_dev = input_allocate_device();
	if (!input_dev) {
		ret = -ENOMEM;
		LOGD(LOG_ERR, "[touch]failed to allocate input device\n");
		goto exit_input_dev_alloc_failed;
	}

	raydium_set_resolution();

	g_raydium_ts->input_dev = input_dev;
	raydium_input_set(input_dev);

	ret = input_register_device(input_dev);
	if (ret) {
		LOGD(LOG_ERR, "[touch]failed to register input device: %s\n",
		     dev_name(&client->dev));
		goto exit_input_register_device_failed;
	}

#ifdef GESTURE_EN
	input_set_capability(input_dev, EV_KEY, KEY_SLEEP);
	input_set_capability(input_dev, EV_KEY, KEY_WAKEUP);
#endif

	/*suspend/resume routine*/
#if defined(CONFIG_FB)
	raydium_register_notifier();
#elif defined(CONFIG_HAS_EARLYSUSPEND)
	/*Early-suspend level*/
	g_raydium_ts->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1;
	g_raydium_ts->early_suspend.suspend = raydium_ts_early_suspend;
	g_raydium_ts->early_suspend.resume = raydium_ts_late_resume;
	register_early_suspend(&g_raydium_ts->early_suspend);
#endif/*end of CONFIG_FB*/

#ifdef CONFIG_RM_SYSFS_DEBUG
	raydium_create_sysfs(client);
#endif/*end of CONFIG_RM_SYSFS_DEBUG*/

	INIT_WORK(&g_raydium_ts->work, raydium_work_handler);

	g_raydium_ts->workqueue = create_singlethread_workqueue("raydium_ts");
	/*irq_gpio = 13 irqflags = 108*/
	LOGD(LOG_DEBUG, "[touch]pdata irq : %d\n", g_raydium_ts->irq_gpio);
	LOGD(LOG_DEBUG, "[touch]client irq : %d, pdata flags : %d\n",
	     client->irq, pdata->irqflags);
#if defined(CONFIG_PANEL_NOTIFIER)
	LOGD(LOG_DEBUG, "%s: Probe: Setup panel event notifier\n", __func__);
	raydium_setup_panel_notifier(g_raydium_ts);
#elif defined(CONFIG_DRM)
	LOGD(LOG_DEBUG, "%s: Probe: Setup drm notifier\n", __func__);
	raydium_setup_drm_notifier(g_raydium_ts);
#endif/*end of CONFIG_DRM*/

	g_raydium_ts->irq = gpio_to_irq(pdata->irq_gpio);
	ret = request_threaded_irq(g_raydium_ts->irq, NULL, raydium_ts_interrupt,
				   IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
				   client->dev.driver->name, g_raydium_ts);
	if (ret < 0) {
		LOGD(LOG_ERR, "[touch]raydium_probe: request irq failed\n");
		goto exit_irq_request_failed;
	}

	g_raydium_ts->irq_desc = irq_to_desc(g_raydium_ts->irq);
	g_raydium_ts->irq_enabled = true;
	g_raydium_ts->touch_offload = false;

	/*disable_irq then enable_irq for avoid Unbalanced enable for IRQ */

	/*raydium_irq_control(ts, ENABLE);*/

	LOGD(LOG_DEBUG, "[touch]RAD Touch driver ver :0x%X\n", g_u32_driver_version);

	/*fw update check*/
	ret = raydium_fw_update_init(u16_i2c_data);
	if (ret < 0) {
		LOGD(LOG_ERR, "[touch]FW update init failed\n");
		ret = -ENODEV;
		goto exit_irq_request_failed;
	}

	LOGD(LOG_INFO, "[touch] probe: done\n");
	return 0;

exit_irq_request_failed:
#if defined(CONFIG_FB)
	raydium_unregister_notifier();
#elif defined(CONFIG_PANEL_NOTIFIER)
	panel_event_notifier_unregister(g_raydium_ts->entry);
#elif defined(CONFIG_DRM)
        raydium_setup_drm_unregister_notifier();
#endif

	cancel_work_sync(&g_raydium_ts->work);
	input_unregister_device(input_dev);
	g_raydium_ts->input_dev = NULL;

exit_input_register_device_failed:
	if (g_raydium_ts->input_dev)
		input_free_device(input_dev);
	g_raydium_ts->input_dev = NULL;

exit_input_dev_alloc_failed:
exit_check_i2c:
#ifdef MSM_NEW_VER
	if (g_raydium_ts->ts_pinctrl) {
		if (IS_ERR_OR_NULL(g_raydium_ts->pinctrl_state_release)) {
			devm_pinctrl_put(g_raydium_ts->ts_pinctrl);
			g_raydium_ts->ts_pinctrl = NULL;
		} else {
			if (pinctrl_select_state(g_raydium_ts->ts_pinctrl,
					g_raydium_ts->pinctrl_state_release))
				LOGD(LOG_ERR,
				    "[touch]pinctrl_select_state failed\n");
		}
	}
#endif/*end of MSM_NEW_VER*/

	if (gpio_is_valid(pdata->reset_gpio))
		gpio_free(pdata->reset_gpio);

	if (gpio_is_valid(pdata->irq_gpio))
		gpio_free(pdata->irq_gpio);

err_gpio_req:
	raydium_enable_regulator(g_raydium_ts, false);

error_get_regulator:
	raydium_get_regulator(g_raydium_ts, false);
error_alloc_data:
parse_dt_failed:
exit_check_functionality_failed:
	return ret;

}


void raydium_ts_shutdown(struct i2c_client *client)
{

	LOGD(LOG_INFO, "[touch] %s: start\n", __func__);

	cancel_work_sync(&g_raydium_ts->work);
	if (g_raydium_ts->workqueue) {
		destroy_workqueue(g_raydium_ts->workqueue);
		g_raydium_ts->workqueue = NULL;
	}
#if defined(CONFIG_FB)
	raydium_unregister_notifier();
#elif defined(CONFIG_HAS_EARLYSUSPEND)
	unregister_early_suspend(&g_raydium_ts->early_suspend);
#elif defined(CONFIG_PANEL_NOTIFIER)
if (active_panel)
	panel_event_notifier_unregister(g_raydium_ts->entry);
#elif defined(CONFIG_DRM)
if (active_panel)
	drm_panel_notifier_unregister(active_panel, &g_raydium_ts->fb_notif);
#endif/*end of CONFIG_FB*/
	input_unregister_device(g_raydium_ts->input_dev);
	g_raydium_ts->input_dev = NULL;
	gpio_free(g_raydium_ts->rst_gpio);

#ifdef CONFIG_RM_SYSFS_DEBUG
	raydium_release_sysfs(client);
#endif /*end of CONFIG_RM_SYSFS_DEBUG*/

	disable_irq(g_raydium_ts->irq);
	free_irq(client->irq, g_raydium_ts);

	if (gpio_is_valid(g_raydium_ts->rst_gpio))
		gpio_free(g_raydium_ts->rst_gpio);

	if (gpio_is_valid(g_raydium_ts->irq_gpio))
		gpio_free(g_raydium_ts->irq_gpio);


	raydium_enable_regulator(g_raydium_ts, false);
	raydium_get_regulator(g_raydium_ts, false);

	devm_kfree(&client->dev, g_raydium_ts);
	g_raydium_ts = NULL;

	i2c_set_clientdata(client, NULL);
	LOGD(LOG_INFO, "[touch] %s: done\n", __func__);
}

static int raydium_ts_remove(struct i2c_client *client)
{

	LOGD(LOG_INFO, "[touch] %s: start\n", __func__);

	cancel_work_sync(&g_raydium_ts->work);
	if (g_raydium_ts->workqueue) {
		destroy_workqueue(g_raydium_ts->workqueue);
		g_raydium_ts->workqueue = NULL;
	}
#if defined(CONFIG_FB)
	raydium_unregister_notifier();
#elif defined(CONFIG_HAS_EARLYSUSPEND)
	unregister_early_suspend(&g_raydium_ts->early_suspend);
#elif defined(CONFIG_PANEL_NOTIFIER)
if (active_panel)
	panel_event_notifier_unregister(g_raydium_ts->entry);
#elif defined(CONFIG_DRM)
if (active_panel)
	drm_panel_notifier_unregister(active_panel, &g_raydium_ts->fb_notif);
#endif/*end of CONFIG_FB*/
	input_unregister_device(g_raydium_ts->input_dev);
	g_raydium_ts->input_dev = NULL;
	gpio_free(g_raydium_ts->rst_gpio);

#ifdef CONFIG_RM_SYSFS_DEBUG
	raydium_release_sysfs(client);
#endif /*end of CONFIG_RM_SYSFS_DEBUG*/

	disable_irq(g_raydium_ts->irq);
	free_irq(client->irq, g_raydium_ts);

	if (gpio_is_valid(g_raydium_ts->rst_gpio))
		gpio_free(g_raydium_ts->rst_gpio);

	if (gpio_is_valid(g_raydium_ts->irq_gpio))
		gpio_free(g_raydium_ts->irq_gpio);


	raydium_enable_regulator(g_raydium_ts, false);
	raydium_get_regulator(g_raydium_ts, false);

	devm_kfree(&client->dev, g_raydium_ts);
	g_raydium_ts = NULL;

	i2c_set_clientdata(client, NULL);
	LOGD(LOG_INFO, "[touch] %s: done\n", __func__);
	return 0;
}

static const struct i2c_device_id raydium_ts_id[] = {
	{RAYDIUM_NAME, 0},
	{}
};

MODULE_DEVICE_TABLE(i2c, raydium_ts_id);

#ifdef CONFIG_OF
static const struct of_device_id raydium_match_table[] = {
	{ .compatible = "raydium,raydium-ts",},
	{ },
};
#else
#define raydium_match_table NULL
#endif/*end of CONFIG_OF*/

static struct i2c_driver raydium_ts_driver = {
	.probe = raydium_ts_probe,
	.remove = raydium_ts_remove,
	.shutdown = raydium_ts_shutdown,
	.id_table = raydium_ts_id,
	.driver = {
		.name = RAYDIUM_NAME,
		.owner = THIS_MODULE,
		.of_match_table = raydium_match_table,
#if defined(CONFIG_PM)
		.pm    = &raydium_ts_pm_ops,
#endif/*end of CONFIG_PM*/
	},
};

static int __init raydium_ts_init(void)
{
	int ret;

	ret = i2c_add_driver(&raydium_ts_driver);
	return ret;
}

static void __exit raydium_ts_exit(void)
{
	i2c_del_driver(&raydium_ts_driver);
}

module_init(raydium_ts_init);
module_exit(raydium_ts_exit);

MODULE_AUTHOR("<Rejion>");
MODULE_DESCRIPTION("Raydium TouchScreen driver");
MODULE_LICENSE("GPL");