input: touch: sharp:fix unbalanced irq disable.
[linux-3.10.git] / drivers / input / touchscreen / lr388k7_ts.c
index cc28c41..3d593af 100644 (file)
@@ -2,6 +2,7 @@
  * LR388K7 touchscreen driver
  *
  * Copyright (C) 2014, Sharp Corporation
+ * Copyright (c) 2015, NVIDIA CORPORATION. All rights reserved.
  *
  * Author: Makoto Itsuki <itsuki.makoto@sharp.co.jp>
  *
 #include <linux/regulator/consumer.h>
 #include <linux/uaccess.h>
 #include <linux/workqueue.h>
+#include <linux/jiffies.h>
+#include <linux/spinlock_types.h>
+#ifdef CONFIG_TOUCHSCREEN_NVTOUCH
+#include "nvtouch/nvtouch_kernel.h"
+u8 nvtouch_data[20000];
+#endif
 
 /* DEBUG */
 #ifndef DEBUG_LR388K7
 #define DEBUG_LR388K7
 #endif
 
-/* INPUT_ENABLE */
-#define INPUT_ENABLE
 /* ACTIVE */
 /* #define ACTIVE_ENABLE */
+/* UDEV */
+#define UDEV_ENABLE
+
 
 #ifdef __min
 #undef __min
@@ -83,7 +91,7 @@
 #define K7_CMD_DATA_OFFSET (0x030400)
 #define K7_CMD_DATA_SIZE (251 + K7_RD_HEADER_SIZE)
 #define K7_Q_SIZE (8)
-#define K7_DRIVER_VERSION (6)
+#define K7_DRIVER_VERSION (18)
 #define K7_INT_STATUS_MASK_DATA (0x01)
 #define K7_INT_STATUS_MASK_BOOT (0x02)
 #define K7_INT_STATUS_MASK_CMD  (0x04)
 #define K7_REMOTE_WAKEUP_CODE (0xEA)
 #define K7_DEFAULT_MODE (3)
 
+enum K7_SCAN_STATE_OPTIONS {
+       K7_SCAN_STATE_IDLE = 0,
+       K7_SCAN_STATE_ACTIVE,
+};
 
 enum K7_SLOW_SCAN_OPTIONS {
        K7_SLOW_SCAN_30 = 30,
@@ -114,6 +126,8 @@ struct lr388k7_ts_parameter {
        bool b_is_init_finish;
        bool b_is_calc_finish;
        bool b_is_suspended;
+       bool b_is_reset;
+       bool b_is_disabled;
        u32 u32SCK;
        u16 u16fw_ver;
        u16 u16module_ver;
@@ -125,6 +139,10 @@ struct lr388k7 {
        struct spi_device       *spi;
        struct device           *dev;
        struct input_dev        *idev;
+       struct pinctrl          *pinctrl;
+       struct pinctrl_state    *spi_intf_en;
+       struct pinctrl_state    *spi_intf_dis;
+
 #if defined(ACTIVE_ENABLE)
        struct input_dev        *idev_active;
        int                     tool;
@@ -179,12 +197,46 @@ struct lr388k7_active_report {
 };
 #endif
 
+
+#if defined(UDEV_ENABLE)
+struct lr388k7_udev_event {
+       u8 str[512];
+};
+#endif
+
+static int dev_open(struct inode *inode, struct file *filp);
+static int dev_release(struct inode *inode, struct file *filp);
+static ssize_t
+dev_read(struct file *filp, char __user *buf, size_t count, loff_t *pos);
+static ssize_t
+dev_write(struct file *filp, const char __user *buf,
+         size_t count, loff_t *pos);
+static long dev_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
+
+static const struct file_operations dev_fops = {
+       .owner = THIS_MODULE,
+       .open = dev_open,
+       .release = dev_release,
+       .read = dev_read,
+       .write = dev_write,
+       .unlocked_ioctl = dev_ioctl,
+       .compat_ioctl = dev_ioctl,
+};
+
+static struct miscdevice lr388k7_ts_miscdev = {
+       .minor = MISC_DYNAMIC_MINOR,
+       .name = "touch",
+       .fops = &dev_fops,
+};
+
 static struct spi_device *g_spi;
 static struct lr388k7_ts_parameter g_st_state;
 static struct lr388k7_queue_info g_st_q;
 static struct lr388k7_cmd_queue_info g_st_cmd_q;
 static struct lr388k7_ts_dbg g_st_dbg;
 static u8 g_u8_mode;
+static u8 g_u8_scan;
+static u16 g_u16_wakeup_enable;
 static u32 g_u32_raw_data_size = 50 * 88 * 2;
 
 #define IS_DBG (g_st_dbg.u8ForceCap == 1 || \
@@ -213,8 +265,10 @@ static int lr388k7_hardreset(unsigned long wait)
                return false;
 
        gpio_set_value(ts->gpio_reset, 0);
+       g_st_state.b_is_reset = true;
        usleep_range(wait * 1000, wait * 1000 + 1000);
        gpio_set_value(ts->gpio_reset, 1);
+       g_st_state.b_is_reset = false;
        return true;
 }
 
@@ -413,6 +467,9 @@ static u8 lr388k7_clear_irq(void)
        u8 u8Ret = 0;
        size_t count = 1;
 
+       if (g_st_state.b_is_reset)
+               return u8Ret;
+
        u8_tx_buf[0] = K7_RD_OPCODE;
        u8_tx_buf[1] = (K7_INT_STATUS_ADDR >> 16) & 0xFF;
        u8_tx_buf[2] = (K7_INT_STATUS_ADDR >>  8) & 0xFF;
@@ -570,32 +627,6 @@ static void lr388k7_read_spec_size(void)
        }
 }
 
