RE: [PATCH v2] upport Elan Touchscreen eKTF product.

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi Dmitry,
	I reply to your last question here. 
	Your review is the one I want to ignore it and this is the right
patch for v2. 
	Sorry for inconvenience.

	The kfifo_out_locked() was used by store_set_mode() sysfs attribute
function.
	I will improve the driver based on this version and according to
your suggestion.

Thanks,
Scott

> -----Original Message-----
> From: linux-input-owner@xxxxxxxxxxxxxxx
[mailto:linux-input-owner@xxxxxxxxxxxxxxx] On
> Behalf Of Scott Liu
> Sent: Wednesday, October 24, 2012 10:11 AM
> To: Scott Liu; Dmitry Torokhov; linux-input@xxxxxxxxxxxxxxx;
linux-i2c@xxxxxxxxxxxxxxx;
> linux-kernel@xxxxxxxxxxxxxxx
> Cc: Benjamin Tissoires; Jesse; Vincent Wang; Paul
> Subject: [PATCH v2] upport Elan Touchscreen eKTF product.
> 
> Hi Dmitry:
>         Sorry, please ignore my previous patch.
> 
> This patch is for Elan eKTF Touchscreen product, I2C adpater module.
> 
> Signed-off-by: Scott Liu <scott.liu@xxxxxxxxxx>
> ---
> Hi,
>         v2 revision I have fixed some bug as your advise.
>         1. To target the mainline
>         2. No Android dependency
>         3. reuse those duplication code from Henrik's patchset.
>                 (input_mt_sync_frame()  / input_mt_get_slot_by_key())
>         4. some typo and etc...
> 
>  drivers/input/touchscreen/Kconfig      |    9 +
>  drivers/input/touchscreen/Makefile     |    1 +
>  drivers/input/touchscreen/elants_i2c.c | 2533
++++++++++++++++++++++++++++++++
>  include/linux/i2c/elants.h             |   56 +
>  4 files changed, 2599 insertions(+)
>  create mode 100644 drivers/input/touchscreen/elants_i2c.c
>  create mode 100644 include/linux/i2c/elants.h
> 
> diff --git a/drivers/input/touchscreen/Kconfig
b/drivers/input/touchscreen/Kconfig
> index 1ba232c..50e6f05 100644
> --- a/drivers/input/touchscreen/Kconfig
> +++ b/drivers/input/touchscreen/Kconfig
> @@ -237,6 +237,15 @@ config TOUCHSCREEN_EETI
>  	  To compile this driver as a module, choose M here: the
>  	  module will be called eeti_ts.
> 
> +config TOUCHSCREEN_ELAN
> +         tristate "Elan touchscreen panel support"
> +         depends on I2C
> +         help
> +           Say Y here to enable support for I2C connected Elan touch
panels.
> +
> +           To compile this driver as a module, choose M here: the
> +           module will be called elants_i2c.
> +
>  config TOUCHSCREEN_EGALAX
>  	tristate "EETI eGalax multi-touch panel support"
>  	depends on I2C
> diff --git a/drivers/input/touchscreen/Makefile
b/drivers/input/touchscreen/Makefile
> index 178eb12..428a631 100644
> --- a/drivers/input/touchscreen/Makefile
> +++ b/drivers/input/touchscreen/Makefile
> @@ -28,6 +28,7 @@ obj-$(CONFIG_TOUCHSCREEN_EDT_FT5X06)	+=
edt-ft5x06.o
>  obj-$(CONFIG_TOUCHSCREEN_HAMPSHIRE)	+= hampshire.o
>  obj-$(CONFIG_TOUCHSCREEN_GUNZE)		+= gunze.o
>  obj-$(CONFIG_TOUCHSCREEN_EETI)		+= eeti_ts.o
> +obj-$(CONFIG_TOUCHSCREEN_ELAN)		+= elants_i2c.o
>  obj-$(CONFIG_TOUCHSCREEN_ELO)		+= elo.o
>  obj-$(CONFIG_TOUCHSCREEN_EGALAX)	+= egalax_ts.o
>  obj-$(CONFIG_TOUCHSCREEN_FUJITSU)	+= fujitsu_ts.o
> diff --git a/drivers/input/touchscreen/elants_i2c.c
b/drivers/input/touchscreen/elants_i2c.c
> new file mode 100644
> index 0000000..47546be
> --- /dev/null
> +++ b/drivers/input/touchscreen/elants_i2c.c
> @@ -0,0 +1,2533 @@
> +/*
> + * Elan Microelectronics touchpanels with I2C interface
> + *
> + * Copyright (C) 2012 Elan Microelectronics Corporation.
> + * Scott Liu <scott.liu@xxxxxxxxxx>
> + *
> + * This code is partly based on hid-multitouch.c:
> + *
> + *  Copyright (c) 2010-2012 Stephane Chatty <chatty@xxxxxxx>
> + *  Copyright (c) 2010-2012 Benjamin Tissoires <benjamin.tissoires@gmail.
com>
> + *  Copyright (c) 2010-2012 Ecole Nationale de l'Aviation Civile, France
> + *
> + */
> +
> +/*
> + * 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.
> + *
> + */
> +
> +#include <linux/module.h>
> +#include <linux/input.h>
> +#include <linux/interrupt.h>
> +#include <linux/platform_device.h>
> +#include <linux/i2c.h>
> +#include <linux/delay.h>
> +#include <linux/gpio.h>
> +#include <linux/jiffies.h>
> +#include <linux/hrtimer.h>
> +#include <linux/timer.h>
> +#include <linux/kthread.h>
> +#include <linux/miscdevice.h>
> +#include <linux/uaccess.h>
> +#include <linux/buffer_head.h>
> +#include <linux/version.h>
> +#include <linux/kfifo.h>
> +#include <linux/slab.h>
> +#include <linux/input/mt.h>
> +#include <linux/i2c/elants.h>
> +
> +
> +/* debug option */
> +static bool debug = false;
> +module_param(debug, bool, 0444);
> +MODULE_PARM_DESC(debug, "print a lot of debug information");
> +
> +#define elan_dbg(client, fmt, arg...)   \
> +	if (debug)      \
> +		dev_printk(KERN_DEBUG, &client->dev, fmt, ##arg)
> +
> +/*=================================================
> + *  Marco
> + *================================================= */
> +#define DRV_NAME        "elants_i2c"
> +
> +#define DRV_MA_VER 2
> +#define DRV_MI_VER 0
> +#define DRV_SUB_MI_VER 0
> +
> +#define _str(s) #s
> +#define str(s)  _str(s)
> +#define DRIVER_VERSION
> str(DRV_MA_VER.DRV_MI_VER.DRV_SUB_MI_VER)
> +
> +#define IDX_PACKET_SIZE_WIDTH   40
> +
> +#define MAX_CONTACT_NUM	10
> +
> +/* FW Power Saving Mode */
> +#define PWR_STATE_DEEP_SLEEP	0
> +#define PWR_STATE_NORMAL        1
> +#define PWR_STATE_MASK          BIT(3)
> +
> +/* kfifo buffer size, used for Read command handshake */
> +#define FIFO_SIZE       (64)
> +
> +/*! Convert from rows or columns into resolution */
> +#define ELAN_TS_RESOLUTION(n)   ((n - 1) * 64)
> +
> +static const char hello_packet[4] = { 0x55, 0x55, 0x55, 0x55 };
> +static const char iniap_packet[4] = { 0x55, 0xaa, 0x33, 0xcc };
> +static const char recov_packet[4] = { 0x55, 0x55, 0x80, 0x80 };
> +
> +
> +/*! driver status flag, should move to public header file */
> +#define STA_NONINIT         0x00000001
> +#define STA_INIT            0x00000002
> +#define STA_INIT2           0x00000004
> +#define STA_INIT3           0x00000100
> +#define STA_INIT4           0x00000200
> +#define STA_PROBED          0x00000008
> +#define STA_ERR_HELLO_PKT   0x00000010
> +#define STA_USE_IRQ         0x00000020
> +#define STA_SLEEP_MODE      0x00000040
> +
> +/*=======================================
> + *  Structure Definition
> + *=======================================*/
> +
> +/*! @enum elan i2c address definition */
> +enum elan_i2c_addr {
> +	elan_i2c_master = 0x10,
> +	elan_i2c_slave1 = 0x20,
> +	elan_i2c_slave2 = 0x21,
> +
> +	elan_i2c_maxnum = 3,
> +};
> +
> +/*! @enum finger_report_header Finger report header byte definition */
> +enum finger_report_header {
> +	idx_coordinate_packet_4_finger = 0x5c,
> +	idx_coordinate_packet_10_finger = 0x62,
> +};
> +
> +/*! @enum fw_queue_report_hdr FW Queue report header definition */
> +enum fw_queue_report_hdr {
> +	queue_header_byte_Single = 0x62,
> +	queue_header_byte_normal = 0x63,
> +	queue_header_byte_wait = 0x64,
> +	cmd_header_byte_rek = 0x66,
> +	queue_header_size = 4,
> +	queue_packet_max_len = queue_header_size + (IDX_PACKET_SIZE_WIDTH *
3),
> +};
> +
> +/*! @enum fw_normal_cmd_hdr FW Normal command header definition */
> +enum fw_normal_cmd_hdr {
> +	cmd_header_byte_write = 0x54,
> +	cmd_header_byte_read = 0x53,
> +	cmd_header_byte_response = 0x52,
> +	cmd_header_byte_hello = 0x55,
> +	cmd_response_len = 4
> +};
> +
> +/*! @enum fw_info_pos FW information position */
> +enum fw_info_pos {
> +	idx_finger_header = 0,
> +	idx_finger_state = 1,
> +	idx_finger_total = 2,
> +	idx_finger_checksum = 34,
> +	idx_finger_width = 35,
> +	idx_4finger_checksum = 17,
> +	idx_finger_width_checksum = 34,
> +};
> +
> +/*! @enum lock_bit Lock bit definition */
> +enum lock_bit {
> +	idx_file_operate = 0,
> +	idx_cmd_handshake = 1,
> +	idx_finger_report = 2,
> +	idx_update_fw = 3,
> +};
> +
> +enum kfifo_ret {
> +	ret_ok = 0,
> +	ret_cmdrsp = 1,
> +	ret_fail = -1,
> +};
> +
> +typedef enum elan_boot_e {
> +	E_BOOT_NORM = 0,
> +	E_BOOT_IAP = 1
> +} elan_boot_t;
> +
> +
> +/*! @struct <multi_queue_header> */
> +struct multi_queue_header {
> +	u8		packet_id;
> +	u8		report_count;
> +	u8		report_length;
> +	u8		reserved;
> +};
> +
> +/*! @brief elan_polling */
> +struct elan_polling {
> +	struct workqueue_struct *elan_wq;	/* polling work queue */
> +	struct timer_list timer;	/* Polling intr_gpio timer */
> +	u8 int_status;				/* polling intr gpio status
*/
> +};
> +
> +/* finger handler, refer to hid-multitouch.c */
> +struct mt_slot {
> +	__s32 x, y, p, w, h;
> +	__s32 contactid;	/* the device ContactID assigned to this
slot */
> +	bool touch_state;	/* is the touch valid? */
> +	bool seen_in_this_frame;/* has this slot been updated */
> +};
> +
> +struct mt_device {
> +	struct mt_slot curdata;	/* placeholder of incoming data */
> +	__u8 num_received;	/* how many contacts we received */
> +	__u8 num_expected;	/* expected last contact index */
> +	__u8 maxcontacts;
> +	bool curvalid;		/* is the current contact valid? */
> +	unsigned mt_flags;	/* flags to pass to input-mt */
> +	struct mt_slot *slots;
> +};
> +
> +
> +/**
> +*
> +* @brief elants_data
> +*
> +* all variable should include in this struct.
> +*
> +*/
> +struct elants_data {
> +	int intr_gpio;		/* interupter pin*/
> +	int rst_gpio;		/* reset pin*/
> +	int use_irq;
> +	u8 major_fw_version;
> +	u8 minor_fw_version;
> +	u8 major_bc_version;
> +	u8 minor_bc_version;
> +	u8 major_hw_id;
> +	u8 minor_hw_id;
> +	bool fw_enabled;	/* True if firmware device enabled*/
> +	int rows;			/* Panel geometry for input layer*/
> +	int cols;
> +	int x_max;
> +	int y_max;
> +	/* Power state 0:sleep 1:active*/
> +	u8 power_state;
> +	/* TS is in IAP mode already*/
> +#define IAP_MODE_ENABLE		1
> +	/* 1 : Firmware update mode
> +		0 : normal*/
> +	unsigned int iap_mode;
> +	unsigned int rx_size;		/* Read size in use*/
> +
> +	/* Multi-queue info */
> +	struct multi_queue_header mq_header;
> +
> +	/* our i2c client*/
> +	struct i2c_client *client;
> +	/* input device*/
> +	struct input_dev *input;
> +	/* normal function work queue*/
> +	struct work_struct work;
> +	/* start probe start*/
> +	struct task_struct	*thread;
> +	/* char device for ioctl and IAP*/
> +	struct miscdevice firmware;
> +	/*	regular polling work thread*/
> +	struct work_struct pollingwork;
> +	/*	regular polling work queue*/
> +	struct elan_polling polling;
> +
> +	/* Protects I2C accesses to device*/
> +	struct mutex mutex;
> +	/* Protects I2C tx/rx*/
> +	struct mutex tr_mutex;
> +
> +	/* device flags */
> +	unsigned long flags;
> +
> +	/* elan-iap i2c address*/
> +	unsigned short i2caddr;
> +
> +	/* fifo and processing */
> +	struct kfifo fifo;
> +
> +	/* Serialize operations around FIFO */
> +	struct mutex fifo_mutex;
> +	wait_queue_head_t wait;
> +	spinlock_t rx_kfifo_lock;
> +
> +	/* boot log */
> +	u8 boot_log[256];
> +
> +	/*! Add for TS driver debug */
> +	unsigned int status;
> +	long int irq_received;
> +	long int packet_received;
> +	long int packet_fail;
> +	long int touched_sync;
> +	long int no_touched_sync;
> +	long int checksum_correct;
> +	long int wdt_reset;
> +	u16 checksum_fail;
> +	u16 header_fail;
> +	u16	mq_header_fail;
> +	u16 drop_frame;
> +
> +	/* mt device */
> +	struct mt_device td;
> +};
> +
> +
> +
> +/*/============================================
> + *  Function prototype
> + *=============================================*/
> +
> +static void
> +elants_drop_packet(struct elants_data *ts);
> +static int
> +elan_hw_reset(struct i2c_client *client);
> +static int
> +elan_touch_pull_frame(struct elants_data *ts,
> +					  u8 *buf);
> +
> +/*=================================================
> + *  Global variable
> + *=================================================*/
> +
> +/*! for elan-iap char driver */
> +static struct miscdevice *private_ts;
> +
> +#define elants_acqurie_data(a, cmd, buf, c) \
> +	elants_async_recv_data(a, cmd, buf, c, c)
> +
> +/*=================================================
> + *  Function implement
> + *=================================================*/
> +static inline void elan_msleep(u32 t)
> +{
> +	/*
> +	 * If the sleeping time is 10us - 20ms, usleep_range() is
recommended.
> +	 * Read Documentation/timers/timers-howto.txt
> +	*/
> +	usleep_range(t*1000, t*1000 + 500);
> +}
> +
> +/**
> + *	@brief elan_ts_poll		-	polling intr pin status.
> + *	@param client : our i2c device
> + *
> + *	@retval 0 means intr pin is low,	\n
> + *	otherwise is high.
> + *
> + *	polling intr pin untill low and the maximus wait time is \b 200ms.
> + */
> +static int elan_ts_poll(struct i2c_client *client)
> +{
> +	struct elants_data *ts = i2c_get_clientdata(client);
> +	int status = 0, retry = 20;
> +
> +	do {
> +		status = gpio_get_value(ts->intr_gpio);
> +		elan_dbg(client,
> +				 "%s: status = %d\n", __func__, status);
> +		retry--;
> +		mdelay(10);
> +	} while (status != 0 && retry > 0);
> +
> +	elan_dbg(client,
> +			 "%s: poll interrupt status %s\n",
> +			 __func__, status == 1 ? "high" : "low");
> +	return (status == 0 ? 0 : -ETIMEDOUT);
> +}
> +
> +
> +/**
> + *	@brief  \b elants_async_recv_data		-	get TP
status
> + *	@param client : our i2c device
> + *	@param cmd : asking command
> + *	@param buf : result
> + *	@param size : command length usually.
> + *
> + *	set command type and TP will return its status in buf.
> + */
> +static int elants_async_recv_data(
> +	struct i2c_client *client,
> +	const uint8_t *cmd,
> +	uint8_t *buf, size_t tx_size,
> +	size_t rx_size)
> +{
> +	struct elants_data *ts = i2c_get_clientdata(client);
> +	dev_dbg(&client->dev,
> +			"[ELAN] Enter: %s\n", __func__);
> +
> +	if (buf == NULL)
> +		return -EINVAL;
> +
> +	mutex_lock(&ts->tr_mutex);
> +	if ((i2c_master_send(client, cmd, tx_size)) != tx_size) {
> +		dev_err(&client->dev,
> +				"%s: i2c_master_send failed\n", __func__);
> +		goto fail;
> +	}
> +
> +	if (unlikely(elan_ts_poll(client) < 0))
> +		goto fail;
> +	else {
> +		if (i2c_master_recv(client, buf, rx_size) != rx_size)
> +			goto fail;
> +		mutex_unlock(&ts->tr_mutex);
> +	}
> +
> +	return 0;
> +
> +fail:
> +	mutex_unlock(&ts->tr_mutex);
> +	return -EINVAL;
> +}
> +
> +
> +/**
> + *	@brief  \b elan_ts_set_data		-	set command to TP.
> + *	@param client : our i2c device
> + *	@param data : command or data which will send to TP.
> + *	@param len : command length usually.
> + *
> + *	set command to our TP.
> + */
> +static int elants_set_data(struct i2c_client *client,
> +						   const u8 *data, size_t
len)
> +{
> +	struct elants_data *ts = i2c_get_clientdata(client);
> +	struct i2c_adapter *adap = client->adapter;
> +	struct i2c_msg msg;
> +	int rc = 0;
> +
> +	dev_dbg(&client->dev, "[ELAN] Enter: %s\n", __func__);
> +	elan_dbg(client,
> +			 "dump cmd: %02x, %02x, %02x, %02x, addr=%x\n",
> +			 data[0], data[1], data[2], data[3], ts->i2caddr);
> +
> +	mutex_lock(&ts->tr_mutex);
> +
> +	msg.addr = ts->i2caddr;
> +	msg.flags = ts->client->flags & I2C_M_TEN;
> +	msg.len = len;
> +	msg.buf = (char *)data;
> +
> +	rc = i2c_transfer(adap, &msg, 1);
> +	if (rc != 1)
> +		dev_err(&ts->client->dev,
> +				"[ELAN] i2c_transfer write fail, rc=%d\n",
rc);
> +
> +	mutex_unlock(&ts->tr_mutex);
> +
> +	/* If everything went ok (i.e. 1 msg transmitted), return #bytes
> +	   transmitted, else error code. */
> +	return (rc == 1) ? len : rc;
> +
> +}
> +
> +/**
> + *	@brief  \b elan_ts_get_data		-	set command to TP.
> + *	@param client : our i2c device
> + *	@param data : data to be received from TP.
> + *	@param len : command length usually.
> + *
> + *	get data from our TP.
> + */
> +static int elants_get_data(
> +	struct i2c_client *client,
> +	const u8 *buf,
> +	size_t len)
> +{
> +	struct elants_data *ts = i2c_get_clientdata(client);
> +	struct i2c_adapter *adap = client->adapter;
> +	struct i2c_msg msg;
> +	int rc = 0;
> +
> +	dev_dbg(&client->dev,
> +			"[ELAN] Enter: %s id:0x%x\n", __func__,
ts->i2caddr);
> +
> +	mutex_lock(&ts->tr_mutex);
> +
> +	msg.addr = ts->i2caddr;
> +	msg.flags = client->flags & I2C_M_TEN;
> +	msg.flags |= I2C_M_RD;
> +	msg.len = len;
> +	msg.buf = (char *)buf;
> +
> +	rc = i2c_transfer(adap, &msg, 1);
> +	if (rc != 1)
> +		dev_err(&client->dev,
> +				"[ELAN] i2c_transfer read fail, rc=%d\n",
rc);
> +
> +	mutex_unlock(&ts->tr_mutex);
> +
> +	/* If everything went ok (i.e. 1 msg transmitted), return #bytes
> +	   transmitted, else error code. */
> +	return (rc == 1) ? len : rc;
> +}
> +
> +
> +static int elants_cmd_transfer_once(
> +	struct i2c_client *client,
> +	const u8 *sbuf, const u8 slen,
> +	u8 *rbuf, u8 rlen)
> +{
> +	int ret = 0;
> +    struct elants_data *ts =
> +			i2c_get_clientdata(client);
> +
> +	mutex_lock(&ts->mutex);
> +	set_bit(idx_cmd_handshake, &ts->flags);
> +	elants_set_data(client, sbuf, slen);
> +	mutex_unlock(&ts->mutex);
> +
> +	if (sbuf[0] == cmd_header_byte_read) {
> +		/* We will wait for non O_NONBLOCK handles until a signal or
data */
> +		mutex_lock(&ts->fifo_mutex);
> +
> +		while (kfifo_len(&ts->fifo) == 0) {
> +			mutex_unlock(&ts->fifo_mutex);
> +			ret = wait_event_interruptible_timeout(
> +					 ts->wait, kfifo_len(&ts->fifo),
> +					 msecs_to_jiffies(3000));
> +			if (ret <= 0) {
> +				ret = -ETIMEDOUT;
> +				dev_err(&client->dev,
> +						"timeout!! wake_up(ts->wait)
\n");
> +				goto err2;
> +			}
> +			mutex_lock(&ts->fifo_mutex);
> +		}
> +		if (elan_touch_pull_frame(ts, rbuf) < 0) {
> +			ret = -1;
> +			goto err1;
> +		}
> +
> +		pr_info("[ELAN] Get Data [%.2x:%.2x:%.2x:%.2x]\n",
> +				rbuf[0], rbuf[1], rbuf[2], rbuf[3]);
> +err1:
> +		mutex_unlock(&ts->fifo_mutex);
> +err2:
> +		clear_bit(idx_cmd_handshake, &ts->flags);
> +	}
> +
> +	return (ret > 0) ? 1 : ret;
> +}
> +
> +/**
> + *	@brief interfaces
> + *	provide the hardware and firmware information
> + */
> +static ssize_t show_fw_version_value(
> +	struct device *dev,
> +	struct device_attribute *attr,
> +	char *buf)
> +{
> +	struct i2c_client *client = to_i2c_client(dev);
> +	struct elants_data *ts = i2c_get_clientdata(client);
> +
> +	if (test_bit(idx_update_fw, &ts->flags))
> +		return -1;
> +
> +	return sprintf(buf, "%.2x %.2x\n",
> +				   ts->major_fw_version,
> +				   ts->minor_fw_version);
> +}
> +
> +
> +static ssize_t show_bc_version_value(
> +	struct device *dev,
> +	struct device_attribute *attr,
> +	char *buf)
> +{
> +	struct i2c_client *client = to_i2c_client(dev);
> +	struct elants_data *ts = i2c_get_clientdata(client);
> +
> +	return sprintf(buf, "%.2x %.2x\n",
> +				   ts->major_bc_version,
> +				   ts->minor_bc_version);
> +}
> +
> +static ssize_t show_drvver_value(
> +	struct device *dev,
> +	struct device_attribute *attr,
> +	char *buf)
> +{
> +	return sprintf(buf, "%s\n", DRIVER_VERSION);
> +}
> +
> +
> +static ssize_t show_intr_gpio(
> +	struct device *dev,
> +	struct device_attribute *attr,
> +	char *buf)
> +{
> +	int ret = 0;
> +	struct i2c_client *client = to_i2c_client(dev);
> +	struct elants_data *ts = i2c_get_clientdata(client);
> +
> +	if (test_bit(idx_update_fw, &ts->flags))
> +		return -1;
> +
> +	ret = gpio_get_value(ts->intr_gpio);
> +
> +	return sprintf(buf, "%d\n", ret);
> +}
> +
> +static ssize_t show_adapter_pkt_rvd(
> +	struct device *dev,
> +	struct device_attribute *attr,
> +	char *buf)
> +{
> +	struct i2c_client *client = to_i2c_client(dev);
> +	struct elants_data *ts = i2c_get_clientdata(client);
> +
> +	if (test_bit(idx_update_fw, &ts->flags))
> +		return -1;
> +
> +	return sprintf(buf, "irq_received=%ld packet_received=%ld " \
> +						"packet_fail=%ld
mq_hdr_fail=%d, " \
> +						"checksum_fail=%x
header_fail=%d, " \
> +						"poll_timer=%d,
wdt_reset=%ld\n",
> +				   ts->irq_received, ts->packet_received,
> +				   ts->packet_fail, ts->mq_header_fail,
> +				   ts->checksum_fail, ts->header_fail,
> +				   ts->drop_frame, ts->wdt_reset);
> +}
> +
> +static ssize_t show_queue_count(
> +	struct device *dev,
> +	struct device_attribute *attr,
> +	char *buf)
> +{
> +	struct i2c_client *client = to_i2c_client(dev);
> +	struct elants_data *ts = i2c_get_clientdata(client);
> +
> +	if (test_bit(idx_update_fw, &ts->flags))
> +		return -1;
> +
> +	return sprintf(buf, "queue_report_count=%d, report_length=%d\n",
> +				   ts->mq_header.report_count,
> +				   ts->mq_header.report_length);
> +}
> +
> +
> +static ssize_t store_power_mode(
> +	struct device *dev,
> +	struct device_attribute *attr,
> +	const char *buf, size_t count)
> +{
> +	int ret = 0;
> +	unsigned long val;
> +	const char AcMode[] = {0x54, 0x30, 0x00, 0x01};
> +	const char BtMode[] = {0x54, 0x38, 0x00, 0x01};
> +	char cmd[4];
> +	struct i2c_client *client = to_i2c_client(dev);
> +	struct elants_data *ts = i2c_get_clientdata(client);
> +
> +	if (test_bit(idx_update_fw, &ts->flags))
> +		return -1;
> +
> +	ret = kstrtoul(buf, 10, &val);
> +	if (ret)
> +		return ret;
> +
> +	switch (val) {
> +	case 0:
> +		memcpy(cmd, AcMode, sizeof(AcMode));
> +		break;
> +	case 1:
> +		memcpy(cmd, BtMode, sizeof(BtMode));
> +		break;
> +	default:
> +		return -1;
> +	}
> +
> +	mutex_lock(&ts->mutex);
> +	elants_set_data(ts->client, cmd, sizeof(cmd));
> +	mutex_unlock(&ts->mutex);
> +
> +	return count;
> +}
> +
> +static ssize_t show_power_mode(
> +	struct device *dev,
> +	struct device_attribute *attr,
> +	char *buf)
> +{
> +	const char RespCmd[] = {0x53, 0x30, 0x00, 0x01};
> +	char tbuf[4];
> +	struct i2c_client *client = to_i2c_client(dev);
> +	struct elants_data *ts = i2c_get_clientdata(client);
> +
> +	if (test_bit(idx_update_fw, &ts->flags))
> +		return -1;
> +
> +
> +	mutex_lock(&ts->mutex);
> +	set_bit(idx_cmd_handshake, &ts->flags);
> +	elants_acqurie_data(ts->client, RespCmd, tbuf, sizeof(RespCmd));
> +	if (tbuf[0] != cmd_header_byte_response) {
> +		dev_err(&client->dev,
> +				"exception!! %x:%x:%x:%x\n",
> +				tbuf[0], tbuf[1], tbuf[2], tbuf[3]);
> +		elants_drop_packet(ts);
> +		memset(tbuf, 0x0, sizeof(tbuf));
> +	}
> +	clear_bit(idx_cmd_handshake, &ts->flags);
> +	mutex_unlock(&ts->mutex);
> +
> +	return sprintf(buf, "%x:%x:%x:%x\n",
> +				   tbuf[0], tbuf[1], tbuf[2], tbuf[3]);
> +}
> +
> +static ssize_t show_report_rate(
> +	struct device *dev,
> +	struct device_attribute *attr,
> +	char *buf)
> +{
> +	struct i2c_client *client = to_i2c_client(dev);
> +	struct elants_data *ts = i2c_get_clientdata(client);
> +	long int old_frame, new_frame;
> +
> +	old_frame = ts->packet_received;
> +	ssleep(1);
> +	new_frame = ts->packet_received;
> +
> +	return sprintf(buf, "%ld\n", new_frame - old_frame);
> +}
> +
> +static ssize_t show_iap_mode(
> +	struct device *dev,
> +	struct device_attribute *attr,
> +	char *buf)
> +{
> +	struct i2c_client *client = to_i2c_client(dev);
> +	struct elants_data *ts = i2c_get_clientdata(client);
> +
> +	return sprintf(buf, "%s\n",
> +				   (ts->iap_mode == 0) ? "Normal" :
"Recovery");
> +}
> +
> +static ssize_t show_recal(
> +	struct device *dev,
> +	struct device_attribute *attr,
> +	char *buf)
> +{
> +	struct i2c_client *client = to_i2c_client(dev);
> +	struct elants_data *ts = i2c_get_clientdata(client);
> +	u8 sbuf[4], retstr[32] = "re-K finish";
> +
> +	u8 w_flashkey[4] = {0x54, 0xC0, 0xE1, 0x5A};
> +	u8 rek[4] = {0x54, 0x29, 0x00, 0x01};
> +
> +	ts->i2caddr = elan_i2c_master;
> +	elants_set_data(client, w_flashkey, 4);
> +	elan_msleep(1);
> +	elants_set_data(client, rek, 4);
> +
> +	while (gpio_get_value(ts->intr_gpio) == 0) {
> +		if (elants_get_data(client, sbuf, 4) != 4)
> +			sprintf(retstr, "re-K Fail");
> +		pr_info("[ELAN] buf=%x:%x:%x:%x\n", buf[0],
> +				sbuf[1], sbuf[2], sbuf[3]);
> +	}
> +
> +	return sprintf(buf, "%s\n", retstr);
> +}
> +
> +
> +static ssize_t show_boot_log(
> +	struct device *dev,
> +	struct device_attribute *attr,
> +	char *buf)
> +{
> +	struct i2c_client *client = to_i2c_client(dev);
> +	struct elants_data *ts = i2c_get_clientdata(client);
> +
> +	/* show boot status, allow user cat this log during iap mode
enable!! */
> +
> +	return scnprintf(buf, PAGE_SIZE, ts->boot_log);
> +}
> +
> +static ssize_t store_set_mode(
> +	struct device *dev,
> +	struct device_attribute *attr,
> +	const char *buf, size_t count)
> +{
> +	int ret;
> +	unsigned int cmds[32];
> +	u8 recv_buf[32];
> +	struct i2c_client *client = to_i2c_client(dev);
> +	struct elants_data *ts = i2c_get_clientdata(client);
> +
> +	if (test_bit(idx_update_fw, &ts->flags))
> +		return -1;
> +
> +	/* get input */
> +	sscanf(buf, "%x %x %x %x", &cmds[0], &cmds[1], &cmds[2], &cmds[3]);
> +
> +	if (cmds[0] != cmd_header_byte_read &&
> +		cmds[0] != cmd_header_byte_write)
> +		return -EFAULT;
> +
> +	pr_info("[ELAN] Command %.2x:%.2x:%.2x:%.2x\n",
> +			cmds[0], cmds[1], cmds[2], cmds[3]);
> +
> +	ret = elants_cmd_transfer_once(client,
> +								   (const u8
*)cmds, 4, recv_buf, 4);
> +
> +	return (ret > 0) ? count : -1;
> +}
> +
> +
> +
> +static DEVICE_ATTR(cmd_mode, S_IWUGO, NULL, store_set_mode);
> +static DEVICE_ATTR(power_mode, S_IRUGO|S_IWUGO,
> +				   show_power_mode, store_power_mode);
> +static DEVICE_ATTR(queue_count, S_IRUGO, show_queue_count, NULL);
> +static DEVICE_ATTR(drv_version, S_IRUGO, show_drvver_value, NULL);
> +static DEVICE_ATTR(fw_version, S_IRUGO, show_fw_version_value, NULL);
> +static DEVICE_ATTR(bc_version, S_IRUGO, show_bc_version_value, NULL);
> +static DEVICE_ATTR(ts_packet, S_IRUGO, show_adapter_pkt_rvd, NULL);
> +static DEVICE_ATTR(gpio, S_IRUGO, show_intr_gpio, NULL);
> +static DEVICE_ATTR(report_rate, S_IRUGO, show_report_rate, NULL);
> +static DEVICE_ATTR(boot_log, S_IRUGO, show_boot_log, NULL);
> +static DEVICE_ATTR(iap_mode, S_IRUGO, show_iap_mode, NULL);
> +static DEVICE_ATTR(rek, S_IRUGO, show_recal, NULL);
> +
> +
> +
> +static struct attribute *elan_attributes[] = {
> +	&dev_attr_cmd_mode.attr,
> +	&dev_attr_power_mode.attr,
> +	&dev_attr_queue_count.attr,
> +	&dev_attr_fw_version.attr,
> +	&dev_attr_drv_version.attr,
> +	&dev_attr_bc_version.attr,
> +	&dev_attr_gpio.attr,
> +	&dev_attr_ts_packet.attr,
> +	&dev_attr_report_rate.attr,
> +	&dev_attr_boot_log.attr,
> +	&dev_attr_iap_mode.attr,
> +	&dev_attr_rek.attr,
> +
> +	NULL
> +};
> +
> +
> +static struct attribute_group elan_attribute_group = {
> +	.name	= "elants",
> +	.attrs	= elan_attributes,
> +};
> +
> +
> +/**
> + *	@brief elan_hw_reset		-	h/w reset.
> + *	@param client : our i2c device
> + *
> + *	@retval >0 means reset success,	\n
> + *	otherwise is fail.
> + *
> + */
> +static int elan_hw_reset(struct i2c_client *client)
> +{
> +	struct elants_data *ts = i2c_get_clientdata(client);
> +	int ret;
> +
> +	if (ts->rst_gpio < 0)
> +		return -1;
> +
> +	ret = gpio_direction_output(ts->rst_gpio, 0);
> +	if (ret < 0) {
> +		pr_err("gpio_direction fail!\n");
> +		return ret;
> +	}
> +
> +	elan_msleep(2);
> +
> +	ret = gpio_direction_output(ts->rst_gpio, 1);
> +	if (ret < 0)
> +		return ret;
> +
> +	/* wait > 10ms to ensure that fw is in IAP mode */
> +	msleep(20);
> +
> +	return ret;
> +}
> +
> +
> +/**
> + *	@brief  \b elants_is_iap		-	is it in iap mode ?
> + *	@param client : our i2c device
> + *	@param addr : i2c address
> + *
> + *	check whether fw currently is in iap.
> + *	@return :
> + *		 < 0 :normal mode
> + *		 > 0 :iap mode or abnormal.
> + *		-EINVAL : addr overflow, no such device
> + */
> +static int elants_is_iap(
> +	struct i2c_client *client,
> +	u16 addr)
> +{
> +	int rc;
> +	uint8_t buf_recv[4] = {0};
> +	struct elants_data *ts = i2c_get_clientdata(client);
> +
> +	ts->i2caddr = addr;
> +	rc = elants_get_data(client, buf_recv, 4);
> +	if (unlikely(rc < 0)) {
> +		dev_err(&client->dev,
> +				"[ELAN] %s: ID 0x%.2x retval=%d!\n",
> +				__func__, addr, rc);
> +		rc = -ENODEV;
> +	} else {
> +		if (memcmp(buf_recv, iniap_packet, 4)) {
> +			dev_err(&client->dev,
> +					"[ELAN] %s: ID 0x%x retval=%d !\n",
> +					__func__, addr, rc);
> +			rc = -ENODEV;
> +		}
> +	}
> +
> +	ts->i2caddr = elan_i2c_master;
> +
> +	return rc;
> +}
> +
> +static int elants_boot(
> +	struct i2c_client *client,
> +	u16 addr,
> +	elan_boot_t type)
> +{
> +	int rc;
> +	struct elants_data *ts = i2c_get_clientdata(client);
> +	uint8_t command[2][4] = {
> +		{0x4D, 0x61, 0x69, 0x6E},	/* normal_command */
> +		{0x45, 0x49, 0x41, 0x50},	/* iap_command */
> +	};
> +
> +	ts->i2caddr = addr;
> +	rc = elants_set_data(client, command[(int32_t)type], 4);
> +	if (rc != 4) {
> +		if (type == E_BOOT_IAP)
> +			dev_err(&client->dev,
> +					"[elan] Boot IAP fail, error=%d\n",
> +					rc);
> +		else
> +			dev_dbg(&client->dev,
> +					"[elan] Boot normal fail,
error=%d\n",
> +					rc);
> +		ts->i2caddr = elan_i2c_master;
> +		return -EINVAL;
> +	}
> +	pr_info("[elan] Boot success -- 0x%x\n", addr);
> +	ts->i2caddr = elan_i2c_master;
> +	return 0;
> +}
> +
> +static int elants_enter_iap(struct i2c_client *client)
> +{
> +	int rc = 0;
> +	struct elants_data *ts = i2c_get_clientdata(client);
> +
> +	elan_hw_reset(client);
> +
> +	/* Boot devices to IAP mode */
> +	rc = elants_boot(client, elan_i2c_master, E_BOOT_IAP);
> +	if (rc < 0)
> +		return rc;
> +
> +	elan_msleep(10);
> +
> +	/* Check if devices can enter IAP mode */
> +	rc = elants_is_iap(client, elan_i2c_master);
> +	if (rc < 0)
> +		return rc;
> +
> +	ts->iap_mode = IAP_MODE_ENABLE;
> +	set_bit(idx_update_fw, &ts->flags);
> +	ts->i2caddr = elan_i2c_master;
> +
> +	return rc;
> +}
> +
> +
> +
> +/**
> + *	@brief __hello_packet_handler	-	hadle hello packet.
> + *	@param client : our i2c device
> + *
> + *	@return { >0 means success,
> + *			otherwise fail. }
> + *
> + *	Normal hello packet is {0x55, 0x55, 0x55, 0x55}
> + *	recovery mode hello packet is {0x55, 0x55, 0x80, 0x80}
> + */
> +static int __hello_packet_handler(struct i2c_client *client)
> +{
> +	int rc = 0, tries = 5;
> +	uint8_t buf_recv[4] = {0};
> +	struct elants_data *ts = i2c_get_clientdata(client);
> +
> +
> +retry:	/* wait INT for 1sec */
> +	rc = elan_ts_poll(client);
> +	if (rc < 0) {
> +		dev_err(&client->dev,
> +				"%s: poll failed!\n", ELAN_DEV_NAME);
> +		if (tries-- > 0)
> +			goto retry;
> +	}
> +
> +	rc = elants_get_data(client, buf_recv, 4);
> +
> +	/* Print buf_recv anyway */
> +	pr_info("[ELAN] rc = %d Hello Packet: "	\
> +			"[0x%.2x 0x%.2x 0x%.2x 0x%.2x]\n",
> +			rc, buf_recv[0], buf_recv[1], buf_recv[2],
buf_recv[3]);
> +
> +	if (rc != 4) {
> +		dev_err(&client->dev,
> +				"[ELAN] %s: Try recovery because of no
hello\n",
> +				__func__);
> +
> +		/* force TP FW into IAP mode. */
> +		elants_enter_iap(client);
> +		return -EINVAL;
> +	}
> +
> +	/* v0.85 IAP recovery mechanism 2012-1022*/
> +	if (memcmp(buf_recv, hello_packet, 4)) {
> +		/* Check if got 55558080 and
> +		 * should receive next 4Byte for BC version
> +		 */
> +		if (!memcmp(buf_recv, recov_packet, 4)) {
> +			pr_warn("[ELAN] got IAP recovery
packet!(55558080)\n");
> +			rc = elants_get_data(client, buf_recv, 4);
> +			if (unlikely(rc != 4)) {
> +				dev_err(&client->dev,
> +						"Got IAP recovery packet
fail!\n");
> +				return -ENODEV;
> +			}
> +
> +			/* buf_recv[0,1] is dummy data */
> +			ts->major_bc_version = buf_recv[3];
> +			ts->minor_bc_version = buf_recv[2];
> +
> +			pr_info("[ELAN] BC version = %.2x:%.2x",
> +					ts->major_bc_version,
> +					ts->minor_bc_version);
> +		}
> +
> +		pr_info("[ELAN] got mainflow recovery message\n");
> +		rc = elants_enter_iap(client);
> +		if (rc < 0)
> +			dev_err(&client->dev, "Enter IAP mode fail!\n");
> +		return -ENODEV;
> +	}
> +
> +	ts->i2caddr = elan_i2c_master;
> +
> +	return rc;
> +}
> +
> +static int __fw_packet_handler(struct i2c_client *client)
> +{
> +	struct elants_data *ts = i2c_get_clientdata(client);
> +	int rc, tries = 3;
> +	const uint8_t cmd[] = {cmd_header_byte_read, 0x00, 0x00, 0x01};
> +	uint8_t buf_recv[4] = {0x0};
> +
> +	/* Command not support in IAP recovery mode */
> +	if (test_bit(idx_update_fw, &ts->flags))
> +		return 0;
> +retry:
> +	rc = elants_acqurie_data(client, cmd, buf_recv, 4);
> +	if (rc < 0)
> +		return rc;
> +
> +	if (buf_recv[0] == cmd_header_byte_response) {
> +		ts->major_fw_version = ((buf_recv[1] & 0x0f) << 4) |
> +							   ((buf_recv[2] &
0xf0) >> 4);
> +		ts->minor_fw_version = ((buf_recv[2] & 0x0f) << 4) |
> +							   ((buf_recv[3] &
0xf0) >> 4);
> +
> +		if ((ts->major_fw_version == 0x00 &&
> +			 ts->minor_fw_version == 0x00) ||
> +			(ts->major_fw_version == 0xFF &&
> +			 ts->minor_fw_version == 0xFF)) {
> +			dev_err(&client->dev,
> +					"\n\n[ELAN] FW version is empty, "
> +					"suggest IAP ELAN chip\n\n");
> +			return -EINVAL;
> +		}
> +
> +		elan_dbg(client,
> +				 "[ELAN] TOUCH MAJOR FW VERSION 0x%02x\n",
> +				 ts->major_fw_version);
> +		elan_dbg(client,
> +				 "[ELAN] TOUCH MINOR FW VERSION 0x%02x\n",
> +				 ts->minor_fw_version);
> +	} else {
> +		if (tries > 0) {
> +			tries--;
> +			goto retry;
> +		}
> +		ts->major_fw_version = 0xff;
> +		ts->minor_fw_version = 0xff;
> +		dev_err(&client->dev,
> +				"\n\n[ELAN] FW version is empty, "
> +				"suggest IAP ELAN chip\n\n");
> +		return -EINVAL;
> +	}
> +
> +	return 0;
> +}
> +
> +static int __touch_get_resolution(struct i2c_client *client)
> +{
> +	struct elants_data *ts = i2c_get_clientdata(client);
> +	int rc;
> +	uint8_t buf_recv[17] = {0x0};
> +	const uint8_t get_resolution_cmd[] = {
> +		0x5B, 0x00, 0x00, 0x00, 0x00, 0x00
> +	};
> +
> +	/* Command not support in IAP recovery mode */
> +	if (test_bit(idx_update_fw, &ts->flags))
> +		return 0;
> +
> +	rc = elants_async_recv_data(client, get_resolution_cmd, buf_recv,
>
+								sizeof(get_r
esolution_cmd), sizeof(buf_recv));
> +	if (rc < 0)
> +		return -rc;
> +
> +	elan_dbg(client,
> +			 "[ELAN] %x:%x:%x, :%x:%x:%x, %d\n",
> +			 buf_recv[2],  buf_recv[6], buf_recv[10],
> +			 buf_recv[3], buf_recv[7], buf_recv[0], rc);
> +
> +	if (buf_recv[0] != 0x9B)
> +		return -EINVAL;
> +
> +	elan_dbg(client, "[ELAN] %x:%x:%x, :%x:%x:%x, %d\n",
> +			 buf_recv[2],  buf_recv[6], buf_recv[10],
> +			 buf_recv[3], buf_recv[7], buf_recv[11], rc);
> +
> +
> +	ts->rows = (buf_recv[2] + buf_recv[6] + buf_recv[10]);
> +	ts->cols = (buf_recv[3] + buf_recv[7] + buf_recv[11]);
> +
> +	elan_dbg(client, "[ELAN] %x:%x:%x, :%x:%x:%x\n", buf_recv[2],
> +			 buf_recv[6], buf_recv[10],
> +			 buf_recv[3], buf_recv[7], buf_recv[11]);
> +
> +	if (ts->rows < 2 || ts->cols < 2) {
> +		dev_err(&client->dev,
> +				"[ELAN] Invalid resolution (%d, %d)\n",
> +				ts->rows, ts->cols);
> +
> +		/* set default resolution if TP information is wrong */
> +		ts->rows = ELAN_X_MAX;
> +		ts->cols = ELAN_Y_MAX;
> +
> +		rc = ret_fail;
> +	}
> +
> +	/* translate trace number to TSP resolution */
> +	ts->cols = ELAN_TS_RESOLUTION(ts->cols);
> +	ts->rows = ELAN_TS_RESOLUTION(ts->rows);
> +
> +	elan_dbg(client,
> +			 "[ELAN] resolution rows=0x%.2x, "
> +			 "cols=0x%.2x\n",
> +			 ts->rows, ts->cols);
> +
> +	return 0;
> +}
> +
> +
> +/**
> + *	elan_touch_get_bc_ver	-	obtain bootcode data from device
> + *	@client: the interface we are querying
> +
> + *
> + *	Send a bootcode version command and fill the results into the
> + *	elan device structures. Caller must hold the mutex
> + *
> +
> + *	Returns 0 or an error code
> + */
> +static int __elan_touch_get_bc_ver(struct i2c_client *client)
> +{
> +	struct elants_data *ts = i2c_get_clientdata(client);
> +	const u8 get_bc_ver_cmd[] = {0x53, 0x10, 0x00, 0x01};
> +	u8 buf_recv[4];
> +	int rc;
> +
> +	/* Command not support in IAP recovery mode */
> +	if (test_bit(idx_update_fw, &ts->flags))
> +		return 0;
> +
> +	rc = elants_acqurie_data(client, get_bc_ver_cmd,
> +							 buf_recv,
sizeof(buf_recv));
> +	if (rc < 0) {
> +		dev_err(&client->dev,
> +				"elan_ts_acqurie_data failed:
get_bc_ver\n");
> +		return rc;
> +	}
> +
> +	ts->major_bc_version = (((buf_recv[1] & 0x0f) << 4) |
> +							((buf_recv[2]&0xf0)
>> 4));
> +	ts->minor_bc_version = (((buf_recv[2] & 0x0f) << 4) |
> +							((buf_recv[3]&0xf0)
>> 4));
> +
> +	elan_dbg(client,
> +			 "ELAN TOUCH MAJOR BC VERSION 0x%02x\n",
> +			 ts->major_bc_version);
> +	elan_dbg(client,
> +			 "ELAN TOUCH MINOR BC VERSION 0x%02x\n",
> +			 ts->minor_bc_version);
> +
> +	return 0;
> +}
> +
> +static int __elan_fastboot(struct i2c_client *client, int *count)
> +{
> +	int rc = 0;
> +
> +
> +	rc = elants_boot(client, elan_i2c_master, E_BOOT_NORM);
> +	if (rc < 0) {
> +		if (*count > 0)
> +			return -EAGAIN;
> +		return -1;
> +	}
> +
> +	msleep(100);
> +
> +	return rc;
> +}
> +
> +/**
> + *	@brief elan_open		-	open elan device
> + *	@param input : input device
> + *
> + */
> +static int elan_open(struct input_dev *input)
> +{
> +	struct elants_data *ts = input_get_drvdata(input);
> +
> +	dev_err(&ts->client->dev,
> +			"[ELAN] Enter %s\n", __func__);
> +
> +	/* wait probe work_func done */
> +	while ((ts->status & STA_INIT4) == 0)
> +		elan_msleep(1);
> +
> +	return 0;
> +}
> +
> +/**
> + *	@brief elan_close		-	close input device
> + *	@param input : input device
> + *
> + */
> +static void elan_close(struct input_dev *input)
> +{
> +	struct elants_data *ts = input_get_drvdata(input);
> +
> +	dev_err(&ts->client->dev,
> +			"[ELAN] Enter %s\n", __func__);
> +
> +	return;
> +}
> +
> +
> +/**
> + *	@brief \b elan_ts_setup		-	initialization process.
> + *	@param client : our i2c client
> + *
> + *	set our TP up
> + *	-# reset
> + *	-# hello packet
> + *	-# fw version
> + *	-# TP info (resolution)
> + *
> + */
> +static int __devinit elants_setup(struct i2c_client *client)
> +{
> +	struct elants_data *ts = i2c_get_clientdata(client);
> +	int rc, tries = 3, count = 3;
> +	int len = 0;
> +	bool fastboot = true;
> +
> +retry:
> +	/*! Reset */
> +	elan_hw_reset(client);
> +
> +	ts->rx_size = queue_header_size;
> +
> +	/* New BootCode */
> +	if (fastboot == true) {
> +		rc = __elan_fastboot(client, &count);
> +		if (rc < 0) {
> +			if (rc == -EAGAIN && --count > 0)
> +				goto retry;
> +			else {
> +				len += sprintf(ts->boot_log + len,
> +							   "serious bug, BC
may be broken!!\n");
> +				return -1;
> +			}
> +		}
> +		fastboot = 0;
> +	} else {
> +		/* Wait bootcode timeout 1 second +
> +			Main-flow initial ~100ms */
> +		ssleep(2);
> +	}
> +
> +	/*! - elan hello packet init */
> +	rc = __hello_packet_handler(client);
> +	if (rc < 0) {
> +		/* Wrong hello_packet or polling fail, retry */
> +		if ((rc == -EINVAL || rc == -ETIMEDOUT) && --tries > 0) {
> +			dev_err(&client->dev,
> +					"[ELAN] retries=%d, rc=%d\n",
> +					tries, rc);
> +			goto retry;
> +		}
> +
> +		len += sprintf(ts->boot_log + len,
> +					   "retry=%d polling time-out\n",
> +					   3-tries);
> +
> +		dev_err(&client->dev,
> +				"hello packet error.\n");
> +		/* Go through down*/
> +
> +		/* if iap mode enable, return and wait for IAP */
> +		if (ts->iap_mode == IAP_MODE_ENABLE) {
> +			len += sprintf(ts->boot_log + len, "IAP mode
enable\n");
> +			return rc;
> +		}
> +	}
> +
> +	elan_dbg(client,
> +			 "__hello_packet_handler ...\n");
> +
> +	/*! - elan fw version */
> +	rc = __fw_packet_handler(client);
> +	if (rc < 0) {
> +		dev_err(&client->dev, "firmware checking error.\n");
> +		len += sprintf(ts->boot_log+len, "fw_packet_error=%x:%x\n",
> +					   ts->major_fw_version,
ts->minor_fw_version);
> +
> +		if (rc == -EINVAL) {
> +			len += sprintf(ts->boot_log+len,
> +						   "FW version is empty, IAP
enable!!\n");
> +			set_bit(idx_update_fw, &ts->flags);
> +			ts->iap_mode = IAP_MODE_ENABLE;
> +		}
> +
> +		/* Go through down*/
> +	}
> +
> +	elan_dbg(client, "__fw_packet_handler...\n");
> +
> +	/*! - elan TP information */
> +	rc = __touch_get_resolution(client);
> +	if (rc < 0) {
> +		dev_err(&client->dev,
> +				"TP information checking error.\n");
> +		len += sprintf(ts->boot_log+len,
> +					   "touch_get_resolution=%x:%x\n",
> +					   ts->rows, ts->cols);
> +		/* Go through down*/
> +	}
> +
> +	elan_dbg(client,
> +			 "__touch_get_resolution...\n");
> +
> +
> +	/* Get TS BootCode version */
> +	rc = __elan_touch_get_bc_ver(client);
> +	if (rc < 0) {
> +		dev_err(&client->dev,
> +				"TP get BC version error.\n");
> +		len += sprintf(ts->boot_log+len,
> +					   "touch_get_BC_ver=%x:%x\n",
> +					   ts->major_bc_version,
ts->major_bc_version);
> +		/* Go through down*/
> +	}
> +
> +	if (len == 0)
> +		len += sprintf(ts->boot_log, "boot success!!\n");
> +
> +	return rc;
> +
> +}
> +
> +
> +static int elants_get_power_state(struct i2c_client *client)
> +{
> +	int rc = 0;
> +	const uint8_t cmd[] = {cmd_header_byte_read, 0x50, 0x00, 0x01};
> +	uint8_t buf[4], power_state;
> +
> +	rc = elants_acqurie_data(client, cmd, buf, 4);
> +	if (rc)
> +		return rc;
> +
> +	power_state = buf[1];
> +	elan_dbg(client,
> +			 "dump repsponse: %0x\n", power_state);
> +	power_state = (power_state & PWR_STATE_MASK) >> 3;
> +	elan_dbg(client,
> +			 "power state = %s\n",
> +			 power_state == PWR_STATE_DEEP_SLEEP ?
> +			 "Deep Sleep" : "Normal/Idle");
> +
> +	return power_state;
> +}
> +
> +
> +/**
> + *	@brief \b elan_ts_recv_data		-	received TP data
> + *	@param client: our i2c device
> + *	@param buf : buffer for put received data
> + *
> + *	received data from TP device.
> + */
> +static int elants_recv_data(struct i2c_client *client, uint8_t *buf)
> +{
> +	struct elants_data *ts = i2c_get_clientdata(client);
> +	int rc = 0, bytes_to_recv;
> +
> +	dev_dbg(&client->dev,
> +			"[ELAN] Enter %s\n", __func__);
> +
> +	if (buf == NULL)
> +		return -EINVAL;
> +
> +	mutex_lock(&ts->tr_mutex);
> +
> +	bytes_to_recv = ts->rx_size;
> +	rc = i2c_master_recv(client, buf, bytes_to_recv);
> +
> +	dev_dbg(&client->dev,
> +			"[ELAN] %d:%d:%x:%x, addr=%x\n", bytes_to_recv, rc,
> +			buf[0], buf[34], client->addr);
> +	dev_dbg(&client->dev,
> +			"[ELAN] %x:%x:%x:%x:%x:%x\n", buf[0], buf[1],
buf[2],
> +			buf[3], buf[4], buf[5]);
> +
> +	if (rc != bytes_to_recv) {
> +		dev_err(&client->dev,
> +				"%s: i2c_master_recv error?!\n",
> +				__func__);
> +		rc = -EINVAL;
> +	}
> +	mutex_unlock(&ts->tr_mutex);
> +
> +	return rc;
> +}
> +
> +/**
> + *	elan_touch_pull_frame	-	pull a frame from the fifo
> + *	@ed: our elan touch device
> + *	@ehr: return buffer for the header
> + *	@buf: data buffer
> + *
> + *	Pulls a frame from the FIFO into the provided ehr and data buffer.
> + *	The data buffer must be at least cmd_response_len bytes long.
> + */
> +static int elan_touch_pull_frame(struct elants_data *ts, u8 *buf)
> +{
> +	dev_dbg(&ts->client->dev,
> +			"[ELAN] Enter %s\n", __func__);
> +
> +	WARN_ON(kfifo_out_locked(&ts->fifo, buf, cmd_response_len,
> +							 &ts->rx_kfifo_lock)
> +			!= cmd_response_len);
> +	return cmd_response_len;
> +}
> +
> +
> +/**
> + *	elan_touch_fifo_clean_old	-	Make room for new frames
> + *	@ed: our elan touch device
> + *	@room: space needed
> + *
> + *	Empty old frames out of the FIFO until we can fit the new one into
> + *	the other end.
> + */
> +static void elan_touch_fifo_clean_old(struct elants_data *ts, int room)
> +{
> +	u8 buffer[cmd_response_len];
> +	dev_dbg(&ts->client->dev,
> +			"[ELAN] Enter %s\n", __func__);
> +
> +	while (kfifo_len(&ts->fifo) + room >= FIFO_SIZE)
> +		elan_touch_pull_frame(ts, buffer);
> +}
> +
> +
> +/** @brief \b elan_ts_GetRepoInfo	-	parse Multi-queue report
header
> + *	@param client : our i2c device
> + *	@param buf : buffer data
> + *
> + *	parsing report header and get data length.
> + *
> + */
> +static int elants_GetRepoInfo(struct i2c_client *client, uint8_t *buf)
> +{
> +	struct elants_data *ts = i2c_get_clientdata(client);
> +	struct multi_queue_header *buff = (struct multi_queue_header *)buf;
> +	const u8 wait_packet[4] = {0x64, 0x64, 0x64, 0x64};
> +	int times = 10, rc = 0;
> +
> +	switch (buf[idx_finger_header]) {
> +	case cmd_header_byte_hello:
> +		if (!memcmp(buf, hello_packet, 4))
> +			ts->wdt_reset++;
> +		return ret_cmdrsp;
> +	case cmd_header_byte_response:
> +		/* Queue the data, using the fifo lock to serialize the
multiple
> +		   accesses to the FIFO */
> +		elan_dbg(client,
> +				 "[ELAN] recv cmd_header_byte_response\n");
> +
> +		mutex_lock(&ts->fifo_mutex);
> +		if (kfifo_len(&ts->fifo) + cmd_response_len >= FIFO_SIZE)
> +			/* Make room, make room */
> +			elan_touch_fifo_clean_old(ts, cmd_response_len);
> +		/* Push the data */
> +		kfifo_in_locked(&ts->fifo, buf,
> +						cmd_response_len,
&ts->rx_kfifo_lock);
> +		mutex_unlock(&ts->fifo_mutex);
> +
> +		elan_dbg(client,
> +				 "[ELAN] wake_up [%02x:%02x:%02x:%02x]\n",
> +				 buf[0], buf[1], buf[2], buf[3]);
> +		wake_up(&ts->wait);
> +		return ret_cmdrsp;
> +	case cmd_header_byte_rek:
> +		/* re-K comand response, ingore it! */
> +		return ret_cmdrsp;
> +		/* Buffer mode header */
> +	case queue_header_byte_normal:
> +		elan_dbg(client,
> +				 "[ELAN] report_count=%d report_len=%d\n",
> +				 buff->report_count, buff->report_length);
> +		if (likely(buff->report_count <= 3)) {
> +			ts->mq_header.report_count = buff->report_count;
> +			ts->mq_header.report_length = buff->report_length;
> +			ts->rx_size = ts->mq_header.report_length;
> +		} else
> +			return ret_fail;
> +
> +		break;
> +	case queue_header_byte_wait:
> +		dev_err(&client->dev,
> +				"========queue_header_byte_wait
%x:%x:%x:%x========\n",
> +				buf[0], buf[1], buf[2], buf[3]);
> +		/*! BUGFIX: buff[0] might be wrong (0x63),
> +		 * check buff[1 ~ 3] is enough
> +		 */
> +		if (!memcmp(buf+1, &wait_packet[1], 3)) {
> +			do {
> +				udelay(30);
> +				elants_recv_data(client, (uint8_t *)buff);
> +			} while (buff->packet_id != queue_header_byte_normal
&&
> +					 --times > 0);
> +			if (times > 0)
> +				rc = elants_GetRepoInfo(client, (uint8_t
*)buff);
> +			else
> +				return ret_fail;
> +			elan_dbg(client,
> +					 "Detect Wait_Header:rx_size=%d, "\
> +					 "report_count=%d report_len=%d\n",
> +					 ts->rx_size,
> +					 ts->mq_header.report_count,
> +					 ts->mq_header.report_length);
> +		} else
> +			dev_err(&client->dev,
> +					"[ELAN] ERROR!! wait
header:%x:%x:%x:%x\n",
> +					buf[0], buf[1], buf[2], buf[3]);
> +		break;
> +		/* Not buffer mode, it's single word mode */
> +	case queue_header_byte_Single:
> +		ts->mq_header.report_count = 1;
> +		ts->mq_header.report_length = IDX_PACKET_SIZE_WIDTH;
> +		ts->rx_size = ts->mq_header.report_length;
> +		return ts->rx_size;
> +		break;
> +	default:
> +		dev_err(&client->dev,
> +				"unknown multi-queue command!! --%x
%x:%x:%x--\n",
> +				buf[0], buf[1], buf[2], buf[3]);
> +		ts->mq_header_fail++;
> +
> +		/* If glitch causes frame error, drop all finger report */
> +		ts->rx_size = queue_packet_max_len;
> +		elants_recv_data(client, (uint8_t *)buff);
> +		return ret_fail;
> +	}
> +
> +	return ts->rx_size;
> +}
> +
> +
> +/** @brief \b elan_touch_checksum	-	Add for checksum mechanism
> + *	@param client : our i2c device
> + *	@param buf : buffer data
> + *
> + *	caculating checksum for make sure all data validity.
> + *
> + */
> +static int elan_touch_checksum(struct i2c_client *client, u8 *buf)
> +{
> +	u8 i = 0, checksum = 0;
> +	struct elants_data *ts = i2c_get_clientdata(client);
> +
> +	/*! FIXME: checksum wasn't including width byte */
> +	for (i = 0; i < IDX_PACKET_SIZE_WIDTH - 6; i++)
> +		checksum = checksum + buf[i];
> +
> +	ts->checksum_correct = checksum;
> +
> +	if (checksum != buf[idx_finger_width_checksum]) {
> +		ts->checksum_fail++;
> +		dev_err(&client->dev,
> +				"elan touch checksum fail: %02x:%02x\n",
> +				checksum, buf[idx_finger_width_checksum]);
> +		return -EFAULT;
> +	}
> +
> +	return 0;
> +}
> +
> +/**
> + *	@brief \b elan_touch_parse_fid	-	parse the 10 fid bits
> + *	@param data : the input bit stream
> + *	@param fid : an array of fid values
> + *
> + *	Unpack the 10 bits into an array.
> + *
> + *	FIXME: Review whether we can't just use << operators after making
> + *	sure the bits are native endian ?
> + */
> +static inline void elan_touch_parse_fid(u8 *data, u8 *fid)
> +{
> +	fid[0] = (data[0] & 0x01);
> +	fid[1] = (data[0] & 0x02);
> +	fid[2] = (data[0] & 0x04);
> +	fid[3] = (data[0] & 0x08);
> +	fid[4] = (data[0] & 0x10);
> +	fid[5] = (data[0] & 0x20);
> +	fid[6] = (data[0] & 0x40);
> +	fid[7] = (data[0] & 0x80);
> +	fid[8] = (data[1] & 0x10);
> +	fid[9] = (data[1] & 0x20);
> +}
> +
> +/**
> + *	@brief \b elan_touch_parse_wid	-	parse the 10 wid bits
> + *	@param data : the input bit stream
> + *	@param wid : an array of width level
> + *
> + *	Unpack the 10 bits into an array.
> + *
> + */
> +static inline void elan_touch_parse_wid(u8 *data, u8 *wid)
> +{
> +	wid[0] = (data[0] >> 4);
> +	wid[1] = (data[0] & 0x0f);
> +	wid[2] = (data[1] >> 4);
> +	wid[3] = (data[1] & 0x0f);
> +	wid[4] = (data[2] >> 4);
> +	wid[5] = (data[2] & 0x0f);
> +	wid[6] = (data[3] >> 4);
> +	wid[7] = (data[3] & 0x0f);
> +	wid[8] = (data[4] >> 4);
> +	wid[9] = (data[4] & 0x0f);
> +}
> +
> +
> +static inline int elants_parse_xy(
> +	uint8_t *data,
> +	uint16_t *x,
> +	uint16_t *y)
> +{
> +	*x = *y = 0;
> +
> +	*x = (data[0] & 0xf0);
> +	*x <<= 4;
> +	*x |= data[1];
> +
> +	*y = (data[0] & 0x0f);
> +	*y <<= 8;
> +	*y |= data[2];
> +
> +	return 0;
> +}
> +
> +/* transition stage for lookup by table, maybe update finger report
> +	using by Win8 50Byte format that having actual value for X, Y width
*/
> +static inline int elan_lookup_wid(
> +	u8 data,
> +	u16 *w,
> +	u16 *h)
> +{
> +	static u16 pre_w, pre_h, cur_w, cur_h;
> +	const u8 width_lookup_table[15][2] = {
> +		{3, 2},	{3, 2}, {6, 3},
> +		{6, 3},	{10, 3}, {15, 4},
> +		{15, 5}, {15, 5}, {15, 5},
> +		{15, 5}, {15, 5}, {15, 5},
> +		{15, 5}, {15, 5}, {15, 5},
> +	};
> +
> +	cur_w = width_lookup_table[data][0] * 17;
> +	cur_h = width_lookup_table[data][1] * 17;
> +
> +	/* IIR to balance w, h vaule, don't jitter too much */
> +	*w = (cur_w + pre_w) >> 1;
> +	*h = (cur_h + pre_h) >> 1;
> +
> +	pre_w = cur_w;
> +	pre_h = cur_h;
> +
> +	return 0;
> +}
> +
> +static int elan_mt_compute_slot(struct mt_device *td,
> +								struct
input_dev *input)
> +{
> +	return input_mt_get_slot_by_key(input, td->curdata.contactid);
> +}
> +
> +/*
> + * this function is called when a whole contact has been processed,
> + * so that it can assign it to a slot and store the data there
> + */
> +static void elan_mt_complete_slot(struct mt_device *td,
> +								  struct
input_dev *input)
> +{
> +	struct elants_data *ts =
> +		container_of(td, struct elants_data, td);
> +
> +	if (td->curvalid) {
> +		int slotnum = elan_mt_compute_slot(td, input);
> +		struct mt_slot *s = &td->curdata;
> +
> +		if (slotnum < 0 || slotnum >= td->maxcontacts)
> +			return;
> +
> +		input_mt_slot(input, slotnum);
> +		input_mt_report_slot_state(input, MT_TOOL_FINGER,
> +								
s->touch_state);
> +		if (s->touch_state) {
> +			/* this finger is on the screen */
> +			int wide = (s->w > s->h);
> +			/* divided by two to match visual scale of touch */
> +			int major = max(s->w, s->h) >> 1;
> +			int minor = min(s->w, s->h) >> 1;
> +
> +			elan_dbg(ts->client,
> +					 "[ELAN] slot=%d x=%x y=%x w=%x
h=%x\n",
> +					 slotnum, s->x, s->y, major, minor);
> +
> +			input_event(input, EV_ABS, ABS_MT_POSITION_X, s->x);
> +			input_event(input, EV_ABS, ABS_MT_POSITION_Y, s->y);
> +			input_event(input, EV_ABS, ABS_MT_ORIENTATION,
wide);
> +			input_event(input, EV_ABS, ABS_MT_PRESSURE, s->p);
> +			input_event(input, EV_ABS, ABS_MT_TOUCH_MAJOR,
major);
> +			input_event(input, EV_ABS, ABS_MT_TOUCH_MINOR,
minor);
> +		}
> +	}
> +
> +	td->num_received++;
> +}
> +
> +/*
> + * this function is called when a whole packet has been received and
processed,
> + * so that it can decide what to send to the input layer.
> + */
> +static void mt_sync_frame(struct mt_device *td, struct input_dev *input)
> +{
> +	input_mt_sync_frame(input);
> +	input_sync(input);
> +	td->num_received = 0;
> +}
> +
> +
> +/** @brief \b elan_mt_event	-	process finger reports
> + *	@param ts: our touchscreen
> + *	@param finger_stat : number of fingers in packet
> + *	@param buf : received buffer
> + *
> + *	Walk the received report and process the finger data, extracting
> + *	and reporting co-ordinates. No locking is needed here as the
workqueue
> + *	does our threading for us.
> + */
> +static int elan_mt_event(
> +	struct elants_data *ts,
> +	int finger_stat,
> +	u8 *buf)
> +{
> +	int i;
> +	u8 fid[MAX_CONTACT_NUM], wid[MAX_CONTACT_NUM];
> +	u16 x, y, w, h;
> +	struct i2c_client *client = ts->client;
> +	struct mt_device *td = &ts->td;
> +
> +	dev_dbg(&client->dev,
> +			"[ELAN] Enter elan_mt_event Func\n");
> +
> +	/* Parsing Finger, Width field */
> +	elan_touch_parse_fid(&buf[idx_finger_state], &fid[0]);
> +	elan_touch_parse_wid(&buf[idx_finger_width], &wid[0]);
> +
> +	/* number of fingers expects in this frame */
> +	td->num_expected = finger_stat;
> +	for (i = 0; i < td->maxcontacts; i++) {
> +		if (finger_stat == 0)
> +			break;
> +
> +		/* tracking id */
> +		td->curdata.contactid = (fid[i] > 0) ? i+1 : 0;
> +
> +		if (td->curdata.contactid == 0)
> +			continue;
> +
> +		td->curdata.touch_state = true;
> +
> +		elants_parse_xy(&buf[3+i*3], &x, &y);
> +		td->curdata.x = x;
> +		td->curdata.y = y;
> +
> +		elan_lookup_wid(wid[i], &w, &h);
> +		td->curdata.w = w;
> +		td->curdata.h = h;
> +
> +		finger_stat--;
> +
> +		elan_mt_complete_slot(td, ts->input);
> +	}
> +
> +	if (td->num_received >= td->num_expected)
> +		mt_sync_frame(td, ts->input);
> +
> +	return 1;
> +}
> +
> +
> +
> +/** @brief \b elants_report_data	-	report finger report to user
space.
> + *	@param client : our i2c device
> + *	@param buf : raw data from TP device.
> + *
> + *	- reporting finger data to user space.
> + *	- packet_fail count
> + *
> + */
> +static void elants_report_data(struct i2c_client *client, uint8_t *buf)
> +{
> +	struct elants_data *ts = i2c_get_clientdata(client);
> +
> +	switch (buf[idx_finger_header]) {
> +	case idx_coordinate_packet_4_finger:
> +	case idx_coordinate_packet_10_finger: {
> +		u8 finger_stat  = buf[idx_finger_total] & 0x0f;
> +		elan_dbg(client,
> +				 "[ELAN] finger_stat == %d\n", finger_stat);
> +		elan_dbg(client,
> +				 "[ELAN] finger:%x:%x:%x:%x:%x\n",
> +				 buf[0], buf[1], buf[2], buf[3], buf[4]);
> +
> +		/* Enter right process, reset int_status*/
> +		ts->polling.int_status = 0;
> +		ts->packet_received++;
> +
> +		if (likely(finger_stat != 0)) {
> +			ts->td.curvalid = true;
> +			ts->touched_sync++;
> +		} else
> +			ts->no_touched_sync++;
> +
> +		/* Handle mt event */
> +		elan_mt_event(ts, finger_stat, buf);
> +	}
> +	break;
> +	default:
> +		ts->header_fail++;
> +		dev_err(&client->dev,
> +				"[ELAN] %s: unknown packet type:
%x:%x:%x:%x\n",
> +				__func__, buf[0], buf[1], buf[2], buf[3]);
> +		break;
> +	}
> +
> +	return;
> +}
> +
> +/** @brief \b elants_drop_packet	-	err handler that drop all
packet.
> + *
> + *	mutex protection will at outside this function.
> + *
> + */
> +static void elants_drop_packet(struct elants_data *ts)
> +{
> +	uint8_t buf[queue_packet_max_len] = {0x0};
> +
> +	dev_dbg(&ts->client->dev,
> +			"[ELAN] Enter %s\n", __func__);
> +
> +	if (test_bit(idx_update_fw, &ts->flags))
> +		return;
> +
> +	if (gpio_get_value(ts->intr_gpio) != 0)
> +		goto end;
> +
> +	/* -# Read multi_queue header */
> +	ts->rx_size = queue_header_size;
> +	if (elants_recv_data(ts->client, buf) < 0)
> +		goto end;
> +
> +	/* -# Get multi_queue header info*/
> +	if (elants_GetRepoInfo(ts->client, buf) > 0) {
> +		/* 3. Get finger report data */
> +		elants_recv_data(ts->client, buf);
> +		udelay(10);
> +		if (gpio_get_value(ts->intr_gpio) != 0)
> +			goto end;
> +	}
> +
> +	/* -#received all packet till ts->intr pull high */
> +	ts->rx_size = 1;
> +	while (gpio_get_value(ts->intr_gpio) == 0) {
> +		elants_recv_data(ts->client, buf);
> +		udelay(10);
> +	}
> +
> +end:
> +	ts->rx_size = queue_header_size;
> +	dev_dbg(&ts->client->dev,
> +			"[ELAN] Leave %s\n", __func__);
> +
> +	return;
> +}
> +
> +
> +
> +/** @brief \b elan_ts_pollWork_func	-	regular processing
> + *	@param work : pass from kernel
> + *
> + *	poll_timer polled processing to occur
> + *	elan_ts_pollWork_func() to check if our ts
> + *	is abnormal.
> + *
> + */
> +static void elants_pollWork_func(struct work_struct *work)
> +
> +{
> +	struct elants_data *ts =
> +		container_of(work, struct elants_data, pollingwork);
> +
> +	dev_dbg(&ts->client->dev,
> +			"[ELAN] Enter %s\n", __func__);
> +
> +	if (test_bit(idx_update_fw, &ts->flags))
> +		goto fail;
> +
> +	if (gpio_get_value(ts->intr_gpio) != 0)
> +		goto fail;
> +	else {
> +		ts->polling.int_status++;
> +		if (ts->polling.int_status < 3)
> +			goto fail;
> +	}
> +
> +	/* - we use mutex_trylock() here since polling is not very important
*/
> +	if (!mutex_trylock(&ts->mutex)) {
> +		elan_dbg(ts->client,
> +				 "[ELAN] trylock fail! return...\n");
> +		goto fail;
> +	}
> +
> +	if (test_bit(idx_finger_report, &ts->flags)) {
> +		elan_dbg(ts->client,
> +				 "[ELAN] 1.finger_Report processing ...
ignore!!\n");
> +		goto unlock;
> +	}
> +
> +	if (test_bit(idx_cmd_handshake, &ts->flags)) {
> +		elan_dbg(ts->client,
> +				 "[ELAN] 2.command processing ...
ignore!!\n");
> +		goto unlock;
> +	}
> +
> +	dev_err(&ts->client->dev,
> +			"[ELAN] Force to release intr_gpio!!\n");
> +
> +	ts->drop_frame++;
> +	elants_drop_packet(ts);
> +
> +unlock:
> +	mutex_unlock(&ts->mutex);
> +
> +fail:
> +	return;
> +}
> +
> +static irqreturn_t elants_work_func(int irq, void *work)
> +{
> +	struct elants_data *ts = work;
> +	uint8_t buf[queue_packet_max_len] = {0x0};
> +	u8 pos = 0, rc;
> +
> +	dev_dbg(&ts->client->dev,
> +			"[ELAN] Enter %s\n", __func__);
> +
> +	if (test_bit(idx_update_fw, &ts->flags))
> +		return IRQ_HANDLED;
> +
> +	/* - this means that we have already serviced it or glich happen!!
*/
> +	if (gpio_get_value(ts->intr_gpio) != 0) {
> +		dev_dbg(&ts->client->dev,
> +				"[ELAN] Leave %s(gpio)\n", __func__);
> +		return IRQ_HANDLED;
> +	}
> +
> +	mutex_lock(&ts->mutex);
> +
> +	set_bit(idx_finger_report, &ts->flags);
> +
> +	/* - Read multi_queue header */
> +	if (elants_recv_data(ts->client, buf) < 0)
> +		goto fail;
> +
> +	/*  - Get multi_queue header info */
> +	rc = elants_GetRepoInfo(ts->client, buf);
> +	if (rc < 0 || rc == ret_cmdrsp)
> +		goto fail;
> +
> +	/* - Get finger report data */
> +	if (elants_recv_data(ts->client, buf) < 0)
> +		goto fail;
> +
> +	clear_bit(idx_finger_report, &ts->flags);
> +
> +	mutex_unlock(&ts->mutex);
> +
> +	/* - parsing report and send out */
> +	while (ts->mq_header.report_count--) {
> +		if (elan_touch_checksum(ts->client, buf + pos) == 0)
> +			elants_report_data(ts->client, buf + pos);
> +		pos = pos + IDX_PACKET_SIZE_WIDTH;
> +		udelay(10);
> +	}
> +
> +	ts->rx_size = queue_header_size;
> +	dev_dbg(&ts->client->dev,
> +			"[ELAN] Leave %s\n", __func__);
> +	return IRQ_HANDLED;
> +
> +fail:
> +	clear_bit(idx_finger_report, &ts->flags);
> +	mutex_unlock(&ts->mutex);
> +	ts->rx_size = queue_header_size;
> +
> +	dev_dbg(&ts->client->dev,
> +			"[ELAN] Leave %s(Fail)\n", __func__);
> +	return IRQ_HANDLED;
> +}
> +
> +/**
> + *	@brief \b elants_poll_timer_func	- err handler when intr_gpio
is low but no isr
> serviced it.
> + *	@param data : our ts
> + *
> + *	intr_gpio polling checking, it'll force to get data if intr_gpio is
low
> + *	and not in isr routine.
> + *
> + */
> +static void elants_poll_timer_func(unsigned long data)
> +{
> +	struct elants_data *ts = (struct elants_data *)data;
> +	struct elan_polling *timer = &ts->polling;
> +
> +	dev_dbg(&ts->client->dev,
> +			"[ELAN] Enter %s\n", __func__);
> +
> +	/* - ignore it if normal work is processing */
> +	if (work_pending(&ts->work)) {
> +		dev_dbg(&ts->client->dev,
> +				"[ELAN] 1.work_pending ... ignore!!\n");
> +		goto reset;
> +	}
> +
> +	/* - ignore it if poll_timer work is processing */
> +	if (work_pending(&ts->pollingwork)) {
> +		dev_dbg(&ts->client->dev,
> +				"[ELAN] 2.work_pending ... ignore!!\n");
> +		goto reset;
> +	}
> +
> +	if (!queue_work(timer->elan_wq, &ts->pollingwork))
> +		dev_err(&ts->client->dev,
> +				"[ELAN] pollWork active failed!!\n");
> +
> +reset:
> +	timer->timer.expires = jiffies + 10 * HZ;
> +	add_timer(&ts->polling.timer);
> +
> +	return;
> +}
> +
> +static irqreturn_t elants_irq_handler(int irq, void *dev_id)
> +{
> +	struct elants_data *ts = dev_id;
> +	struct i2c_client *client = ts->client;
> +
> +	dev_dbg(&client->dev, "[ELAN] %s\n", __func__);
> +
> +	ts->irq_received++;
> +
> +	return IRQ_WAKE_THREAD;
> +}
> +
> +
> +static int elants_register_interrupt(struct i2c_client *client)
> +{
> +	struct elants_data *ts = i2c_get_clientdata(client);
> +	int err = -1;
> +
> +	if (client->irq) {
> +
> +		ts->use_irq = 1;
> +
> +		err = request_threaded_irq(client->irq, elants_irq_handler,
> +								
elants_work_func,
> +								
IRQF_TRIGGER_FALLING |
> IRQF_ONESHOT,
> +								
client->name, ts);
> +		if (err) {
> +			dev_err(&client->dev,
> +					"%s: request_irq %d failed\n",
> +					__func__, client->irq);
> +			goto err;
> +		}
> +
> +		ts->status |= STA_USE_IRQ;
> +
> +		elan_dbg(client,
> +				 "[ELAN] %s in interrupt mode\n",
ts->input->name);
> +	}
> +err:
> +	return err;
> +}
> +
> +static int remove_elants(struct i2c_client *client)
> +{
> +	int ret = 0;
> +	struct elants_data *ts = i2c_get_clientdata(client);
> +
> +	if (&client->dev.kobj)
> +		sysfs_remove_group(&client->dev.kobj,
&elan_attribute_group);
> +
> +	if (ts->use_irq) {
> +		if (client->irq)
> +			free_irq(client->irq, ts);
> +	}
> +
> +	input_mt_destroy_slots(ts->input);
> +
> +	if (ts->input)
> +		input_unregister_device(ts->input);
> +
> +	if (ts->polling.elan_wq)
> +		destroy_workqueue(ts->polling.elan_wq);
> +
> +	if (&ts->polling.timer) {
> +		ret = del_timer(&ts->polling.timer);
> +		if (ret != 0)
> +			dev_err(&client->dev,
> +					"[ELAN] del_timer fail!!\n");
> +	}
> +
> +	if (&ts->mutex)
> +		mutex_destroy(&ts->mutex);
> +	if (&ts->tr_mutex)
> +		mutex_destroy(&ts->tr_mutex);
> +	if (&ts->fifo_mutex)
> +		mutex_destroy(&ts->fifo_mutex);
> +
> +	if (ts->fw_enabled) {
> +		ret = misc_deregister(&ts->firmware);
> +		if (ret < 0)
> +			dev_err(&client->dev,
> +					"[ELAN] misc_deregister fail!!\n");
> +	}
> +
> +	kfree(ts->td.slots);
> +
> +	/* free kfifo */
> +	kfifo_free(&ts->fifo);
> +	kfree(ts);
> +
> +	return ret;
> +}
> +
> +
> +/**
> + *	probe_thread_func	-	init touch device.
> + *	@work: /int work queue
> + *
> + *	Perform real probe for our I2C device and if successful configure
> + *	it up as an input device. If not then clean up and return an error
> + *	code.
> + */
> +
> +static int probe_thread_func(void *data)
> +{
> +	struct elants_data *ts = data;
> +	struct i2c_client *client = ts->client;
> +	int err = 0;
> +
> +	mutex_lock(&ts->mutex);
> +
> +	err = elants_setup(client);
> +	if (err < 0) {
> +		dev_err(&client->dev,
> +				"[ELAN] %s probe failed\n",
> +				ELAN_DEV_NAME);
> +		/* User can IAP anyway, continue */
> +	}
> +
> +	set_bit(BTN_TOUCH, ts->input->keybit);
> +
> +	/*! - Single touch input params setup */
> +	input_set_abs_params(ts->input, ABS_X, 0, ts->cols, 0, 0);
> +	input_set_abs_params(ts->input, ABS_Y, 0, ts->rows, 0, 0);
> +	input_set_abs_params(ts->input, ABS_PRESSURE, 0, 255, 0, 0);
> +
> +	/*! @warning FIXME: ABS_MT_PRESSURE can be supported by FW.
> +		currently we have done it by ABS_MT_WIDTH_MAJOR */
> +	/*! - Multitouch input params setup */
> +	input_set_abs_params(ts->input, ABS_MT_POSITION_X, 0, ts->cols, 0,
0);
> +	input_set_abs_params(ts->input, ABS_MT_POSITION_Y, 0, ts->rows, 0,
0);
> +	input_set_abs_params(ts->input, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0);
> +	input_set_abs_params(ts->input, ABS_MT_TOUCH_MINOR, 0, 255, 0, 0);
> +
> +	/* not test, keep mark for less Android-ICS */
> +	input_set_abs_params(ts->input, ABS_MT_ORIENTATION, 0, 1, 0, 0);
> +
> +	__set_bit(EV_ABS, ts->input->evbit);
> +	__set_bit(EV_SYN, ts->input->evbit);
> +
> +	input_set_drvdata(ts->input, ts);
> +
> +	err = input_register_device(ts->input);
> +	if (err) {
> +		dev_err(&client->dev,
> +				"[ELAN] %s unable to register input
device\n",
> +				ELAN_DEV_NAME);
> +		goto fail_un;
> +	}
> +
> +	ts->td.slots = kzalloc(MAX_CONTACT_NUM * sizeof(struct mt_slot),
> +						   GFP_KERNEL);
> +	if (!ts->td.slots) {
> +		dev_err(&client->dev,
> +				"cannot allocate multitouch slots\n");
> +		goto fail_un;
> +	}
> +	ts->td.maxcontacts = MAX_CONTACT_NUM;
> +	ts->td.mt_flags |= INPUT_PROP_DIRECT;
> +
> +	input_mt_init_slots(ts->input, ts->td.maxcontacts, ts->td.mt_flags);
> +	/* set frame rate size as 100fps */
> +	input_set_events_per_packet(ts->input, 100);
> +
> +	/*! @warning If the firmware device fails
> +	 * we carry on as it doesn't stop normal
> +	   usage */
> +	private_ts = &ts->firmware;
> +	if (elants_register_interrupt(ts->client) < 0) {
> +		dev_err(&client->dev,
> +				"[ELAN] %s register_interrupt failed!\n",
> +				ELAN_DEV_NAME);
> +		goto fail_un;
> +	}
> +
> +	/*! - Register SW watchdog timer */
> +	init_timer(&ts->polling.timer);
> +	/*! - check intr_gpio every 10secs */
> +	ts->polling.timer.expires = jiffies + 10 * HZ;
> +	ts->polling.timer.function = &elants_poll_timer_func;
> +	ts->polling.timer.data = (unsigned long)ts;
> +	add_timer(&ts->polling.timer);
> +
> +	mutex_unlock(&ts->mutex);
> +
> +	ts->status |= STA_INIT4;
> +
> +	return 0;
> +
> +fail_un:
> +	mutex_unlock(&ts->mutex);
> +	remove_elants(client);
> +	return err;
> +}
> +
> +
> +
> +/**
> + *	@brief elants_probe	-	probe for touchpad
> + *	@param client : our I2C client
> + *
> + *	Perform setup and probe for our I2C device and if successful
configure
> + *	it up as an input device. If not then clean up and return an error
> + *	code.
> + */
> +static int __devinit elants_probe(
> +	struct i2c_client *client,
> +	const struct i2c_device_id *id)
> +{
> +	long err = -1;
> +	struct elan_i2c_platform_data *pdata = NULL;
> +	struct elants_data *ts =
> +		kzalloc(sizeof(struct elants_data), GFP_KERNEL);
> +
> +	if (ts == NULL)
> +		return -ENOMEM;
> +
> +	ts->status |= STA_PROBED;
> +
> +	mutex_init(&ts->mutex);
> +	mutex_init(&ts->tr_mutex);
> +	mutex_init(&ts->fifo_mutex);
> +	init_waitqueue_head(&ts->wait);
> +	spin_lock_init(&ts->rx_kfifo_lock);
> +
> +	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
> +		dev_err(&client->dev,
> +				"[ELAN] %s: i2c check functionality
error\n",
> +				ELAN_DEV_NAME);
> +		goto fail_un;
> +	}
> +
> +	/*! - Regular polling Process */
> +	ts->polling.elan_wq = create_singlethread_workqueue("elan_poll_wq");
> +	if (!ts->polling.elan_wq) {
> +		dev_err(&client->dev,
> +				"[ELAN] %s: create workqueue failed\n",
> +				ELAN_DEV_NAME);
> +		goto fail_un;
> +	}
> +
> +	/* INIT polling machinams */
> +	INIT_WORK(&ts->pollingwork, elants_pollWork_func);
> +
> +	pdata = client->dev.platform_data;
> +	if (!pdata) {
> +		dev_err(&client->dev,
> +				"[ELAN] %s no platform data\n",
> +				ELAN_DEV_NAME);
> +		goto fail_un;
> +	}
> +
> +	ts->status &= STA_INIT;
> +
> +	ts->intr_gpio = pdata->intr_gpio;
> +	ts->rst_gpio = pdata->rst_gpio;
> +	/* set initial i2c address */
> +	client->addr = elan_i2c_master;
> +	ts->i2caddr = client->addr;
> +
> +	elan_dbg(client,
> +			 "reset=%d, intr=%d\n", ts->rst_gpio,
ts->intr_gpio);
> +
> +	ts->client = client;
> +	i2c_set_clientdata(client, ts);
> +
> +	/* INIT kfifo */
> +	err = kfifo_alloc(&ts->fifo, FIFO_SIZE, GFP_KERNEL);
> +	if (!kfifo_initialized(&ts->fifo)) {
> +		dev_err(&client->dev,
> +				"%s error kfifo_alloc\n", __func__);
> +		goto fail_un;
> +	}
> +
> +	ts->status &= STA_INIT2;
> +
> +	ts->input = input_allocate_device();
> +	if (ts->input == NULL) {
> +		dev_err(&client->dev,
> +				"[ELAN] %s Failed to allocate input
device\n",
> +				ELAN_DEV_NAME);
> +		goto fail_un;
> +	}
> +
> +	ts->input->name = ELAN_DEV_NAME;
> +	ts->input->open = elan_open;
> +	ts->input->close = elan_close;
> +
> +	/* Says HELLO to touch device */
> +	ts->thread = kthread_run(probe_thread_func, ts, client->name);
> +	if (IS_ERR(ts->thread)) {
> +		err = PTR_ERR(ts->thread);
> +		goto fail_un;
> +	}
> +
> +	ts->status &= STA_INIT3;
> +
> +	/* - register sysfs  @} */
> +	elan_dbg(client,
> +			 "[ELAN] create sysfs!!\n");
> +	if (sysfs_create_group(&client->dev.kobj, &elan_attribute_group))
> +		dev_err(&client->dev,
> +				"[ELAN] sysfs create group error\n");
> +
> +
> +	return 0;
> +
> +fail_un:
> +	remove_elants(client);
> +	return err;
> +}
> +
> +static int __devexit elants_remove(struct i2c_client *client)
> +{
> +	return remove_elants(client);
> +}
> +
> +#ifdef CONFIG_PM_SLEEP
> +/** @brief \b elan_ts_suspend	-	enter sleep mode
> + *
> + *	when Suspend mode, disable_irq and cancel work queue.
> + *
> + */
> +static int elants_suspend(struct device *dev)
> +{
> +	struct i2c_client *client = to_i2c_client(dev);
> +	struct elants_data *ts = i2c_get_clientdata(client);
> +	const u8 set_sleep_cmd[] = {0x54, 0x50, 0x00, 0x01};
> +	int rc = 0;
> +
> +	dev_err(&client->dev,
> +			"[ELAN] %s: enter\n", __func__);
> +
> +	/* Command not support in IAP recovery mode */
> +	if (test_bit(idx_update_fw, &ts->flags))
> +		return 0;
> +
> +	disable_irq(client->irq);
> +	cancel_work_sync(&ts->work);
> +
> +	mutex_lock(&ts->mutex);
> +	rc = elants_set_data(client,
> +						 set_sleep_cmd,
sizeof(set_sleep_cmd));
> +
> +	if (rc < 0)
> +		goto end;
> +
> +	ts->power_state = 0;
> +	/* de-active timer */
> +	del_timer_sync(&ts->polling.timer);
> +
> +
> +end:
> +	mutex_unlock(&ts->mutex);
> +	return rc;
> +}
> +
> +
> +/** @brief \b elan_ts_resume	-	enter wake-up mode
> + *
> + *	when Wake-up mode, enable_irq.
> + *
> + */
> +static int elants_resume(struct device *dev)
> +{
> +	struct i2c_client *client = to_i2c_client(dev);
> +	struct elants_data *ts = i2c_get_clientdata(client);
> +	const u8 set_active_cmd[] = {0x54, 0x58, 0x00, 0x01};
> +	int rc = 0, retry = 5;
> +
> +	dev_err(&client->dev,
> +			"[ELAN] %s: enter\n", __func__);
> +
> +	/* Command not support in IAP recovery mode */
> +	if (test_bit(idx_update_fw, &ts->flags))
> +		return 0;
> +
> +	mutex_lock(&ts->mutex);
> +
> +	do {
> +		rc = elants_set_data(client,
> +							 set_active_cmd,
sizeof(set_active_cmd));
> +		elan_msleep(2);
> +		rc = elants_get_power_state(client);
> +		if (unlikely(rc != PWR_STATE_NORMAL))
> +			dev_err(&client->dev,
> +					"[ELAN] %s: wake up tp failed! err =
%d\n",
> +					__func__, rc);
> +		else
> +			break;
> +	} while (--retry);
> +
> +	ts->power_state = 1;
> +	mutex_unlock(&ts->mutex);
> +
> +	/* re-active poll timer */
> +	mod_timer(&ts->polling.timer, jiffies + 10 * HZ);
> +
> +	enable_irq(client->irq);
> +
> +	return rc;
> +}
> +#endif
> +
> +static SIMPLE_DEV_PM_OPS(elants_pm, elants_suspend, elants_resume);
> +
> +/*! brief system registeration */
> +static const struct i2c_device_id elan_ts_id[] = {
> +	{ ELAN_DEV_NAME, 0 },
> +	{ }
> +};
> +MODULE_DEVICE_TABLE(i2c, elan_ts_id);
> +
> +/*! brief system registeration */
> +static struct i2c_driver elan_ts_driver = {
> +	.probe		= elants_probe,
> +	.remove		= __devexit_p(elants_remove),
> +	.id_table	= elan_ts_id,
> +	.driver		= {
> +		.name	= ELAN_DEV_NAME,
> +		.owner	= THIS_MODULE,
> +		.bus    = &i2c_bus_type,
> +		.pm		= &elants_pm,
> +	},
> +};
> +
> +module_i2c_driver(elan_ts_driver);
> +
> +
> +MODULE_VERSION(DRIVER_VERSION);
> +MODULE_DESCRIPTION("Elan Microelectronics Touchpanels");
> +MODULE_LICENSE("GPL");
> diff --git a/include/linux/i2c/elants.h b/include/linux/i2c/elants.h
> new file mode 100644
> index 0000000..df46e1e
> --- /dev/null
> +++ b/include/linux/i2c/elants.h
> @@ -0,0 +1,56 @@
> +#ifndef _LINUX_I2C_ELANTS_H
> +#define _LINUX_I2C_ELANTS_H
> +
> +#define ELAN_DEV_NAME	"elants_i2c"
> +
> +/* set TSP resolution by actual TPM */
> +#define ELAN_X_MAX  2944
> +#define ELAN_Y_MAX  1856
> +
> +
> +/*! @brief \b platform data
> + * @param intr_gpio : gpio pin
> + * @param rst_gpio : interuption pin
> + *
> + * Platform data, all platform dependent variable should put here.
> + *
> + */
> +struct elan_i2c_platform_data {
> +	unsigned short version;
> +	unsigned int abs_x_min;
> +	unsigned int abs_x_max;
> +	unsigned int abs_y_min;
> +	unsigned int abs_y_max;
> +	int intr_gpio;
> +	int rst_gpio;
> +};
> +
> +/*! @brief \b ioctl command definition.
> + * @param IOCTL_I2C_SLAVE : set i2c address that would be controled right
now.
> + * @param IOCTL_MAJOR_FW_VER : fw major number
> + * @param IOCTL_MINOR_FW_VER : fw minor number
> + * @param IOCTL_RESET : Hardware Reset
> + * @param IOCTL_SET_COMMAND : control command set to TP device.
> + * @param IOCTL_GET_COMMAND : get response from our TP device.
> + * @param IOCTL_IAP_ENABLE : Enter IAP mode
> + * @param IOCTL_IAP_DISABLE : Leave IAP mode
> + * @param IOCTL_I2C_INT : gpio status
> + *
> + *
> + * ioctl command, easy user to control our TP from application.
> + *
> + */
> +#define ELAN_IOCTLID		0xD0
> +#define IOCTL_I2C_SLAVE		_IOW(ELAN_IOCTLID,  1, int)
> +#define IOCTL_MAJOR_FW_VER  _IOR(ELAN_IOCTLID, 2, int)
> +#define IOCTL_MINOR_FW_VER  _IOR(ELAN_IOCTLID, 3, int)
> +#define IOCTL_RESET			_IOW(ELAN_IOCTLID, 4, int)
> +#define IOCTL_I2C_INT		_IOR(ELAN_IOCTLID, 8, int)
> +#define IOCTL_SET_COMMAND	_IOW(ELAN_IOCTLID, 9, unsigned long)
> +#define IOCTL_GET_COMMAND	_IOR(ELAN_IOCTLID, 10, unsigned long)
> +#define IOCTL_IAP_ENABLE	_IOW(ELAN_IOCTLID, 11, int)
> +#define IOCTL_IAP_DISABLE	_IOW(ELAN_IOCTLID, 12, int)
> +#define IOCTL_CHECK_RECOVERY_MODE	_IOR(ELAN_IOCTLID, 13, int)
> +#define IOCTL_BOOTCODE_CMD	_IOW(ELAN_IOCTLID, 14, unsigned long)
> +
> +#endif /* _LINUX_I2C_ELANTS_H */
> --
> 1.7.9.5
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-input" in
> the body of a message to majordomo@xxxxxxxxxxxxxxx
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

--
To unsubscribe from this list: send the line "unsubscribe linux-i2c" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Linux GPIO]     [Linux SPI]     [Linux Hardward Monitoring]     [LM Sensors]     [Linux USB Devel]     [Linux Media]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux