input: touch: sharp:fix unbalanced irq disable.
[linux-3.10.git] / drivers / input / touchscreen / lr388k7_ts.c
index 730cd28..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 */
@@ -86,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 (9)
+#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)
@@ -122,6 +127,7 @@ struct lr388k7_ts_parameter {
        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;
@@ -133,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;
@@ -226,6 +236,7 @@ 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 || \
@@ -616,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;
@@ -668,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
                         */
@@ -679,6 +699,8 @@ static void lr388k7_event_handler(u8 u8Status)
                        } else {
                                lr388k7_read_spec_size();
                        }
+#endif
+
                } else {
                        lr388k7_read_spec_size();
                }
@@ -729,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);
 
        /*
@@ -754,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;
@@ -778,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");
 
@@ -793,11 +798,6 @@ 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 (g_st_state.b_is_suspended)
                g_st_state.b_is_suspended = false;
 
@@ -828,26 +828,16 @@ static irqreturn_t lr388k7_irq_thread(int irq, void *_ts)
        return IRQ_HANDLED;
 }
 
-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,
@@ -948,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,
@@ -967,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;
@@ -1009,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,
@@ -1030,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;
@@ -1041,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*/
@@ -1061,12 +1073,45 @@ 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 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,
@@ -1112,11 +1157,10 @@ static ssize_t lr388k7_ts_check_state_show(struct device *dev,
        u8_tx_buf[count++] = 0xAC;
        u8_tx_buf[count++] = 0x00;
 
-       g_st_state.u32SCK = 0;
-
        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"
@@ -1133,14 +1177,13 @@ static ssize_t lr388k7_ts_check_state_show(struct device *dev,
        u8_tx_buf[count++] = 0x00;
        u8_tx_buf[count++] = 0x00;
 
-       g_st_state.u32SCK = 0;
-
        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"
@@ -1157,14 +1200,13 @@ static ssize_t lr388k7_ts_check_state_show(struct device *dev,
        u8_tx_buf[count++] = 0x00;
        u8_tx_buf[count++] = 0x00;
 
-       g_st_state.u32SCK = 0;
-
        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"
@@ -1186,7 +1228,104 @@ static ssize_t lr388k7_ts_check_state_show(struct device *dev,
 }
 #endif
 
-static DEVICE_ATTR(force_cap, 0666, lr388k7_ts_force_cap_show,
+#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);
@@ -1201,12 +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, 0666,
+static DEVICE_ATTR(check_state, 0660,
                   lr388k7_ts_check_state_show,
                   lr388k7_ts_check_state_store);
-#endif
 
+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,
@@ -1215,8 +1360,10 @@ 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
 };
@@ -1246,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);
@@ -1253,6 +1402,7 @@ static void lr388k7_close(struct input_dev *input)
        ts->opened = false;
 
        mutex_unlock(&ts->mutex);
+       dev_info(&ts->spi->dev, "[EXIT] close\n");
 }
 
 
@@ -1397,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;
@@ -1452,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++;
        }
@@ -1542,27 +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
 
+       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;
 }
@@ -1586,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);
@@ -1802,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);
 
@@ -1881,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;
 
@@ -1984,12 +2216,14 @@ static long dev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 
 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();
 
@@ -1999,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)
@@ -2110,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;*/
@@ -2231,6 +2506,8 @@ static int lr388k7_probe(struct spi_device *spi)
        gpio_set_value(ts->gpio_reset, 0);
        g_st_state.b_is_reset = true;
 
+       init_spi_pinctrl(ts, dev);
+
        /* regulator */
        ts->regulator_3v3 = devm_regulator_get(&g_spi->dev, "avdd");
        if (IS_ERR(ts->regulator_3v3)) {
@@ -2404,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);
 
@@ -2462,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:
@@ -2566,6 +2841,10 @@ static void lr388k7_start(struct lr388k7 *ts)
 
        usleep_range(5000, 6000);
 
+       if (ts->spi_intf_en)
+               pinctrl_select_state(ts->pinctrl,
+                       ts->spi_intf_en);
+
        /*
         * Enable clock, if necessary
         */
@@ -2611,6 +2890,9 @@ static void lr388k7_ctrl_suspend(struct lr388k7 *ts)
                return;
        }
 
+       if (ts->spi_intf_dis)
+               pinctrl_select_state(ts->pinctrl,
+                               ts->spi_intf_dis);
 
        /* Disable (3.3V) */
        if (ts->regulator_3v3) {
@@ -2635,6 +2917,10 @@ static void lr388k7_ctrl_suspend(struct lr388k7 *ts)
                                error);
        }
 
+       /* Reset assert */
+       gpio_set_value(ts->gpio_reset, 0);
+       g_st_state.b_is_reset = true;
+
        mutex_unlock(&ts->mutex);
 }
 
@@ -2645,15 +2931,8 @@ static void lr388k7_stop(struct lr388k7 *ts)
        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);
-
-       if (g_st_state.b_is_suspended)
-               return 0;
-
-       lr388k7_disable_irq(ts);
 
        lr388k7_stop(ts);
 
@@ -2664,16 +2943,18 @@ static int lr388k7_suspend(struct device *dev)
        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;
@@ -2706,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)
@@ -2716,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");
@@ -2730,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");
@@ -2744,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
 
@@ -2761,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,