-static bool lr388k7_check_status(void)
-{
-       u8 u8_tx_buf[K7_RD_HEADER_SIZE + 1], u8_rx_buf[K7_RD_HEADER_SIZE + 1];
-       u8 u8Ret = 0;
-       size_t count = 1;
-
-       u8_tx_buf[0] = K7_RD_OPCODE;
-       u8_tx_buf[1] = (K7_CMD_DATA_OFFSET >> 16) & 0xFF;
-       u8_tx_buf[2] = (K7_CMD_DATA_OFFSET >>  8) & 0xFF;
-       u8_tx_buf[3] = (K7_CMD_DATA_OFFSET >>  0) & 0xFF;
-       u8_tx_buf[4] = 0x00;
-
-       g_st_state.u32SCK = 0;
-
-       if (lr388k7_spi_read(u8_tx_buf, u8_rx_buf, count)) {
-               u8Ret = u8_rx_buf[K7_RD_HEADER_SIZE];
-
-               if (u8Ret == K7_REMOTE_WAKEUP_CODE)
-                       return true;
-       }
-
-       g_st_state.u32SCK = g_spi->max_speed_hz;
-
-       return false;
-}
-
 static void lr388k7_event_handler(u8 u8Status)
 {
        void *p_q_buf;
@@ -622,6 +653,41 @@ static void lr388k7_event_handler(u8 u8Status)
                 */
                if (g_st_state.b_is_init_finish) {
 
+#ifdef CONFIG_TOUCHSCREEN_NVTOUCH
+                       int  raw_data_size = g_u32_raw_data_size +
+                               K7_DATA_READ_SIZE;
+
+                       n_ret = lr388k7_read_data((u8 *)nvtouch_data);
+
+                       if (nvtouch_get_driver_mode() !=
+                               NVTOUCH_DRIVER_CONFIG_MODE_VENDOR_ONLY) {
+                               if (n_ret)
+                                       nvtouch_kernel_process(nvtouch_data,
+                                                       raw_data_size,
+                                                       g_u8_mode);
+                               else
+                                       pr_err("lr388k7_read_data failed.\n");
+                       }
+
+
+
+                       if (nvtouch_get_driver_mode() !=
+                               NVTOUCH_DRIVER_CONFIG_MODE_NVTOUCH_ONLY) {
+                               /*
+                                *      Get pointer of queue buffer
+                                */
+                               p_q_buf = lr388k7_enqueue_start();
+                               if (p_q_buf) {
+                                       memcpy(p_q_buf, nvtouch_data,
+                                                       raw_data_size);
+                                       if (n_ret)
+                                               lr388k7_enqueue_finish();
+                               }
+                       }
+                       /* Nvtouch end */
+
+
+#else
                        /*
                         * Get pointer of queue buffer
                         */
@@ -633,6 +699,8 @@ static void lr388k7_event_handler(u8 u8Status)
                        } else {
                                lr388k7_read_spec_size();
                        }
+#endif
+
                } else {
                        lr388k7_read_spec_size();
                }
@@ -683,6 +751,10 @@ static void lr388k7_work_handler(struct work_struct *work)
                return;
        }
 
+#ifdef CONFIG_TOUCHSCREEN_NVTOUCH
+       nvtouch_kernel_timestamp_touch_irq();
+#endif
+
        mutex_lock(&ts->mutex);
 
        /*
@@ -698,7 +770,7 @@ static void lr388k7_work_handler(struct work_struct *work)
                 * Check if irq is already cleared.
                 */
                irq_value = gpio_get_value(ts->gpio_irq);
-               /*      if(irq_value) // for high-active */
+
                if (!irq_value)
                        u8_status = lr388k7_clear_irq();
                else
@@ -708,22 +780,6 @@ static void lr388k7_work_handler(struct work_struct *work)
        mutex_unlock(&ts->mutex);
 }
 
