From: Scott Liu <scott....@emc.com.tw>

This patch is for Elan eKTH Touchscreen product, I2C adpater module.

Signed-off-by: Scott Liu <scott....@emc.com.tw>
---
 drivers/input/touchscreen/Kconfig      |   12 +
 drivers/input/touchscreen/Makefile     |    1 +
 drivers/input/touchscreen/elants_i2c.c | 1789 ++++++++++++++++++++++++++++++++
 3 files changed, 1802 insertions(+)
 create mode 100644 drivers/input/touchscreen/elants_i2c.c

diff --git a/drivers/input/touchscreen/Kconfig 
b/drivers/input/touchscreen/Kconfig
index 961d58d..b400faa 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -317,6 +317,18 @@ config TOUCHSCREEN_GUNZE
          To compile this driver as a module, choose M here: the
          module will be called gunze.
 
+config TOUCHSCREEN_ELAN
+       tristate "Elan touchscreens"
+       depends on I2C
+       help
+         Say Y here if you have an Elan touchscreen connected to
+         your system.
+
+         If unsure, say N.
+
+         To compile this driver as a module, choose M here: the
+         module will be called elan.
+
 config TOUCHSCREEN_ELO
        tristate "Elo serial touchscreens"
        select SERIO
diff --git a/drivers/input/touchscreen/Makefile 
b/drivers/input/touchscreen/Makefile
index 62801f2..687d5a7 100644
--- a/drivers/input/touchscreen/Makefile
+++ b/drivers/input/touchscreen/Makefile
@@ -30,6 +30,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..e46675a
--- /dev/null
+++ b/drivers/input/touchscreen/elants_i2c.c
@@ -0,0 +1,1789 @@
+/*
+ * Elan Microelectronics touchpanels with I2C interface
+ *
+ * Copyright (C) 2012 Elan Microelectronics Corporation.
+ * Scott Liu <scott....@emc.com.tw>
+ *
+ * This code is partly based on hid-multitouch.c:
+ *
+ *  Copyright (c) 2010-2012 Stephane Chatty <cha...@enac.fr>
+ *  Copyright (c) 2010-2012 Benjamin Tissoires <benjamin.tissoi...@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/async.h>
+#include <linux/i2c.h>
+#include <linux/delay.h>
+#include <linux/uaccess.h>
+#include <linux/buffer_head.h>
+#include <linux/version.h>
+#include <linux/kfifo.h>
+#include <linux/slab.h>
+#include <linux/debugfs.h>
+#include <linux/firmware.h>
+#include <linux/version.h>
+#include <linux/input/mt.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...)   \
+       do {    \
+               if (debug)      \
+                       dev_printk(KERN_DEBUG, \
+                               &client->dev, fmt, ##arg);      \
+       } while (0)
+
+/*
+ * Device, Driver information
+ */
+#define DEVICE_NAME    "elants_i2c"
+
+#define DRV_MA_VER 1
+#define DRV_MI_VER 0
+#define DRV_SUB_MI_VER 4
+
+#define _str(s) (#s)
+#define str(s)  _str(s)
+#define DRIVER_VERSION  str(DRV_MA_VER.DRV_MI_VER.DRV_SUB_MI_VER)
+
+/* For CMT (must match XRANGE/YRANGE as defined in board config */
+#define X_PIXELS_PER_MM        13
+#define Y_PIXELS_PER_MM        14
+
+/*
+ * Finger report description
+ */
+
+#define MAX_CONTACT_NUM        10
+
+/*
+ * 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 };
+
+/*
+ * Elan I2C Address definition
+ */
+
+#define        DEV_MASTER      0x10
+#define        DEV_SLAVE1      0x20
+#define        DEV_SLAVE2      0x21
+#define        MAX_DEVICE      3
+
+/*
+ * Finger report header byte definition
+ */
+
+#define        REPORT_HEADER_10_FINGER 0x62
+
+/*
+ * Buffer mode Queue Header information
+ */
+
+#define        QUEUE_HEADER_SINGLE     0x62
+#define        QUEUE_HEADER_NORMAL     0X63
+#define QUEUE_HEADER_WAIT      0x64
+#define        QUEUE_HEADER_SIZE       4
+
+#define PACKET_SIZE    55
+#define        MAX_PACKET_LEN  169
+
+/*
+ * Command header definition
+ */
+
+#define        CMD_HEADER_WRITE        0x54
+#define        CMD_HEADER_READ 0x53
+#define CMD_HEADER_6B_READ     0x5B
+#define        CMD_HEADER_RESP 0x52
+#define        CMD_HEADER_6B_RESP      0x9B
+#define        CMD_HEADER_HELLO        0x55
+#define        CMD_HEADER_REK  0x66
+#define        CMD_RESP_LEN    4
+
+/*
+ * FW information position
+ */
+
+#define        FW_POS_HEADER   0
+#define        FW_POS_STATE    1
+#define        FW_POS_TOTAL    2
+#define        FW_POS_CHECKSUM 34
+#define        FW_POS_WIDTH    35
+#define FW_POS_PRESSURE 45
+
+/*
+ * test_bit definition
+ */
+
+#define        LOCK_FILE_OPERATE       0
+#define        LOCK_CMD_HANDSHAKE      1
+#define        LOCK_FINGER_REPORT      2
+#define        LOCK_FW_UPDATE  3
+
+/*
+ * kfifo return value definition
+ */
+
+#define RET_OK 0
+#define        RET_CMDRSP      1
+#define        RET_FAIL        -1
+
+/*
+ * define boot condition definition
+ */
+
+#define        E_BOOT_NORM     0
+#define        E_BOOT_IAP      1
+
+/* FW read command, 0x53 0x?? 0x0, 0x01 */
+#define        E_ELAN_INFO_FW_VER      0x00
+#define        E_ELAN_INFO_BC_VER      0x10
+#define E_ELAN_INFO_TEST_VER   0xe0
+#define        E_ELAN_INFO_FW_ID       0xf0
+
+/**
+ * struct multi_queue_header - used by buffer queue header
+ *
+ * @packet_id: packet_id represented status of buffer.
+ * @report_count: number of finger report in buffer.
+ * @report_length: total length exclusive queue length.
+ */
+struct multi_queue_header {
+       u8 packet_id;
+       u8 report_count;
+       u8 report_length;
+       u8 reserved;
+};
+
+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;
+};
+
+/**
+ * struct elants_data - represents a global define of elants device
+ */
+struct elants_data {
+
+       bool irq_wake;
+
+       /* [0] : Solution version
+          [1] : minor version */
+       union {
+               u8 _fw_version[2];
+               u16 fw_version;
+       };
+
+       u8 bc_version;
+       u8 iap_version;
+
+       union {
+               u8 _test_version[2];
+               u16 test_version;
+       };
+
+       bool fw_enabled;
+       int rows;
+       int cols;
+       int x_max;
+       int y_max;
+#define IAP_MODE_ENABLE        1
+       unsigned int iap_mode;
+       unsigned int rx_size;
+
+       u8 packet_size;
+
+       struct multi_queue_header mq_header;
+
+       struct i2c_client *client;
+       struct input_dev *input;
+       struct task_struct *thread;
+
+       struct mutex mutex;     /* Protects I2C accesses to device */
+       struct mutex tr_mutex;  /* Protects I2C tx/rx */
+
+       unsigned long flags;    /* device flags */
+
+       unsigned short i2caddr;
+
+       struct kfifo fifo;
+       struct mutex fifo_mutex;
+       wait_queue_head_t wait;
+       spinlock_t rx_kfifo_lock;
+
+       struct mt_device td;    /* mt device */
+
+       /* fields required for debug fs */
+       struct mutex dbfs_mutex;
+       struct dentry *dbfs_root;
+
+       /* Add for TS driver debug */
+       long int irq_received;
+       long int packet_received;
+       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;
+};
+
+/*
+ *  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);
+}
+
+static inline bool elan_chip_number(u8 addr)
+{
+       return addr == DEV_MASTER ? 1 : 0;
+}
+
+/**
+ *     elan_set_data - set command to TP.
+ *
+ *     @client: our i2c device
+ *     @data: command or data which will send to TP.
+ *     @len: command length usually.
+ *
+ *     set command to our TP.
+ */
+static int elan_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, "Enter: %s\n", __func__);
+       elan_dbg(client,
+                "%s cmd: %*phC, addr=%x\n",
+                __func__, (int)len, data, 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,
+                       "i2c_transfer write fail, rc=%d\n", rc);
+
+       mutex_unlock(&ts->tr_mutex);
+
+       /* If everything went ok (i.e. 1 msg transmitted), return #0
+          transmitted, else error code. */
+       return (rc < 0) ? -EIO : 0;
+
+}
+
+/**
+ *     elan_get_data - get command to TP.
+ *
+ *     @client: our i2c device
+ *     @data: data to be received from TP.
+ *     @len: command length usually.
+ *
+ *     get data from our TP.
+ */
+static int elan_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, "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, "i2c_transfer read fail, rc=%d\n", rc);
+
+       elan_dbg(client, "%s len=%zu data:%*phC\n",
+                __func__, len, (int)len, buf);
+
+       mutex_unlock(&ts->tr_mutex);
+
+       /* If everything went ok (i.e. 1 msg transmitted), return #0
+          transmitted, else error code. */
+       return rc != 1 ? -EIO : 0;
+}
+
+/**
+ *     elan_i2c_read_block
+ *
+ *     @client: our i2c device
+ *     @cmd: command
+ *     @val: data to be received from TP.
+ *     @len: command length usually.
+ *
+ *     get data from our TP by continueous read.
+ */
+static int elan_i2c_read_block(struct i2c_client *client,
+                              u8 *cmd, u8 *val, u16 len)
+{
+       struct i2c_msg msgs[2];
+       int ret;
+
+       dev_dbg(&client->dev, "Enter: %s\n", __func__);
+
+       msgs[0].addr = client->addr;
+       msgs[0].flags = client->flags & I2C_M_TEN;
+       msgs[0].len = 4;
+       msgs[0].buf = cmd;
+
+       msgs[1].addr = client->addr;
+       msgs[1].flags = client->flags & I2C_M_TEN;
+       msgs[1].flags |= I2C_M_RD;
+       msgs[1].len = len;
+       msgs[1].buf = val;
+
+       ret = i2c_transfer(client->adapter, msgs, 2);
+       return (ret == 2) ? len : ret;
+}
+
+static int elan_dbfs_open(struct inode *inode, struct file *file)
+{
+       int retval = 0;
+       struct elants_data *ts = inode->i_private;
+
+       dev_dbg(&ts->client->dev, "Enter %s\n", __func__);
+
+       if (!ts)
+               return -ENODEV;
+
+       retval = mutex_lock_interruptible(&ts->dbfs_mutex);
+       if (retval)
+               return retval;
+
+       if (!kobject_get(&ts->client->dev.kobj)) {
+               retval = -ENODEV;
+               goto dbfs_out;
+       }
+
+       file->private_data = ts;
+dbfs_out:
+       mutex_unlock(&ts->dbfs_mutex);
+       return retval;
+}
+
+static ssize_t elan_dbfs_read(struct file *file,
+                             char __user *buffer, size_t count, loff_t *ppos)
+{
+       u8 rxbuf[256];
+       int ret;
+       struct elants_data *ts = file->private_data;
+       struct i2c_adapter *adap = ts->client->adapter;
+       struct i2c_msg msg;
+
+       if (count > 256)
+               return -EMSGSIZE;
+
+       msg.addr = ts->i2caddr;
+       msg.flags = ts->client->flags & I2C_M_TEN;
+       msg.flags |= I2C_M_RD;
+       msg.len = count;
+       msg.buf = rxbuf;
+
+       ret = i2c_transfer(adap, &msg, 1);
+       if (ret == 1)
+               if (copy_to_user(buffer, rxbuf, count))
+                       return -EFAULT;
+
+       /* If everything went ok (i.e. 1 msg transmitted), return #bytes
+          transmitted, else error code. */
+       return (ret == 1) ? count : ret;
+}
+
+static ssize_t elan_dbfs_write(struct file *file,
+                              const char __user *buffer, size_t count,
+                              loff_t *ppos)
+{
+       int ret;
+       u8 txbuf[256];
+       struct elants_data *ts = file->private_data;
+       struct i2c_adapter *adap = ts->client->adapter;
+       struct i2c_msg msg;
+
+       if (count > 256)
+               return -EMSGSIZE;
+
+       if (copy_from_user(txbuf, buffer, count))
+               return -EFAULT;
+
+       msg.addr = ts->i2caddr;
+       msg.flags = ts->client->flags & I2C_M_TEN;
+       msg.len = count;
+       msg.buf = (char *)txbuf;
+
+       ret = i2c_transfer(adap, &msg, 1);
+       if (ret != 1)
+               dev_err(&ts->client->dev,
+                       "i2c_master_send fail, ret=%d\n", ret);
+
+       /* If everything went ok (i.e. 1 msg transmitted), return #bytes
+          transmitted, else error code. */
+       return (ret == 1) ? count : ret;
+}
+
+static int elan_dbfs_release(struct inode *inode, struct file *file)
+{
+       struct elants_data *ts = file->private_data;
+
+       if (!ts)
+               return -ENODEV;
+
+       if (ts->dbfs_root) {
+               debugfs_remove_recursive(ts->dbfs_root);
+               mutex_destroy(&ts->dbfs_mutex);
+       }
+
+       return 0;
+}
+
+static const struct file_operations elan_debug_fops = {
+       .owner = THIS_MODULE,
+       .open = elan_dbfs_open,
+       .release = elan_dbfs_release,
+       .read = elan_dbfs_read,
+       .write = elan_dbfs_write,
+};
+
+static int elan_dbfs_init(struct elants_data *ts)
+{
+       /* Create a global debugfs root for all elan ts devices */
+       ts->dbfs_root = debugfs_create_dir(DEVICE_NAME, NULL);
+       if (ts->dbfs_root == ERR_PTR(-ENODEV))
+               ts->dbfs_root = NULL;
+
+       mutex_init(&ts->dbfs_mutex);
+
+       debugfs_create_file("elan-iap", 0777,
+                           ts->dbfs_root, ts, &elan_debug_fops);
+
+       return 0;
+}
+
+/**
+ * elan_sw_reset - software reset.
+ *
+ * @client: our i2c device
+ *     retval >0 means reset success,
+ *     otherwise is fail.
+ *
+ */
+static int elan_sw_reset(struct i2c_client *client)
+{
+       int ret;
+       const u8 srst[4] = { 0x77, 0x77, 0x77, 0x77 };
+
+       dev_dbg(&client->dev, "Enter: %s\n", __func__);
+
+       ret = i2c_master_send(client, srst, sizeof(srst));
+
+       if (ret != sizeof(srst)) {
+               dev_err(&client->dev, "%s: i2c_master_send failed\n", __func__);
+               return -ENODEV;
+       }
+
+       /* Wait to send fastboot command */
+       elan_msleep(10);
+
+       return ret;
+}
+
+static int elan_boot(struct i2c_client *client, u16 addr, u8 type)
+{
+       int rc;
+       struct elants_data *ts = i2c_get_clientdata(client);
+       uint8_t command[2][4] = {
+               {0x4D, 0x61, 0x69, 0x6E},
+               {0x45, 0x49, 0x41, 0x50},
+       };
+
+       ts->i2caddr = addr;
+       rc = elan_set_data(client, command[(int32_t) type], 4);
+       if (rc < 0) {
+               if (type == E_BOOT_IAP)
+                       dev_err(&client->dev, "Boot IAP fail, error=%d\n", rc);
+               else
+                       dev_dbg(&client->dev,
+                               "Boot normal fail, error=%d\n", rc);
+               ts->i2caddr = DEV_MASTER;
+               return -EINVAL;
+       }
+       dev_info(&client->dev, "Boot success -- 0x%x\n", addr);
+       ts->i2caddr = DEV_MASTER;
+       return 0;
+}
+
+/**
+ *     __hello_packet_handler  - hadle hello packet.
+ *
+ *     @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;
+       uint8_t buf_recv[4] = { 0 };
+       struct elants_data *ts = i2c_get_clientdata(client);
+
+       dev_dbg(&client->dev, "Enter: %s\n", __func__);
+
+       rc = elan_get_data(client, buf_recv, 4);
+
+       /* Print buf_recv anyway */
+       dev_info(&client->dev, "rc=%d HelloPacket:%*phC\n",
+                       rc, 4, buf_recv);
+
+       if (rc < 0) {
+               dev_err(&client->dev,
+                       "%s: Try recovery because of no hello\n", __func__);
+       }
+
+       if (memcmp(buf_recv, hello_packet, 4)) {
+               if (!memcmp(buf_recv, recov_packet, 4)) {
+                       dev_info(&client->dev,
+                                "got mainflow recovery message\n");
+
+                       ts->iap_mode = IAP_MODE_ENABLE;
+                       set_bit(LOCK_FW_UPDATE, &ts->flags);
+               }
+
+               return -ENODEV;
+       }
+
+       ts->i2caddr = DEV_MASTER;
+
+       return rc;
+}
+
+/**
+ * Firmware version is for something big movement.
+ * ex: CodeBase update.
+ */
+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_READ,
+               E_ELAN_INFO_FW_VER, 0x00, 0x01
+       };
+       uint8_t buf_recv[4] = { 0x0 };
+
+       dev_dbg(&client->dev, "Enter: %s\n", __func__);
+
+       /* Command not support in IAP recovery mode */
+       if (test_bit(LOCK_FW_UPDATE, &ts->flags))
+               return 0;
+retry:
+       rc = elan_i2c_read_block(client, (u8 *) cmd, buf_recv, 4);
+       if (rc < 0)
+               elan_dbg(client,
+                        "read fw version rc=%d, buf=%*phC\n", rc, 4, buf_recv);
+
+       if (buf_recv[0] == CMD_HEADER_RESP) {
+               ts->_fw_version[0] = ((buf_recv[1] & 0x0f) << 4) |
+                   ((buf_recv[2] & 0xf0) >> 4);
+               ts->_fw_version[1] = ((buf_recv[2] & 0x0f) << 4) |
+                   ((buf_recv[3] & 0xf0) >> 4);
+
+               if (ts->fw_version == 0x00 || ts->fw_version == 0xFF) {
+                       dev_err(&client->dev,
+                               "\n\nFW version is empty, "
+                               "suggest IAP ELAN chip\n\n");
+                       return -EINVAL;
+               }
+       } else {
+               elan_dbg(client, "read fw retry tries=%d\n", tries);
+               if (tries > 0) {
+                       tries--;
+                       goto retry;
+               }
+
+               ts->fw_version = 0xffff;
+               dev_err(&client->dev,
+                       "\n\nFW version is empty, "
+                       "suggest IAP ELAN chip\n\n");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+/**
+ * Test version is for something minor change.
+ * ex: parameters, coordination
+ */
+static int __test_packet_handler(struct i2c_client *client)
+{
+       struct elants_data *ts = i2c_get_clientdata(client);
+       int rc, tries = 3;
+       const uint8_t cmd[] = { CMD_HEADER_READ,
+               E_ELAN_INFO_TEST_VER, 0x00, 0x01
+       };
+       uint8_t buf_recv[4] = { 0x0 };
+
+       dev_dbg(&client->dev, "Enter: %s\n", __func__);
+
+       /* Command not support in IAP recovery mode */
+       if (test_bit(LOCK_FW_UPDATE, &ts->flags))
+               return 0;
+retry:
+       rc = elan_i2c_read_block(client, (u8 *) cmd, buf_recv, 4);
+       if (rc < 0) {
+               elan_dbg(client, "read test version error rc=%d, buf=%*phC\n",
+                        rc, 4, buf_recv);
+               return rc;
+       }
+
+       if (buf_recv[0] == CMD_HEADER_RESP) {
+               ts->_test_version[0] = ((buf_recv[1] & 0x0f) << 4) |
+                   ((buf_recv[2] & 0xf0) >> 4);
+               ts->_test_version[1] = ((buf_recv[2] & 0x0f) << 4) |
+                   ((buf_recv[3] & 0xf0) >> 4);
+       } else {
+               elan_dbg(client, "read fw retry tries=%d\n", tries);
+               if (tries > 0) {
+                       tries--;
+                       goto retry;
+               }
+               ts->test_version = 0xffff;
+               dev_err(&client->dev, "Get test version fail\n");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int __tp_info_handler(struct i2c_client *client)
+{
+       struct i2c_msg msgs[2];
+       struct elants_data *ts = i2c_get_clientdata(client);
+       int rc;
+       uint8_t buf_recv[17] = { 0x0 };
+       const uint8_t get_resolution_cmd[] = {
+               CMD_HEADER_6B_READ, 0x00, 0x00, 0x00, 0x00, 0x00
+       };
+
+       dev_dbg(&client->dev, "Enter: %s\n", __func__);
+
+       /* Command not support in IAP recovery mode */
+       if (test_bit(LOCK_FW_UPDATE, &ts->flags))
+               return 0;
+
+       msgs[0].addr = client->addr;
+       msgs[0].flags = client->flags & I2C_M_TEN;
+       msgs[0].len = 6;
+       msgs[0].buf = (u8 *) get_resolution_cmd;
+
+       msgs[1].addr = client->addr;
+       msgs[1].flags = client->flags & I2C_M_TEN;
+       msgs[1].flags |= I2C_M_RD;
+       msgs[1].len = sizeof(buf_recv);
+       msgs[1].buf = buf_recv;
+
+       rc = i2c_transfer(client->adapter, msgs, 2);
+       if (rc < 0) {
+               elan_dbg(client, "tp_info error rc=%d\n", rc);
+               return rc;
+       }
+
+       if (buf_recv[0] != CMD_HEADER_6B_RESP)
+               return -EINVAL;
+
+       ts->rows = (buf_recv[2] + buf_recv[6] + buf_recv[10]);
+       ts->cols = (buf_recv[3] + buf_recv[7] + buf_recv[11]);
+
+       if (ts->rows < 2 || ts->cols < 2) {
+               dev_warn(&client->dev,
+                        "Invalid resolution (%d, %d)\n", ts->rows, ts->cols);
+
+               ts->rows = -1;
+               ts->cols = -1;
+
+               return 0;
+       }
+
+       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 __bc_packet_handler(struct i2c_client *client)
+{
+       struct elants_data *ts = i2c_get_clientdata(client);
+       const u8 get_bc_ver_cmd[] = { CMD_HEADER_READ,
+               E_ELAN_INFO_BC_VER, 0x00, 0x01
+       };
+       u8 buf_recv[4];
+       int rc;
+
+       dev_dbg(&client->dev, "Enter: %s\n", __func__);
+
+       /* Command not support in IAP recovery mode */
+       if (test_bit(LOCK_FW_UPDATE, &ts->flags))
+               return 0;
+
+       rc = elan_i2c_read_block(client, (u8 *) get_bc_ver_cmd,
+                                buf_recv, sizeof(buf_recv));
+       if (rc < 0) {
+               dev_err(&client->dev,
+                       "Read FW version error rc=%d, buf=%*phC\n", rc, 4,
+                       buf_recv);
+               return rc;
+       }
+
+       ts->bc_version = (((buf_recv[1] & 0x0f) << 4) |
+                         ((buf_recv[2] & 0xf0) >> 4));
+       ts->iap_version = (((buf_recv[2] & 0x0f) << 4) |
+                          ((buf_recv[3] & 0xf0) >> 4));
+       return 0;
+}
+
+static int __elan_fastboot(struct i2c_client *client)
+{
+       int rc = 0;
+
+       dev_dbg(&client->dev, "Enter: %s\n", __func__);
+
+       rc = elan_boot(client, DEV_MASTER, E_BOOT_NORM);
+       if (rc < 0)
+               return -1;
+
+       /* Wait for Hello packets */
+       msleep(50);
+
+       return rc;
+}
+
+static int elan_open(struct input_dev *input)
+{
+       struct elants_data *ts = input_get_drvdata(input);
+
+       dev_dbg(&ts->client->dev, "Enter: %s\n", __func__);
+
+       return 0;
+}
+
+static void elan_close(struct input_dev *input)
+{
+       struct elants_data *ts = input_get_drvdata(input);
+
+       dev_dbg(&ts->client->dev, "Enter %s\n", __func__);
+
+       return;
+}
+
+/**
+*      elan_touch_pull_frame - pull a frame from the fifo
+*
+*      @ts: our elan touch device
+*      @buf: data buffer
+*
+*      Pulls a frame from the FIFO into the provided ehr and data buffer.
+*      The data buffer must be at least CMD_RESP_LEN bytes long.
+*/
+static int elan_touch_pull_frame(struct elants_data *ts, u8 *buf)
+{
+       dev_dbg(&ts->client->dev, "Enter: %s\n", __func__);
+
+       WARN_ON(kfifo_out_locked(&ts->fifo, buf, CMD_RESP_LEN,
+                                &ts->rx_kfifo_lock)
+               != CMD_RESP_LEN);
+       return CMD_RESP_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_RESP_LEN];
+
+       dev_dbg(&ts->client->dev, "Enter: %s\n", __func__);
+
+       while (kfifo_len(&ts->fifo) + room >= FIFO_SIZE)
+               elan_touch_pull_frame(ts, buffer);
+}
+
+/**
+ *     elan_getrepoinfo - parse Multi-queue report header
+ *
+ *     @client: our i2c device
+ *     @buf: buffer data
+ *
+ *     parsing report header and get data length.
+ *
+ */
+static int elan_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;
+       struct multi_queue_header *mq = &ts->mq_header;
+       const u8 wait_packet[4] = { 0x64, 0x64, 0x64, 0x64 };
+       int times = 10, rc = 0;
+
+       dev_dbg(&client->dev, "Enter: %s\n", __func__);
+
+       switch (buf[FW_POS_HEADER]) {
+       case CMD_HEADER_HELLO:
+               if (!memcmp(buf, hello_packet, 4))
+                       ts->wdt_reset++;
+               return RET_CMDRSP;
+       case CMD_HEADER_RESP:
+       case CMD_HEADER_REK:
+               /* Queue the data, using the fifo lock to serialize
+                * the multiple accesses to the FIFO
+                */
+               elan_dbg(client, "recv CMD_HEADER_RESP\n");
+
+               mutex_lock(&ts->fifo_mutex);
+               if (kfifo_len(&ts->fifo) + CMD_RESP_LEN >= FIFO_SIZE)
+                       elan_touch_fifo_clean_old(ts, CMD_RESP_LEN);
+               /* Push the data */
+               kfifo_in_locked(&ts->fifo, buf,
+                               CMD_RESP_LEN, &ts->rx_kfifo_lock);
+               mutex_unlock(&ts->fifo_mutex);
+
+               elan_dbg(client, "wake_up [%*phC]\n", 4, buf);
+               wake_up_interruptible(&ts->wait);
+               return RET_CMDRSP;
+               /* Buffer mode header */
+       case QUEUE_HEADER_NORMAL:
+               elan_dbg(client,
+                        "report_count=%d report_len=%d\n",
+                        buff->report_count, buff->report_length);
+
+               if (buff->report_count <= 3) {
+                       mq->report_count = buff->report_count;
+                       mq->report_length = buff->report_length;
+                       ts->rx_size = mq->report_length;
+                       ts->packet_size = mq->report_length / mq->report_count;
+               } else
+                       return RET_FAIL;
+
+               break;
+       case QUEUE_HEADER_WAIT:
+               dev_info(&client->dev,
+                        "QUEUE_HEADER_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);
+                               elan_get_data(client, (u8 *) buff, ts->rx_size);
+                       } while ((buff->packet_id != QUEUE_HEADER_NORMAL) &&
+                                (--times > 0));
+                       if (times > 0)
+                               rc = elan_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,
+                                mq->report_count, mq->report_length);
+               } else
+                       dev_err(&client->dev,
+                               "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_SINGLE:
+               mq->report_count = 1;
+               mq->report_length = PACKET_SIZE;
+               ts->rx_size = mq->report_length;
+               return ts->rx_size;
+       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 = MAX_PACKET_LEN;
+               elan_get_data(client, (u8 *) buff, ts->rx_size);
+               return RET_FAIL;
+       }
+
+       return ts->rx_size;
+}
+
+/**
+ *     elan_touch_checksum -  Add for checksum mechanism
+ *
+ *     @client : our i2c device
+ *     @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);
+
+       dev_dbg(&client->dev, "Enter: %s\n", __func__);
+
+       for (i = 0; i < FW_POS_CHECKSUM; i++)
+               checksum = checksum + buf[i];
+
+       ts->checksum_correct = checksum;
+
+       if (checksum != buf[FW_POS_CHECKSUM]) {
+               ts->checksum_fail++;
+               dev_err(&client->dev,
+                       "elan touch checksum fail: %02x:%02x\n",
+                       checksum, buf[FW_POS_CHECKSUM]);
+               return -EFAULT;
+       }
+
+       return 0;
+}
+
+/**
+ *     elan_parse_fid - parse the 10 fid bits
+ *
+ *     @data: the input bit stream
+ *     @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_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);
+}
+
+/**
+ *      elan_parse_wid - parse width data with length of 5-bit
+ *
+ *      @data: the input bit stream
+ *      @wid: an array of width level
+ *
+ *      Unpack the 10 bits into an array.
+ */
+static inline void elan_parse_wid(u8 *data, u8 *wid)
+{
+       wid[0] = (data[0] & 0x1f);
+       wid[1] = (data[1] & 0x1f);
+       wid[2] = (data[2] & 0x1f);
+       wid[3] = (data[3] & 0x1f);
+       wid[4] = (data[4] & 0x1f);
+       wid[5] = (data[5] & 0x1f);
+       wid[6] = (data[6] & 0x1f);
+       wid[7] = (data[7] & 0x1f);
+       wid[8] = (data[8] & 0x1f);
+       wid[9] = (data[9] & 0x1f);
+
+       return;
+}
+
+/**
+ *      elan_parse_pid - parse pressure data with length of 8-bit
+ *
+ *      @data: the input bit stream
+ *      @wid: an array of width level
+ *
+ *      Unpack the 10 bits into an array.
+ */
+static inline void elan_parse_pid(u8 *data, u8 *pressure)
+{
+       pressure[0] = data[0];
+       pressure[1] = data[1];
+       pressure[2] = data[2];
+       pressure[3] = data[3];
+       pressure[4] = data[4];
+       pressure[5] = data[5];
+       pressure[6] = data[6];
+       pressure[7] = data[7];
+       pressure[8] = data[8];
+       pressure[9] = data[9];
+
+       return;
+}
+
+static inline int elan_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;
+}
+
+static inline int elan_lookup_wid(u8 data, u16 *w, u16 *h)
+{
+       static u16 pre_w = 0, pre_h = 0, 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;
+
+       *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)
+{
+       int i;
+       for (i = 0; i < td->maxcontacts; ++i) {
+               if (td->slots[i].contactid == td->curdata.contactid &&
+                   td->slots[i].touch_state)
+                       return i;
+       }
+       for (i = 0; i < td->maxcontacts; ++i) {
+               if (!td->slots[i].seen_in_this_frame &&
+                   !td->slots[i].touch_state)
+                       return i;
+       }
+       /* should not occurs. If this happens that means
+        * that the device sent more touches that it says
+        * in the report descriptor. It is ignored then. */
+       return -1;
+}
+
+/*
+* 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)
+{
+       td->curdata.seen_in_this_frame = true;
+       if (td->curvalid) {
+               int slotnum = elan_mt_compute_slot(td);
+
+               if (slotnum >= 0 && slotnum < td->maxcontacts)
+                       td->slots[slotnum] = td->curdata;
+       }
+       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 elan_mt_emit_event(struct mt_device *td, struct input_dev *input)
+{
+       struct elants_data *ts = container_of(td, struct elants_data, td);
+       int i;
+
+       for (i = 0; i < td->maxcontacts; ++i) {
+               struct mt_slot *s = &(td->slots[i]);
+               if (!s->seen_in_this_frame)
+                       s->touch_state = false;
+
+               input_mt_slot(input, i);
+               input_mt_report_slot_state(input, MT_TOOL_FINGER,
+                                          s->touch_state);
+               if (s->touch_state) {
+                       /* this finger is on the screen */
+                       int major = max(s->w, s->h), minor = min(s->w, s->h);
+
+                       elan_dbg(ts->client, "i=%d x=%d y=%d p=%d w=%d h=%d.\n",
+                                i, s->x, s->y, s->p, 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_PRESSURE, s->p);
+                       input_event(input, EV_ABS, ABS_MT_TOUCH_MAJOR, major);
+               }
+               s->seen_in_this_frame = false;
+       }
+
+       input_mt_report_pointer_emulation(input, true);
+       input_sync(input);
+       td->num_received = 0;
+}
+
+/**
+ *     elan_mt_event - process finger reports
+ *     @ts: our touchscreen
+ *     @finger_stat: number of fingers in packet
+ *     @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] = { 0 };
+       u8 wid[MAX_CONTACT_NUM] = { 0 };
+       u8 pid[MAX_CONTACT_NUM] = { 0 };
+       u16 x = 0, y = 0, w = 0, h = 0;
+       struct i2c_client *client = ts->client;
+       struct mt_device *td = &ts->td;
+
+       dev_dbg(&client->dev, "Enter: %s\n", __func__);
+
+       /* Parsing Finger, Width, Pressure field */
+       elan_parse_fid(&buf[FW_POS_STATE], &fid[0]);
+       elan_parse_wid(&buf[FW_POS_WIDTH], &wid[0]);
+       elan_parse_pid(&buf[FW_POS_PRESSURE], &pid[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;
+
+               elan_parse_xy(&buf[3 + i * 3], &x, &y);
+               td->curdata.x = x;
+               td->curdata.y = y;
+               td->curdata.p = pid[i];
+
+               h = w = wid[i];
+               td->curdata.w = w;
+               td->curdata.h = h;
+
+               finger_stat--;
+
+               elan_mt_complete_slot(td);
+       }
+
+       if (td->num_received >= td->num_expected)
+               elan_mt_emit_event(td, ts->input);
+
+       return 1;
+}
+
+/**
+ *     elan_report_data - report finger report to user space.
+ *
+ *     @client : our i2c device
+ *     @buf : raw data from TP device.
+ *
+ *     - reporting finger data to user space.
+ *
+ */
+static void elan_report_data(struct i2c_client *client, uint8_t *buf)
+{
+       struct elants_data *ts = i2c_get_clientdata(client);
+
+       dev_dbg(&client->dev, "Enter: %s\n", __func__);
+
+       switch (buf[FW_POS_HEADER]) {
+       case REPORT_HEADER_10_FINGER:{
+                       u8 finger_stat = buf[FW_POS_TOTAL] & 0x0f;
+                       elan_dbg(client, "finger_stat == %d\n", finger_stat);
+                       elan_dbg(client, "finger:%*phC\n", 10, buf);
+
+                       /* Enter right process, reset int_status */
+                       ts->packet_received++;
+
+                       if (likely(finger_stat != 0)) {
+                               ts->td.curvalid = true;
+                               ts->touched_sync++;
+                       } else {
+                               ts->no_touched_sync++;
+                       }
+                       elan_mt_event(ts, finger_stat, buf);
+               }
+               break;
+       default:
+               ts->header_fail++;
+               dev_warn(&client->dev,
+                        "%s: unknown packet type: %*phC\n", __func__, 10, buf);
+               break;
+       }
+
+       return;
+}
+
+static irqreturn_t elan_work_func(int irq, void *work)
+{
+       struct elants_data *ts = work;
+       struct i2c_client *client = ts->client;
+
+       uint8_t buf[MAX_PACKET_LEN] = { 0x0 };
+       u8 pos = 0, rc = 0;
+
+       dev_dbg(&client->dev, "Enter: %s\n", __func__);
+
+       ts->irq_received++;
+
+       if (test_bit(LOCK_FW_UPDATE, &ts->flags))
+               return IRQ_HANDLED;
+
+       mutex_lock(&ts->mutex);
+
+       set_bit(LOCK_FINGER_REPORT, &ts->flags);
+
+       /* - Read multi_queue header */
+       rc = elan_get_data(client, (u8 *) buf, ts->rx_size);
+       if (rc < 0)
+               goto fail;
+
+       /*  - Get multi_queue header info */
+       rc = elan_getrepoinfo(ts->client, buf);
+       if (rc < 0 || rc == RET_CMDRSP)
+               goto fail;
+
+       /*  - check if packet size is valid */
+       if ((ts->packet_size != PACKET_SIZE)) {
+               dev_err(&ts->client->dev, "%s: uncorrect packet size = %d\n",
+                       __func__, ts->packet_size);
+               goto fail;
+       }
+
+       /* - Get finger report data */
+       rc = elan_get_data(client, (u8 *) buf, ts->rx_size);
+       if (rc < 0)
+               goto fail;
+
+       clear_bit(LOCK_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)
+                       elan_report_data(ts->client, buf + pos);
+               pos = pos + ts->packet_size;
+               udelay(10);
+       }
+
+       ts->rx_size = QUEUE_HEADER_SIZE;
+
+       return IRQ_HANDLED;
+
+fail:
+       clear_bit(LOCK_FINGER_REPORT, &ts->flags);
+       mutex_unlock(&ts->mutex);
+       ts->rx_size = QUEUE_HEADER_SIZE;
+
+       return IRQ_HANDLED;
+}
+
+static int remove_elants(struct i2c_client *client)
+{
+       int ret = 0;
+       struct elants_data *ts = i2c_get_clientdata(client);
+
+       if ((client->irq))
+               free_irq(client->irq, ts);
+
+       if (ts->input)
+               input_unregister_device(ts->input);
+
+       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);
+
+       kfree(ts->td.slots);
+       kfifo_free(&ts->fifo);
+       kfree(ts);
+
+       return ret;
+}
+
+static int elan_input_dev_create(struct elants_data *ts)
+{
+       int err = 0;
+       struct i2c_client *client = ts->client;
+
+       if (ts->rows > 0 && ts->cols > 0) {
+               /* translate trace number to TSP resolution */
+               ts->x_max = ELAN_TS_RESOLUTION(ts->rows);
+               ts->y_max = ELAN_TS_RESOLUTION(ts->cols);
+       } else
+               dev_warn(&client->dev, "trace number error, %d,%d\n",
+                        ts->rows, ts->cols);
+
+       /* Clear the existing one if it exists */
+       if (ts->input) {
+               input_unregister_device(ts->input);
+               ts->input = NULL;
+       }
+
+       ts->input = input_allocate_device();
+       if (ts->input == NULL) {
+               dev_err(&client->dev, "Failed to allocate input device\n");
+               return -ENOMEM;
+       }
+
+       ts->input->name = "Elan-Touchscreen";
+       ts->input->id.bustype = BUS_I2C;
+       ts->input->dev.parent = &ts->client->dev;
+       ts->input->open = elan_open;
+       ts->input->close = elan_close;
+
+       __set_bit(BTN_TOUCH, ts->input->keybit);
+       __set_bit(EV_ABS, ts->input->evbit);
+       __set_bit(EV_KEY, ts->input->evbit);
+
+       /*! - Single touch input params setup */
+       input_set_abs_params(ts->input, ABS_X, 0, ts->x_max, 0, 0);
+       input_set_abs_params(ts->input, ABS_Y, 0, ts->y_max, 0, 0);
+       input_set_abs_params(ts->input, ABS_PRESSURE, 0, 255, 0, 0);
+       input_abs_set_res(ts->input, ABS_X, X_PIXELS_PER_MM);
+       input_abs_set_res(ts->input, ABS_Y, Y_PIXELS_PER_MM);
+
+       ts->td.maxcontacts = MAX_CONTACT_NUM;
+       ts->td.mt_flags |= INPUT_MT_DIRECT;
+
+       /* Multitouch input params setup */
+       err =
+           input_mt_init_slots(ts->input, ts->td.maxcontacts, ts->td.mt_flags);
+       if (err) {
+               dev_err(&client->dev,
+                       "allocate memory for MT slots failed, %d\n", err);
+               goto err_free_device;
+       }
+
+       input_set_abs_params(ts->input, ABS_MT_POSITION_X, 0, ts->x_max, 0, 0);
+       input_set_abs_params(ts->input, ABS_MT_POSITION_Y, 0, ts->y_max, 0, 0);
+       input_set_abs_params(ts->input, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0);
+       input_set_abs_params(ts->input, ABS_MT_PRESSURE, 0, 255, 0, 0);
+       input_abs_set_res(ts->input, ABS_MT_POSITION_X, X_PIXELS_PER_MM);
+       input_abs_set_res(ts->input, ABS_MT_POSITION_Y, Y_PIXELS_PER_MM);
+
+       input_set_drvdata(ts->input, ts);
+
+       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 err_free_device;
+       }
+
+       err = input_register_device(ts->input);
+       if (err) {
+               dev_err(&client->dev, "unable to register input device\n");
+               goto err_free_slot;
+       }
+
+       return 0;
+
+err_free_slot:
+       kfree(ts->td.slots);
+err_free_device:
+       input_free_device(ts->input);
+       ts->input = NULL;
+       return err;
+}
+
+/**
+ *     elan_initialize - initialization process.
+ *
+ *     @client: our i2c client
+ *
+ *     set our TP up
+ *     -# reset
+ *     -# hello packet
+ *     -# fw version
+ *     -# test version
+ *     -# TP info (resolution)
+ *
+ */
+static int elan_initialize(struct i2c_client *client)
+{
+       struct elants_data *ts = i2c_get_clientdata(client);
+       u8 buf[4] = { 0 };
+       int rc;
+
+       dev_dbg(&client->dev, "Enter: %s\n", __func__);
+
+       /* handle recovery packets */
+       rc = elan_get_data(client, buf, 3);
+       if (rc == 0) {
+               if (!memcmp(buf, recov_packet + 2, 2)) {
+                       ts->iap_mode = IAP_MODE_ENABLE;
+                       set_bit(LOCK_FW_UPDATE, &ts->flags);
+                       dev_err(&client->dev, "Get recovery packet == %*phC\n",
+                               3, buf);
+
+                       return -ENODEV;
+               }
+       }
+
+       rc = elan_sw_reset(client);
+       if (rc < 0) {
+               dev_err(&client->dev, "Software reset failed\n");
+               /* continue */
+       }
+
+       ts->rx_size = QUEUE_HEADER_SIZE;
+
+       rc = __elan_fastboot(client);
+       if (rc < 0)
+               dev_err(&client->dev, "fastboot failed, rc=%d\n", rc);
+
+       /*! - elan hello packet init */
+       rc = __hello_packet_handler(client);
+       if (rc < 0) {
+               dev_err(&client->dev, "hello packet error.\n");
+
+               return -ENODEV;
+       }
+
+       /* elan fw version */
+       rc = __fw_packet_handler(client);
+       if (rc < 0) {
+               dev_err(&client->dev, "firmware checking error rc=%d\n", rc);
+
+               if (rc == -EINVAL) {
+                       set_bit(LOCK_FW_UPDATE, &ts->flags);
+                       ts->iap_mode = IAP_MODE_ENABLE;
+               }
+       }
+
+       /* elan TP information */
+       rc = __tp_info_handler(client);
+       if (rc < 0) {
+               dev_err(&client->dev, "TP information checking error.\n");
+               /* Go through down */
+       }
+
+       /* elan test version */
+       rc = __test_packet_handler(client);
+       if (rc < 0) {
+               dev_err(&client->dev, "test version error\n");
+               /* Go through down */
+       }
+
+       /* Get TS BootCode version */
+       rc = __bc_packet_handler(client);
+       if (rc < 0) {
+               dev_err(&client->dev, "TP get BC version error.\n");
+               /* Go through down */
+       }
+
+       return 0;
+}
+
+/**
+ *     elan_initialize_async   - 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 void elan_initialize_async(void *data, async_cookie_t cookie)
+{
+       struct elants_data *ts = data;
+       struct i2c_client *client = ts->client;
+       int err = 0;
+
+       mutex_lock(&ts->mutex);
+
+       err = elan_initialize(client);
+       if (err < 0)
+               dev_err(&client->dev, "probe failed! unbind device.\n");
+
+       err = elan_input_dev_create(ts);
+       if (err) {
+               dev_err(&client->dev, "%s crated failed, %d\n", __func__, err);
+               goto fail_un;
+       }
+
+       dev_info(&client->dev, "Elan Touchscreen Information:\n\r");
+       dev_info(&client->dev,
+                "    Firmware Version:  0x%04x\n\r", ts->fw_version);
+       dev_info(&client->dev,
+                "    Test Version:  0x%04x\n\r", ts->test_version);
+       dev_info(&client->dev, "    BC Version:  0x%04x\n\r", ts->bc_version);
+       dev_info(&client->dev, "    IAP Version:  0x%04x\n\r", ts->iap_version);
+       dev_info(&client->dev, "    Trace Num:   %d, %d\n", ts->rows, ts->cols);
+       dev_info(&client->dev, "    Resolution X,Y:  %d,%d\n",
+                       ts->x_max, ts->y_max);
+
+       err = request_threaded_irq(client->irq, NULL,
+                                  elan_work_func,
+                                  IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+                                  client->name, ts);
+       if (err) {
+               dev_err(&client->dev, "Failed to register interrupt\n");
+               goto fail_un;
+       }
+
+       mutex_unlock(&ts->mutex);
+
+       return;
+
+fail_un:
+       mutex_unlock(&ts->mutex);
+       remove_elants(client);
+       return;
+}
+
+/**
+ *     elan_probe - probe for touchpad
+ *
+ *     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 elan_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 (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+               dev_err(&client->dev,
+                       "%s: i2c check functionality error\n", DEVICE_NAME);
+               return -ENODEV;
+       }
+
+       ts = kzalloc(sizeof(struct elants_data), GFP_KERNEL);
+       if (!ts)
+               return -ENOMEM;
+
+       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);
+
+       err = elan_dbfs_init(ts);
+       if (err < 0) {
+               dev_err(&client->dev, "error create elan debugfs.\n");
+               goto fail_un;
+       } else
+               ts->fw_enabled = 1;
+
+       pdata = client->dev.platform_data;
+       if (!pdata) {
+               dev_err(&client->dev,
+                       "%s No platform data provided\n", DEVICE_NAME);
+       }
+
+       /* set initial i2c address */
+       client->addr = DEV_MASTER;
+       ts->i2caddr = client->addr;
+
+       ts->client = client;
+       i2c_set_clientdata(client, ts);
+
+       /* initial 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;
+       }
+
+       /* Says HELLO to touch device */
+       async_schedule(elan_initialize_async, ts);
+
+       device_init_wakeup(&client->dev, true);
+
+       return 0;
+
+fail_un:
+       remove_elants(client);
+       return err;
+}
+
+static int elan_remove(struct i2c_client *client)
+{
+       return remove_elants(client);
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int elan_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_dbg(&client->dev, "Enter: %s\n", __func__);
+
+       /* Command not support in IAP recovery mode */
+       if (test_bit(LOCK_FW_UPDATE, &ts->flags))
+               return 0;
+
+       mutex_lock(&ts->mutex);
+       rc = elan_set_data(client, set_sleep_cmd, sizeof(set_sleep_cmd));
+       if (rc < 0)
+               dev_err(&client->dev, "suspend command failed!\n");
+
+       if (device_may_wakeup(dev))
+               ts->irq_wake = (enable_irq_wake(client->irq) == 0);
+
+       disable_irq(client->irq);
+
+       mutex_unlock(&ts->mutex);
+
+       return 0;
+}
+
+static int elan_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;
+
+       dev_dbg(&client->dev, "Enter: %s\n", __func__);
+
+       /* Command not support in IAP recovery mode */
+       if (test_bit(LOCK_FW_UPDATE, &ts->flags))
+               return 0;
+
+       if (device_may_wakeup(dev) && ts->irq_wake)
+               disable_irq_wake(client->irq);
+
+       mutex_lock(&ts->mutex);
+
+       rc = elan_set_data(client, set_active_cmd, sizeof(set_active_cmd));
+       if (rc < 0)
+               dev_err(&client->dev, "resume command failed!\n");
+
+       enable_irq(client->irq);
+
+       mutex_unlock(&ts->mutex);
+
+       return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(elan_pm_ops, elan_suspend, elan_resume);
+
+static const struct i2c_device_id elan_ts_id[] = {
+       {DEVICE_NAME, 0},
+       {}
+};
+
+MODULE_DEVICE_TABLE(i2c, elan_ts_id);
+
+static struct i2c_driver elan_ts_driver = {
+       .probe = elan_probe,
+       .remove = elan_remove,
+       .id_table = elan_ts_id,
+       .driver = {
+                  .name = DEVICE_NAME,
+                  .owner = THIS_MODULE,
+                  .pm = &elan_pm_ops,
+                  },
+};
+
+module_i2c_driver(elan_ts_driver);
+
+MODULE_VERSION(DEVICE_NAME);
+MODULE_DESCRIPTION("Elan I2c Touchscreen driver");
+MODULE_LICENSE("GPL");
-- 
1.7.9.5

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to