-static void lr388k7_enable_irq(struct lr388k7 *ts)
-{
-       if (g_st_dbg.wakeup.enable == 1)
-               disable_irq_wake(ts->irq);
-       else
-               enable_irq(ts->irq);
-}
-
-static void lr388k7_disable_irq(struct lr388k7 *ts)
-{
-       if (g_st_dbg.wakeup.enable == 1)
-               enable_irq_wake(ts->irq);
-       else
-               disable_irq(ts->irq);
-}
-
 static irqreturn_t lr388k7_wakeup_thread(int irq, void *_ts)
 {
        struct lr388k7 *ts = (struct lr388k7 *)_ts;
@@ -732,13 +788,8 @@ static irqreturn_t lr388k7_wakeup_thread(int irq, void *_ts)
 
        dev_info(&g_spi->dev, "[ENTER] Wakeup thread\n");
 
+       /* just try to clear */
        u8_status = lr388k7_clear_irq();
-       if (u8_status & K7_INT_STATUS_MASK_CMD) {
-               if (!lr388k7_check_status()) {
-                       lr388k7_event_handler(u8_status);
-                       return IRQ_HANDLED;
-               }
-       }
 
        dev_info(&g_spi->dev, "Tap wakeup\n");
 
@@ -747,15 +798,9 @@ static irqreturn_t lr388k7_wakeup_thread(int irq, void *_ts)
        input_report_key(input_dev, KEY_POWER, 0);
        input_sync(input_dev);
 
-       if (u8_status & K7_INT_STATUS_MASK_DATA) {
-               dev_info(&g_spi->dev, "[DATA] Wakeup thread\n");
-               lr388k7_read_spec_size();
-       }
-
-#if 1
        if (g_st_state.b_is_suspended)
                g_st_state.b_is_suspended = false;
-#endif
+
        dev_info(&g_spi->dev, "[EXIT] Wakeup thread\n");
 
        return IRQ_HANDLED;
@@ -763,6 +808,14 @@ static irqreturn_t lr388k7_wakeup_thread(int irq, void *_ts)
 
 static irqreturn_t lr388k7_irq_thread(int irq, void *_ts)
 {
+       struct lr388k7 *ts = (struct lr388k7 *)_ts;
+       struct input_dev *input_dev = ts->idev;
+
+       if (g_u8_scan == K7_SCAN_STATE_IDLE) {
+               input_event(input_dev, EV_MSC, MSC_ACTIVITY, 1);
+               input_sync(input_dev);
+       }
+
        if (g_st_state.b_is_suspended) {
                if (g_st_dbg.wakeup.enable == 1) {
                        dev_info(&g_spi->dev, "Throw IRQ_WAKE_THREAD\n");
@@ -775,33 +828,16 @@ static irqreturn_t lr388k7_irq_thread(int irq, void *_ts)
        return IRQ_HANDLED;
 }
 
-#if 0
-static void lr388k7_timer(unsigned long handle)
-{
-       struct lr388k7 *ts = (void *)handle;
-}
-#endif
-
-static void lr388k7_start_scan(struct lr388k7 *ts)
-{
-       lr388k7_enable_irq(ts);
-}
-
-static void lr388k7_stop_scan(struct lr388k7 *ts)
-{
-       lr388k7_disable_irq(ts);
-}
-
 /* must be called with ts->mutex held */
 static void __lr388k7_disable(struct lr388k7 *ts)
 {
-       lr388k7_stop_scan(ts);
+       disable_irq(ts->irq);
 }
 
 /* must be called with ts->mutex held */
 static void __lr388k7_enable(struct lr388k7 *ts)
 {
-       lr388k7_start_scan(ts);
+       enable_irq(ts->irq);
 }
 
 static ssize_t lr388k7_ts_force_cap_show(struct device *dev,
@@ -902,11 +938,21 @@ static ssize_t lr388k7_ts_version_show(struct device *dev,
        struct device_attribute *attr,
        char *buf)
 {
+
+#ifdef CONFIG_TOUCHSCREEN_NVTOUCH
+       return sprintf(buf, "FW %d, Driver %d, Module %d, %s\n",
+                       g_st_state.u16fw_ver,
+                       K7_DRIVER_VERSION,
+                       g_st_state.u16module_ver,
+                       nvtouch_kernel_get_version_string()
+                       );
+#else
        return sprintf(buf, "FW %d, Driver %d, Module %d\n",
                       g_st_state.u16fw_ver,
                       K7_DRIVER_VERSION,
                       g_st_state.u16module_ver
                       );
+#endif
 }
 
 static ssize_t lr388k7_ts_version_store(struct device *dev,
@@ -921,14 +967,14 @@ static ssize_t lr388k7_ts_slowscan_enable_store(struct device *dev,
        struct device_attribute *attr,
        const char *buf, size_t count)
 {
+#ifdef ENABLE_SLOW_SCAN
        unsigned long val;
        ssize_t err;
        ssize_t ret;
        if (count < 2)
                return -EINVAL;
 
-       if (g_st_state.b_is_suspended &&
-           g_st_dbg.wakeup.enable == 0)
+       if (g_st_state.b_is_suspended)
                return -EINVAL;
 
        ret = (ssize_t) count;
@@ -963,16 +1009,23 @@ static ssize_t lr388k7_ts_slowscan_enable_store(struct device *dev,
        }
 
        return ret;
+#else
+       return count;
+#endif
 }
 
 static ssize_t lr388k7_ts_slowscan_enable_show(struct device *dev,
        struct device_attribute *attr,
        char *buf)
 {
+#ifdef ENABLE_SLOW_SCAN
        return sprintf(buf, "Slow Scan:%s Scan Rate:%dHz\n",
                       g_st_dbg.slowscan.enable ?
                       "Enabled" : "Disabled",
                       g_st_dbg.slowscan.scan_rate);
+#else
+       return sprintf(buf, "Not implemented yet\n");
+#endif
 }
 
 static ssize_t lr388k7_ts_wakeup_enable_store(struct device *dev,
@@ -984,8 +1037,7 @@ static ssize_t lr388k7_ts_wakeup_enable_store(struct device *dev,
        if (count < 2)
                return -EINVAL;
 
-       if (g_st_state.b_is_suspended &&
-           g_st_dbg.wakeup.enable == 0)
+       if (g_st_state.b_is_suspended)
                return -EINVAL;
 
        ret = (ssize_t) count;
@@ -995,6 +1047,12 @@ static ssize_t lr388k7_ts_wakeup_enable_store(struct device *dev,
                        g_st_dbg.wakeup.enable = 0;
                        lr388k7_send_signal(g_st_state.u32_pid,
                                            LR388K7_SIGNAL_CTRL);
+               } else if (buf[0] == '2') {
+                       if (g_st_dbg.wakeup.enable <= 1)
+                               g_u16_wakeup_enable = g_st_dbg.wakeup.enable;
+                       g_st_dbg.wakeup.enable = 2;
+                       lr388k7_send_signal(g_st_state.u32_pid,
+                                           LR388K7_SIGNAL_CTRL);
                }
        } else if ((buf[0] == '1') && (buf[1] == ' ')) {
                /* check if prefined value*/
@@ -1015,13 +1073,259 @@ static ssize_t lr388k7_ts_wakeup_enable_show(struct device *dev,
        struct device_attribute *attr,
        char *buf)
 {
-       return sprintf(buf, "wakeup_enable:%s Number of taps:%d\n",
-                      g_st_dbg.wakeup.enable ?
+       return sprintf(buf, "wakeup_enable:%s(%d) Number of taps:%d\n",
+                      g_st_dbg.wakeup.enable == 1 ?
                       "Enabled" : "Disabled",
+                      g_st_dbg.wakeup.enable,
                       g_st_dbg.wakeup.num_tap);
 }
 
-static DEVICE_ATTR(force_cap, 0666, lr388k7_ts_force_cap_show,
+static ssize_t lr388k7_ts_test_store(struct device *dev,
+       struct device_attribute *attr,
+       const char *buf, size_t count)
+{
+       ssize_t ret;
+
+       if (count != 2)
+               return -EINVAL;
+
+       ret = (ssize_t) count;
+
+       if (buf[0] == '1') {
+               g_st_dbg.u8Test = 1;
+               lr388k7_send_signal(g_st_state.u32_pid,
+                                   LR388K7_SIGNAL_CTRL);
+       } else if (buf[0] == '0') {
+               g_st_dbg.u8Test = 0;
+               lr388k7_send_signal(g_st_state.u32_pid,
+                                   LR388K7_SIGNAL_CTRL);
+       }
+
+       return ret;
+}
+
+static ssize_t lr388k7_ts_test_show(struct device *dev,
+       struct device_attribute *attr,
+       char *buf)
+{
+       return sprintf(buf, "%s\n", g_st_dbg.u8Test == 1 ?
+                      "Enabled" : "Disabled");
+}
+
+#if defined(DEBUG_LR388K7)
+static ssize_t lr388k7_ts_check_state_store(struct device *dev,
+       struct device_attribute *attr,
+       const char *buf, size_t count)
+{
+       ssize_t ret;
+       ret = (ssize_t) count;
+       return ret;
+}
+
+static ssize_t lr388k7_ts_check_state_show(struct device *dev,
+       struct device_attribute *attr,
+       char *buf)
+{
+       struct lr388k7 *ts = spi_get_drvdata(g_spi);
+       u8 u8_tx_buf[K7_RD_HEADER_SIZE + 5], u8_rx_buf[K7_RD_HEADER_SIZE + 5];
+       u8 u8Ret;
+       u8 u8HWR;
+       u32 u32RES, u32FWR;
+       size_t count = 0;
+
+       u8_tx_buf[count++] = K7_RD_OPCODE;
+       u8_tx_buf[count++] = (K7_STATE_CTL_ADDR >> 16) & 0xFF;
+       u8_tx_buf[count++] = (K7_STATE_CTL_ADDR >>  8) & 0xFF;
+       u8_tx_buf[count++] = (K7_STATE_CTL_ADDR >>  0) & 0xFF;
+       u8_tx_buf[count++] = 0x00;
+
+       g_st_state.u32SCK = 0;
+
+       if (lr388k7_spi_read(u8_tx_buf, u8_rx_buf, count)) {
+               u8Ret = u8_rx_buf[K7_RD_HEADER_SIZE];
+       } else {
+               return sprintf(buf, "status :IRQ(%s) Failed to read\n",
+                      gpio_get_value(ts->gpio_irq) ?
+                      "High" : "Low"
+                      );
+       }
+
+       count = 0;
+       u8_tx_buf[count++] = K7_RD_OPCODE;
+       u8_tx_buf[count++] = 0x00;
+       u8_tx_buf[count++] = 0x02;
+       u8_tx_buf[count++] = 0xAC;
+       u8_tx_buf[count++] = 0x00;
+
+       if (lr388k7_spi_read(u8_tx_buf, u8_rx_buf, count)) {
+               u8HWR = u8_rx_buf[K7_RD_HEADER_SIZE];
+       } else {
+               g_st_state.u32SCK = g_spi->max_speed_hz;
+               return sprintf(buf, "status :IRQ(%s) Failed to read\n",
+                      gpio_get_value(ts->gpio_irq) ?
+                      "High" : "Low"
+                      );
+       }
+
+       count = 0;
+       u8_tx_buf[count++] = K7_RD_OPCODE;
+       u8_tx_buf[count++] = 0x00;
+       u8_tx_buf[count++] = 0x02;
+       u8_tx_buf[count++] = 0xB0;
+       u8_tx_buf[count++] = 0x00;
+       u8_tx_buf[count++] = 0x00;
+       u8_tx_buf[count++] = 0x00;
+       u8_tx_buf[count++] = 0x00;
+
+       if (lr388k7_spi_read(u8_tx_buf, u8_rx_buf, count)) {
+               u32FWR = u8_rx_buf[K7_RD_HEADER_SIZE] |
+                       u8_rx_buf[K7_RD_HEADER_SIZE + 1] << 8 |
+                       u8_rx_buf[K7_RD_HEADER_SIZE + 2] << 16 |
+                       u8_rx_buf[K7_RD_HEADER_SIZE + 3] << 24;
+       } else {
+               g_st_state.u32SCK = g_spi->max_speed_hz;
+               return sprintf(buf, "status :IRQ(%s) Failed to read\n",
+                      gpio_get_value(ts->gpio_irq) ?
+                      "High" : "Low"
+                      );
+       }
+
+       count = 0;
+       u8_tx_buf[count++] = K7_RD_OPCODE;
+       u8_tx_buf[count++] = 0x00;
+       u8_tx_buf[count++] = 0x00;
+       u8_tx_buf[count++] = 0x40;
+       u8_tx_buf[count++] = 0x00;
+       u8_tx_buf[count++] = 0x00;
+       u8_tx_buf[count++] = 0x00;
+       u8_tx_buf[count++] = 0x00;
+
+       if (lr388k7_spi_read(u8_tx_buf, u8_rx_buf, count)) {
+               u32RES = u8_rx_buf[K7_RD_HEADER_SIZE] |
+                       u8_rx_buf[K7_RD_HEADER_SIZE + 1] << 8 |
+                       u8_rx_buf[K7_RD_HEADER_SIZE + 2] << 16 |
+                       u8_rx_buf[K7_RD_HEADER_SIZE + 3] << 24;
+       } else {
+               g_st_state.u32SCK = g_spi->max_speed_hz;
+               return sprintf(buf, "status :IRQ(%s) Failed to read\n",
+                      gpio_get_value(ts->gpio_irq) ?
+                      "High" : "Low"
+                      );
+       }
+
+       g_st_state.u32SCK = g_spi->max_speed_hz;
+
+       return sprintf(
+                      buf,
+                      "IRQ(%s) status=0x%02X, HWRev=%d, FWRev=0x%0X, Res=0x%04X\n",
+                      gpio_get_value(ts->gpio_irq) ?
+                      "High" : "Low",
+                      u8Ret,
+                      u8HWR,
+                      u32FWR,
+                      u32RES
+                      );
+}
+#endif
+
+#define LR388K7_LOG_MAX_SIZE (8 * 1024 * 1024)
+#define LR388K7_LOG_DATA_SIZE (512)
+
+struct lr388k7_log {
+       unsigned long seq_num;
+       unsigned long time;
+       unsigned char data[LR388K7_LOG_DATA_SIZE];
+};
+
+DEFINE_SPINLOCK(lr388k7log_lock);
+struct lr388k7_log glog[LR388K7_LOG_MAX_SIZE / sizeof(struct lr388k7_log)];
+static int log_size = sizeof(glog) / sizeof(glog[0]);
+static unsigned long g_seq_num;
+static int g_log_front;
+static int g_log_rear;
+
+
+static ssize_t lr388k7_ts_log_store(struct device *dev,
+       struct device_attribute *attr,
+       const char *buf, size_t count)
+{
+       ssize_t ret;
+       struct lr388k7_log log;
+       unsigned long flags;
+
+       ret = (ssize_t) count;
+
+       g_seq_num++;
+       log.seq_num = g_seq_num;
+       log.time = jiffies;
+       memcpy(log.data, buf, sizeof(log.data));
+       spin_lock_irqsave(&lr388k7log_lock, flags);
+
+       if (((g_log_rear + 1) % log_size) == g_log_front) {
+               g_log_front++;
+               if (g_log_front >= log_size)
+                       g_log_front = 0;
+               g_log_rear++;
+               if (g_log_rear >= log_size)
+                       g_log_rear = 0;
+       } else {
+               g_log_rear++;
+               if (g_log_rear >= log_size)
+                       g_log_rear = 0;
+       }
+
+       glog[g_log_rear] = log;
+
+       spin_unlock_irqrestore(&lr388k7log_lock, flags);
+
+       return ret;
+}
+
+static ssize_t lr388k7_ts_log_show(struct device *dev,
+       struct device_attribute *attr,
+       char *buf)
+{
+       char *s;
+       unsigned long flags;
+       struct lr388k7_log log;
+
+       s = buf;
+
+       sprintf(s,
+               "FW %d, Driver %d, Module %d\n",
+               g_st_state.u16fw_ver,
+               K7_DRIVER_VERSION,
+               g_st_state.u16module_ver
+               );
+
+       s += strlen(s);
+
+       for (; (s - buf) + LR388K7_LOG_DATA_SIZE < PAGE_SIZE; ) {
+               spin_lock_irqsave(&lr388k7log_lock, flags);
+
+               if (g_log_rear == g_log_front) {
+                       spin_unlock_irqrestore(&lr388k7log_lock, flags);
+                       return (ssize_t)(s - buf);
+               } else {
+                       g_log_front++;
+                       if (g_log_front >= log_size)
+                               g_log_front = 0;
+               }
+               log = glog[g_log_front];
+               spin_unlock_irqrestore(&lr388k7log_lock, flags);
+
+               sprintf(s, "[%08lx|%08lx] %s",
+                       log.seq_num,
+                       log.time,
+                       log.data);
+               s += strlen(s);
+       }
+
+       return (ssize_t)(s - buf);
+}
+
+
+static DEVICE_ATTR(force_cap, 0660, lr388k7_ts_force_cap_show,
                        lr388k7_ts_force_cap_store);
 static DEVICE_ATTR(dump, 0666, lr388k7_ts_dump_show,
                        lr388k7_ts_dump_store);
@@ -1036,8 +1340,18 @@ static DEVICE_ATTR(slowscan_enable, 0640,
 static DEVICE_ATTR(wakeup_enable, 0640,
                   lr388k7_ts_wakeup_enable_show,
                   lr388k7_ts_wakeup_enable_store);
+static DEVICE_ATTR(test, 0640,
+                  lr388k7_ts_test_show,
+                  lr388k7_ts_test_store);
+#if defined(DEBUG_LR388K7)
+static DEVICE_ATTR(check_state, 0660,
+                  lr388k7_ts_check_state_show,
+                  lr388k7_ts_check_state_store);
 
-
+static DEVICE_ATTR(log, 0660,
+                  lr388k7_ts_log_show,
+                  lr388k7_ts_log_store);
+#endif
 
 static struct attribute *lr388k7_ts_attributes[] = {
        &dev_attr_force_cap.attr,
@@ -1046,6 +1360,11 @@ static struct attribute *lr388k7_ts_attributes[] = {
        &dev_attr_version.attr,
        &dev_attr_slowscan_enable.attr,
        &dev_attr_wakeup_enable.attr,
+       &dev_attr_test.attr,
+#if defined(DEBUG_LR388K7)
+       &dev_attr_check_state.attr,
+       &dev_attr_log.attr,
+#endif
        NULL
 };
 
@@ -1074,6 +1393,8 @@ static int lr388k7_open(struct input_dev *input)
 static void lr388k7_close(struct input_dev *input)
 {
        struct lr388k7 *ts = input_get_drvdata(input);
+
+       dev_info(&ts->spi->dev, "[ENTER] close\n");
        mutex_lock(&ts->mutex);
 
        __lr388k7_disable(ts);
@@ -1081,8 +1402,47 @@ static void lr388k7_close(struct input_dev *input)
        ts->opened = false;
 
        mutex_unlock(&ts->mutex);
+       dev_info(&ts->spi->dev, "[EXIT] close\n");
 }
 
+
+#if defined(UDEV_ENABLE)
+static void lr388k7_send_udev_event(void *p)
+{
+       struct lr388k7_udev_event *p_udev_event;
+       char *envp[2];
+       char *event;
+
+       if (!p)
+               return;
+
+       p_udev_event = kmalloc(
+                              sizeof(struct lr388k7_udev_event),
+                              GFP_KERNEL);
+
+       if (!p_udev_event)
+               return;
+
+       if (copy_from_user(p_udev_event,
+                         p,
+                         sizeof(struct lr388k7_udev_event))) {
+               kfree(p_udev_event);
+               return;
+       }
+
+       event = kasprintf(GFP_KERNEL, "TRIGGER=%s", p_udev_event->str);
+       if (event) {
+               envp[0] = event;
+               envp[1] = NULL;
+               kobject_uevent_env(&lr388k7_ts_miscdev.this_device->kobj,
+                                  KOBJ_CHANGE,
+                                  envp);
+               kfree(event);
+       }
+       kfree(p_udev_event);
+}
+#endif
+
 #if defined(ACTIVE_ENABLE)
 static void lr388k7_active_report(void *p)
 {
@@ -1165,7 +1525,6 @@ static void lr388k7_touch_report(void *p)
        struct lr388k7 *ts = spi_get_drvdata(g_spi);
        struct input_dev *input_dev = ts->idev;
        bool b_is_eraser = false;
-       /*  struct input_dev *input_dev_pen = ts->idev_pen; */
 
        if (!p)
                return;
@@ -1188,6 +1547,55 @@ static void lr388k7_touch_report(void *p)
 
        u8_num = p_touch_report->u8_num_of_touch;
 
+#ifdef CONFIG_TOUCHSCREEN_NVTOUCH
+
+       /* Send events to nvtouch (for tracing or reporting) */
+       {
+               /* report events through the same interface with nvtouch */
+               struct nvtouch_events *nv_events =
+                       nvtouch_kernel_get_vendor_events_ptr();
+               for (i = 0; i < u8_num; i++) {
+
+                       if (ts->flip_x)
+                               p_touch_report->tc[i].x =
+                               (ts->max_x - p_touch_report->tc[i].x) < 0 ?
+                               0 : ts->max_x - p_touch_report->tc[i].x;
+                       if (ts->flip_y)
+                               p_touch_report->tc[i].y =
+                               (ts->max_y - p_touch_report->tc[i].y) < 0 ?
+                               0 : ts->max_y - p_touch_report->tc[i].y;
+                       if (ts->swap_xy) {
+                               u16 tmp;
+                               tmp = p_touch_report->tc[i] . x;
+                               p_touch_report->tc[i].x =
+                                       p_touch_report->tc[i].y;
+                               p_touch_report->tc[i].y = tmp;
+                       }
+
+                       nv_events->events[i].tracking_id =
+                               p_touch_report->tc[i].id;
+                       nv_events->events[i].position_y =
+                               p_touch_report->tc[i].x;
+                       nv_events->events[i].position_x =
+                               p_touch_report->tc[i].y;
+                       nv_events->events[i].pressure = p_touch_report->tc[i].z;
+                       nv_events->events[i].tool = NVTOUCH_EVENT_TOOL_PEN;
+                       nv_events->timestamp = nvtouch_get_time_us();
+               }
+               nv_events->event_count = u8_num;
+       }
+
+       if ((nvtouch_get_driver_mode() !=
+               NVTOUCH_DRIVER_CONFIG_MODE_VENDOR_ONLY)
+               && (nvtouch_get_driver_mode() !=
+               NVTOUCH_DRIVER_CONFIG_MODE_VENDOR_DTA)
+       ) {
+               /* events will be reported via nvtouch */
+               kfree(p_touch_report);
+               return;
+       }
+#endif
+
        if (u8_num == 0) {
                if (ts->b_eraser_active) {
                        ts->b_eraser_active = false;
@@ -1243,14 +1651,6 @@ static void lr388k7_touch_report(void *p)
                input_report_abs(input_dev,
                                 ABS_MT_PRESSURE,
                                 p_touch_report->tc[i] . z);
-#if 0
-               input_report_abs(input_dev,
-                                ABS_MT_TOUCH_MAJOR,
-                                p_touch_report->tc[i] .width);
-               input_report_abs(input_dev,
-                                ABS_MT_TOUCH_MINOR,
-                                p_touch_report->tc[i] .height);
-#endif
                input_mt_sync(input_dev);
                u8_num_of_touch++;
        }
@@ -1265,7 +1665,6 @@ static void lr388k7_touch_report(void *p)
        struct lr388k7_touch_report *p_touch_report;
        struct lr388k7 *ts = spi_get_drvdata(g_spi);
        struct input_dev *input_dev = ts->idev;
-       /*  struct input_dev *input_dev_pen = ts->idev_pen; */
 
        if (!p)
                return;
@@ -1334,29 +1733,54 @@ static void lr388k7_touch_report(void *p)
                                 p_touch_report->tc[i] . z);
        }
        input_sync(input_dev);
+
+       kfree(p_touch_report);
 }
 #endif /* #if defined(PROTOCOL_A) */
 
+
+static int access_num;
+static spinlock_t dev_spin_lock;
+
 static int dev_open(struct inode *inode, struct file *filp)
 {
 #if defined(DEBUG_LR388K7)
        dev_info(&g_spi->dev, "dev_open\n");
 #endif
 
-       lr388k7_init_parameter();
+       spin_lock(&dev_spin_lock);
+
+       if (access_num) {
+               spin_unlock(&dev_spin_lock);
+               dev_err(&g_spi->dev, "already open : %d\n", -EBUSY);
+               return -EBUSY;
+       }
+
+       access_num++;
+       spin_unlock(&dev_spin_lock);
 
        return 0;
 }
 
 static int dev_release(struct inode *inode, struct file *filp)
 {
-       int ret;
+       struct lr388k7 *ts = spi_get_drvdata(g_spi);
+
 #if defined(DEBUG_LR388K7)
        dev_info(&g_spi->dev, "dev_release\n");
 #endif
+       if (!ts)
+               return -EINVAL;
+
        g_st_state.b_is_init_finish = 0;
 
-       ret = lr388k7_hardreset(1);
+       spin_lock(&dev_spin_lock);
+       access_num--;
+       spin_unlock(&dev_spin_lock);
+
+       /* Reset assert */
+       gpio_set_value(ts->gpio_reset, 0);
+       g_st_state.b_is_reset = true;
 
        return 0;
 }
@@ -1380,7 +1804,6 @@ static int lr388k7_spi_read(u8 *txbuf, u8 *rxbuf, size_t len)
                .rx_buf = rxbuf,
                .speed_hz =
                g_st_state.u32SCK == 0 ? 12000000 : g_spi->max_speed_hz,
-               /*    .speed_hz           = 18000000, */
        };
 
        mutex_lock(&lock);
@@ -1596,11 +2019,21 @@ static int lr388k7_spi_write(u8 *txbuf, size_t len)
 {
        static DEFINE_MUTEX(lock);
        int status;
+       struct spi_message msg;
+       struct spi_transfer t = {
+               .bits_per_word  = 8,
+               .tx_buf = txbuf,
+               .len = len,
+               .speed_hz =
+               len < 16 ? 12000000 : g_spi->max_speed_hz,
+       };
 
        mutex_lock(&lock);
 
+       spi_message_init(&msg);
+       spi_message_add_tail(&t, &msg);
        /*It returns zero on succcess,else a negative error code. */
-       status = spi_write(g_spi, txbuf, len);
+       status = spi_sync(g_spi, &msg);
 
        mutex_unlock(&lock);
 
@@ -1675,6 +2108,11 @@ static long dev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 
        switch (cmd & 0xFFFF) {
        case LR388K7_IOCTL_TOUCH_REPORT:
+#ifdef CONFIG_TOUCHSCREEN_NVTOUCH
+               if (nvtouch_get_driver_mode() ==
+                       NVTOUCH_DRIVER_CONFIG_MODE_NVTOUCH_ONLY)
+                       break;
+#endif
                lr388k7_touch_report((void *) arg);
                break;
 
@@ -1737,6 +2175,9 @@ static long dev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
        case LR388K7_IOCTL_CLEAR_BUFFER:
                lr388k7_queue_reset();
                g_st_state.b_is_init_finish = arg;
+               if (g_st_state.b_is_init_finish)
+                       lr388k7_send_signal(g_st_state.u32_pid,
+                                           LR388K7_SIGNAL_MODE);
                break;
 
        case LR388K7_IOCTL_ACTIVE_REPORT:
@@ -1755,6 +2196,16 @@ static long dev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 #endif
                break;
 
+       case LR388K7_IOCTL_SET_STATE:
+               g_u8_scan = (u8)arg;
+               break;
+
+#if defined(UDEV_ENABLE)
+       case LR388K7_IOCTL_SEND_UDEV:
+               lr388k7_send_udev_event((void *)arg);
+               break;
+#endif
+
        default:
                ret = false;
                break;
@@ -1763,28 +2214,16 @@ static long dev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
        return ret;
 }
 
-static const struct file_operations dev_fops = {
-       .owner = THIS_MODULE,
-       .open = dev_open,
-       .release = dev_release,
-       .read = dev_read,
-       .write = dev_write,
-       .unlocked_ioctl = dev_ioctl,
-       .compat_ioctl = dev_ioctl,
-};
-
-static struct miscdevice lr388k7_ts_miscdev = {
-       .minor = MISC_DYNAMIC_MINOR,
-       .name = "touch",
-       .fops = &dev_fops,
-};
-
 static void lr388k7_init_parameter(void)
 {
+       unsigned long flags;
        g_u8_mode = K7_DEFAULT_MODE;
+       g_u8_scan = K7_SCAN_STATE_IDLE;
        g_st_state.u32_pid = 0;
        g_st_state.b_is_init_finish = false;
        g_st_state.b_is_suspended = false;
+       g_st_state.b_is_reset = false;
+       g_st_state.b_is_disabled = false;
        g_st_state.u32SCK = 0;
        lr388k7_queue_reset();
 
@@ -1794,6 +2233,15 @@ static void lr388k7_init_parameter(void)
        g_st_dbg.wakeup.num_tap = K7_NUM_TAP_2;
        g_st_dbg.u8ForceCap = 0;
        g_st_dbg.u8Dump = 0;
+       g_st_dbg.u8Test = 0;
+       g_u16_wakeup_enable = 0;
+
+       access_num = 0;
+
+       spin_lock_irqsave(&lr388k7log_lock, flags);
+       g_log_front = 0;
+       g_log_rear = 0;
+       spin_unlock_irqrestore(&lr388k7log_lock, flags);
 }
 
 static void lr388k7_init_ts(void)
@@ -1905,6 +2353,38 @@ static struct lr388k7_platform_data *lr388k7_parse_dt(struct device *dev,
        return ERR_PTR(ret);
 }
 
+static void init_spi_pinctrl(struct lr388k7 *ts, struct device *dev)
+{
+       struct pinctrl *pin = NULL;
+       struct pinctrl_state *active, *inactive;
+
+       pin = devm_pinctrl_get(dev);
+       if (IS_ERR(pin)) {
+               dev_err(dev, "missing pinctrl device\n");
+               return;
+       }
+       ts->pinctrl = pin;
+
+       active = pinctrl_lookup_state(pin, "spi_intf_normal");
+       if (IS_ERR_OR_NULL(active)) {
+               dev_err(dev, "missing spi_intf_normal state\n");
+               goto out;
+       }
+       ts->spi_intf_en = active;
+       inactive = pinctrl_lookup_state(pin, "spi_intf_lowpower");
+       if (IS_ERR_OR_NULL(active)) {
+               dev_err(dev, "missing spi_intf_lowpower state\n");
+               goto out;
+       }
+       ts->spi_intf_dis = inactive;
+
+       return;
+out:
+       if (ts->pinctrl)
+               ts->pinctrl = NULL;
+
+}
+
 static int lr388k7_probe(struct spi_device *spi)
 {
        struct lr388k7_platform_data *pdata;/* = spi->dev.platform_data;*/
@@ -1995,7 +2475,6 @@ static int lr388k7_probe(struct spi_device *spi)
        mutex_init(&ts->mutex);
 
        spin_lock_init(&ts->lock);
-       /* setup_timer(&ts->timer, lr388k7_timer, (unsigned long)ts); */
 
        snprintf(ts->phys,
                 sizeof(ts->phys),
@@ -2025,8 +2504,10 @@ static int lr388k7_probe(struct spi_device *spi)
 #endif
        /* Reset assert */
        gpio_set_value(ts->gpio_reset, 0);
+       g_st_state.b_is_reset = true;
+
+       init_spi_pinctrl(ts, dev);
 
-#if 1
        /* regulator */
        ts->regulator_3v3 = devm_regulator_get(&g_spi->dev, "avdd");
        if (IS_ERR(ts->regulator_3v3)) {
@@ -2056,7 +2537,7 @@ static int lr388k7_probe(struct spi_device *spi)
                dev_err(dev,
                        "LR388K7 TS: regulator enable failed: %d\n",
                        error);
-#endif
+
        /* clk */
        if (pdata->name_of_clock || pdata->name_of_clock_con) {
                ts->clk =
@@ -2142,6 +2623,8 @@ static int lr388k7_probe(struct spi_device *spi)
 
 #endif
 
+       input_set_capability(input_dev, EV_MSC, MSC_ACTIVITY);
+
        input_dev->open = lr388k7_open;
        input_dev->close = lr388k7_close;
        input_dev->enable = lr388k7_input_enable;
@@ -2198,25 +2681,18 @@ static int lr388k7_probe(struct spi_device *spi)
        input_set_drvdata(input_dev_active, ts);
 #endif
 
-#if 0
-       error = request_irq(spi->irq, lr388k7_irq_thread,
-                           IRQF_TRIGGER_FALLING,
-                           "lr388k7_ts", ts);
-#else
        error = request_threaded_irq(spi->irq,
                                     lr388k7_irq_thread,
                                     lr388k7_wakeup_thread,
                                     IRQF_TRIGGER_FALLING,
                                     "lr388k7_ts", ts);
 
-#endif
-
        if (error) {
                dev_err(dev, "Failed to request irq, err: %d\n", error);
                goto err_free_mem;
        }
 
-       lr388k7_disable_irq(ts);
+       disable_irq(ts->irq);
 
        spi_set_drvdata(spi, ts);
 
@@ -2256,6 +2732,11 @@ static int lr388k7_probe(struct spi_device *spi)
        device_enable_async_suspend(dev);
 
        dev_info(dev, "[EXIT] probe\n");
+
+#ifdef CONFIG_TOUCHSCREEN_NVTOUCH
+       nvtouch_kernel_init(58, 37, 15360, 9600, 0, 1, input_dev);
+       pr_info("NvTouch init completed\n");
+#endif
        return 0;
 
  err_clear_drvdata:
@@ -2293,7 +2774,7 @@ static int lr388k7_remove(struct spi_device *spi)
        gpio_free(ts->gpio_clk_sel);
 #endif
        input_unregister_device(ts->idev);
-       /* input_unregister_device(ts->idev_pen); */
+
        kfree(ts);
 
        spi_set_drvdata(spi, NULL);
@@ -2328,17 +2809,22 @@ static void lr388k7_ctrl_resume(struct lr388k7 *ts)
 
 static void lr388k7_start(struct lr388k7 *ts)
 {
-       /*
-         int error;
-
-         if(g_st_state.b_is_suspended)
-         return;
-       */
+       int error;
 
        g_st_state.b_is_suspended = false;
 
        mutex_lock(&ts->mutex);
-#if 0
+
+       if (g_st_dbg.wakeup.enable == 1) {
+               lr388k7_ctrl_resume(ts);
+               mutex_unlock(&ts->mutex);
+               return;
+       }
+
+       /* Reset assert */
+       gpio_set_value(ts->gpio_reset, 0);
+       g_st_state.b_is_reset = true;
+
        /*
         * Enable regulator, if necessary
         */
@@ -2348,13 +2834,16 @@ static void lr388k7_start(struct lr388k7 *ts)
                dev_err(&g_spi->dev,
                        "LR388K7 TS: regulator enable failed: %d\n", error);
 
-       usleep_range(15000, 20000);
-
        error = regulator_enable(ts->regulator_3v3);
        if (error < 0)
                dev_err(&g_spi->dev,
                        "LR388K7 TS: regulator enable failed: %d\n", error);
-       usleep_range(15000, 20000);
+
+       usleep_range(5000, 6000);
+
+       if (ts->spi_intf_en)
+               pinctrl_select_state(ts->pinctrl,
+                       ts->spi_intf_en);
 
        /*
         * Enable clock, if necessary
@@ -2362,10 +2851,11 @@ static void lr388k7_start(struct lr388k7 *ts)
        if (ts->clk)
                clk_enable(ts->clk);
 
-       msleep(20);
-#endif
+       /* Reset deassert */
+       gpio_set_value(ts->gpio_reset, 1);
+       g_st_state.b_is_reset = false;
 
-       lr388k7_ctrl_resume(ts);
+       usleep_range(12000, 13000);
 
        mutex_unlock(&ts->mutex);
 }
@@ -2374,33 +2864,36 @@ static void lr388k7_ctrl_suspend(struct lr388k7 *ts)
 {
        u8 u8_buf[5];
        size_t count = 0;
-       /*  int error; */
+       int error;
+       u8 u8_status = 0;
+       int irq_value;
 
        mutex_lock(&ts->mutex);
 
-#if 0
-       if (IS_DBG) {
-               g_st_dbg.u8ForceCap = 0;
-               g_st_dbg.u8Dump = 0;
-               g_st_dbg.slowscan.enable = 0;
+       if (g_st_dbg.wakeup.enable == 1) {
+               u8_buf[count++] = K7_WR_OPCODE;
+               u8_buf[count++] = (K7_STATE_CTL_ADDR >> 16) & 0xFF;
+               u8_buf[count++] = (K7_STATE_CTL_ADDR >>  8) & 0xFF;
+               u8_buf[count++] = (K7_STATE_CTL_ADDR >>  0) & 0xFF;
+               u8_buf[count++] = K7_POWER_CTL_TAP_WAKEUP;
+               lr388k7_spi_write(u8_buf, count);
 
-               lr388k7_send_signal(g_st_state.u32_pid, LR388K7_SIGNAL_CTRL);
-       }
-#endif
+               irq_value = gpio_get_value(ts->gpio_irq);
 
-       u8_buf[count++] = K7_WR_OPCODE;
-       u8_buf[count++] = (K7_STATE_CTL_ADDR >> 16) & 0xFF;
-       u8_buf[count++] = (K7_STATE_CTL_ADDR >>  8) & 0xFF;
-       u8_buf[count++] = (K7_STATE_CTL_ADDR >>  0) & 0xFF;
-       if (g_st_dbg.wakeup.enable == 1)
-               u8_buf[count++] = K7_POWER_CTL_TAP_WAKEUP;
-       else
-               u8_buf[count++] = K7_POWER_CTL_SLEEP;
-       lr388k7_spi_write(u8_buf, count);
+               if (!irq_value) {
+                       u8_status = lr388k7_clear_irq();
 
-       msleep(100);
+                       lr388k7_event_handler(u8_status);
+               }
+
+               mutex_unlock(&ts->mutex);
+               return;
+       }
+
+       if (ts->spi_intf_dis)
+               pinctrl_select_state(ts->pinctrl,
+                               ts->spi_intf_dis);
 
-#if 0
        /* Disable (3.3V) */
        if (ts->regulator_3v3) {
                error = regulator_disable(ts->regulator_3v3);
@@ -2411,7 +2904,7 @@ static void lr388k7_ctrl_suspend(struct lr388k7 *ts)
        }
        /* handle platforms w/ and w/out regulator switches */
        /* 2) delay for platforms w/ regulator switches */
-       usleep_range(15000, 20000);     /*msleep(15); */
+       /* usleep_range(15000, 20000);  */ /*msleep(15); */
        /* 3) disable clock */
        if (ts->clk)
                clk_disable(ts->clk);
@@ -2423,46 +2916,45 @@ static void lr388k7_ctrl_suspend(struct lr388k7 *ts)
                                "lr388k7 1.8V disable failed: %d\n",
                                error);
        }
-#endif
+
+       /* Reset assert */
+       gpio_set_value(ts->gpio_reset, 0);
+       g_st_state.b_is_reset = true;
 
        mutex_unlock(&ts->mutex);
 }
 
 static void lr388k7_stop(struct lr388k7 *ts)
 {
-       if (g_st_state.b_is_suspended)
-               return;
-
-       g_st_state.b_is_suspended = true;
-
        flush_workqueue(g_st_state.st_wq_k7);
 
        lr388k7_ctrl_suspend(ts);
 }
 
-#ifdef CONFIG_PM
-static int lr388k7_suspend(struct device *dev)
+static int lr388k7_suspend(struct lr388k7 *ts)
 {
-       struct lr388k7 *ts = dev_get_drvdata(dev);
+
        lr388k7_stop(ts);
 
        lr388k7_send_signal(g_st_state.u32_pid, LR388K7_SIGNAL_SLEP);
 
-       lr388k7_disable_irq(ts);
+       g_st_state.b_is_suspended = true;
 
        return 0;
 }
 
-static int lr388k7_resume(struct device *dev)
+static int lr388k7_resume(struct lr388k7 *ts)
 {
-       struct lr388k7 *ts = dev_get_drvdata(dev);
        u8 u8_status = 0;
        int irq_value;
+
        lr388k7_start(ts);
 
        lr388k7_send_signal(g_st_state.u32_pid, LR388K7_SIGNAL_WAKE);
 
-       lr388k7_enable_irq(ts);
+
+       if (g_st_dbg.wakeup.enable == 2)
+               g_st_dbg.wakeup.enable = g_u16_wakeup_enable;
 
        if (IS_DBG) {
                g_st_dbg.u8ForceCap = 0;
@@ -2472,6 +2964,9 @@ static int lr388k7_resume(struct device *dev)
                lr388k7_send_signal(g_st_state.u32_pid, LR388K7_SIGNAL_CTRL);
        }
 
+       if (g_st_dbg.wakeup.enable == 0)
+               return 0;
+
        /* check irq */
        irq_value = gpio_get_value(ts->gpio_irq);
        if (!irq_value) {
@@ -2482,7 +2977,7 @@ static int lr388k7_resume(struct device *dev)
 
                        lr388k7_event_handler(u8_status);
                        irq_value = gpio_get_value(ts->gpio_irq);
-                       /*      if(irq_value) // for high-active */
+
                        if (!irq_value)
                                u8_status = lr388k7_clear_irq();
                        else
@@ -2492,6 +2987,47 @@ static int lr388k7_resume(struct device *dev)
 
        return 0;
 }
+
+#ifdef CONFIG_PM
+static int lr388k7_dev_pm_suspend(struct device *dev)
+{
+       struct lr388k7 *ts = dev_get_drvdata(dev);
+
+       if (!g_st_state.b_is_suspended && !g_st_state.b_is_disabled) {
+               /* only called when input device is not disabled/enabled via
+                * /sys/class/input/input0/enabled interface.
+                * Android uses sysfs by default and will not run into here
+                */
+               lr388k7_suspend(ts);
+#if defined(CONFIG_ANDROID)
+               dev_info(ts->dev, "disabled without input powerhal support.\n");
+#endif
+       }
+       if (g_st_dbg.wakeup.enable == 1)
+               enable_irq_wake(ts->irq);
+
+       return 0;
+}
+
+static int lr388k7_dev_pm_resume(struct device *dev)
+{
+       struct lr388k7 *ts = dev_get_drvdata(dev);
+
+       if (!g_st_state.b_is_disabled) {
+               /* only called when input device is not disabled/enabled via
+                * /sys/class/input/input0/enabled interface.
+                * Android uses sysfs by default and will not run into here
+                */
+               lr388k7_resume(ts);
+#if defined(CONFIG_ANDROID)
+               dev_info(ts->dev, "enabled without input powerhal support.\n");
+#endif
+       }
+       if (g_st_dbg.wakeup.enable == 1)
+               disable_irq_wake(ts->irq);
+
+       return 0;
+}
 #endif /*CONFIG_PM */
 
 static int lr388k7_input_enable(struct input_dev *idev)
@@ -2502,9 +3038,8 @@ static int lr388k7_input_enable(struct input_dev *idev)
        dev_info(ts->dev, "[ENTER] input enable\n");
 #endif
 
-#ifdef CONFIG_PM
-       err = lr388k7_resume(ts->dev);
-#endif
+       g_st_state.b_is_disabled = false;
+       err = lr388k7_resume(ts);
 
 #if defined(DEBUG_LR388K7)
        dev_info(ts->dev, "[EXIT] input enable\n");
@@ -2516,13 +3051,13 @@ static int lr388k7_input_disable(struct input_dev *idev)
 {
        struct lr388k7 *ts = input_get_drvdata(idev);
        int err = 0;
+
 #if defined(DEBUG_LR388K7)
        dev_info(ts->dev, "[ENTER] input disable\n");
 #endif
 
-#ifdef CONFIG_PM
-       err = lr388k7_suspend(ts->dev);
-#endif
+       err = lr388k7_suspend(ts);
+       g_st_state.b_is_disabled = true;
 
 #if defined(DEBUG_LR388K7)
        dev_info(ts->dev, "[EXIT] input disable\n");
@@ -2530,10 +3065,10 @@ static int lr388k7_input_disable(struct input_dev *idev)
        return 0;
 }
 
-#if defined(CONFIG_PM) & !defined(INPUT_ENABLE)
+#if defined(CONFIG_PM)
 static const struct dev_pm_ops lr388k7_pm_ops = {
-       .suspend = lr388k7_suspend,
-       .resume = lr388k7_resume,
+       .suspend = lr388k7_dev_pm_suspend,
+       .resume = lr388k7_dev_pm_resume,
 };
 #endif
 
@@ -2547,7 +3082,7 @@ static struct spi_driver lr388k7_driver = {
        .driver = {
                .name   = "lr388k7_ts",
                .owner  = THIS_MODULE,
-#if defined(CONFIG_PM) & !defined(INPUT_ENABLE)
+#if defined(CONFIG_PM)
                .pm     = &lr388k7_pm_ops,
 #endif
                .of_match_table = lr388k7_ts_match,