(CR):[kane]:kernel: add egis fps drivers
authorhq_guohongtao5_tmp <guohongtao5@huaqin.com>
Thu, 30 Aug 2018 03:35:55 +0000 (11:35 +0800)
committerxiest1 <xiest1@lenovo.com>
Tue, 5 Nov 2019 09:29:40 +0000 (17:29 +0800)
add egis fps drivers

Change-Id: I736e84fe6f565d9fb17a40bb541dd2394ca5b100
Signed-off-by: hq_guohongtao5_tmp <guohongtao5@huaqin.com>
arch/arm64/boot/dts/exynos/exynos9609-wing.dts
arch/arm64/configs/wing_defconfig
drivers/input/Kconfig
drivers/input/Makefile [changed mode: 0644->0755]
drivers/input/egistec/Kconfig [new file with mode: 0755]
drivers/input/egistec/Makefile [new file with mode: 0755]
drivers/input/egistec/et320-int.c [new file with mode: 0755]
drivers/input/egistec/et320.h [new file with mode: 0755]
drivers/input/egistec/navi_input.c [new file with mode: 0755]
drivers/input/egistec/navi_input.h [new file with mode: 0755]

index a6a6d15ce01c17a80d16cf65427f8b4125da83bb..89e707fdba5ab970e6ba517f1f573841709b1f9d 100755 (executable)
                                ifconn,muic = "s2mu106-muic";
                        };
 
+                       /*Fingerprint start*/
+                       et320: et320{
+                               compatible = "egistec,et320";
+                               status = "ok";
+                               reg = <0>;
+                               clocks = <&clock GATE_SPI_1_QCH>, <&clock SPI1>;
+                               clock-names = "spi", "spi_busclk0";
+                               pinctrl-names = "default";
+                               pinctrl-0 = <&spi7_bus &spi7_cs_func>;
+                               egistec,gpio_irq    = <&gpa0 5 0>;
+                               egistec,gpio_rst    = <&gpa1 1 0>;
+                       };
+                       /*Fingerprint end*/
+
                        speedy@11a10000 {
                                status = "okay";
                                #address-cells = <1>;
                                                };
 
                                                l37_reg: LDO37 {
-                                                       regulator-name = "vdd_ldo37";
-                                                       regulator-min-microvolt = <1800000>;
-                                                       regulator-max-microvolt = <3375000>;
-                                                       regulator-ramp-delay = <12000>;
+                                                       regulator-name = "vdd_ldo37";
+                                                       regulator-min-microvolt = <3300000>;
+                                                       regulator-max-microvolt = <3300000>;
+                                                       regulator-ramp-delay = <12000>;
+                                                       regulator-always-on;
                                                };
 
                                                l38_reg: LDO38 {
index 5a82cde01194788177189d6d356a894b538c3dd3..f251289f1a9b6546d6d6a5932e39c74dd77c57ed 100755 (executable)
@@ -537,3 +537,4 @@ CONFIG_SEC_NFC_IF_I2C=y
 CONFIG_SEC_NFC_LDO_EN=y
 CONFIG_SEC_NFC_CLK_REQ=y
 CONFIG_SENSORS_CLASS=y
+CONFIG_INPUT_EGISTEC_320=y
index 724715e4f8bc58113bec5b106c6959c177018332..9f52cf952dac7daeaffe6916bd885ae28361b14f 100644 (file)
@@ -213,6 +213,8 @@ source "drivers/input/misc/Kconfig"
 
 source "drivers/input/rmi4/Kconfig"
 
+source "drivers/input/egistec/Kconfig"
+
 endif
 
 menu "Hardware I/O ports"
old mode 100644 (file)
new mode 100755 (executable)
index f0351af..264f246
@@ -31,3 +31,4 @@ obj-$(CONFIG_INPUT_KEYRESET)  += keyreset.o
 obj-$(CONFIG_INPUT_KEYCOMBO)   += keycombo.o
 
 obj-$(CONFIG_RMI4_CORE)                += rmi4/
+obj-$(CONFIG_INPUT_EGISTEC_320)        += egistec/
diff --git a/drivers/input/egistec/Kconfig b/drivers/input/egistec/Kconfig
new file mode 100755 (executable)
index 0000000..4111f65
--- /dev/null
@@ -0,0 +1,12 @@
+#
+# Input misc drivers configuration
+#
+
+
+config INPUT_EGISTEC_320
+       tristate "Egistec ET320 fingerprint sensor"
+       default n
+       help
+        Say Y here if you wish to include support for EGIS finger print sensor.
+        If unsure, say N.
+
diff --git a/drivers/input/egistec/Makefile b/drivers/input/egistec/Makefile
new file mode 100755 (executable)
index 0000000..b9c0fd2
--- /dev/null
@@ -0,0 +1,10 @@
+
+# Makefile for the input misc drivers.
+#
+
+# Each configuration option enables a list of files.
+
+
+obj-$(CONFIG_INPUT_EGISTEC_320) += et320-int.o\r
+# navi_input.o
+
diff --git a/drivers/input/egistec/et320-int.c b/drivers/input/egistec/et320-int.c
new file mode 100755 (executable)
index 0000000..0c5e6d9
--- /dev/null
@@ -0,0 +1,1102 @@
+/*\r
+ * Simple synchronous userspace interface to SPI devices\r
+ *\r
+ * Copyright (C) 2006 SWAPP\r
+ *     Andrea Paterniani <a.paterniani@swapp-eng.it>\r
+ * Copyright (C) 2007 David Brownell (simplification, cleanup)\r
+ *\r
+ * This program is free software; you can redistribute it and/or\r
+ * modify it under the terms of the GNU General Public License Version 2\r
+ * as published by the Free Software Foundation.\r
+ */\r
+\r
+/*\r
+*\r
+*  et320.spi.c\r
+*  Date: 2016/03/16\r
+*  Version: 0.9.0.1\r
+*  Revise Date:  2016/10/20\r
+*  Copyright (C) 2007-2016 Egis Technology Inc.\r
+*\r
+*/\r
+\r
+\r
+#include <linux/interrupt.h>\r
+#ifdef CONFIG_OF\r
+#include <linux/of.h>\r
+#include <linux/of_address.h>\r
+#include <linux/of_irq.h>\r
+#endif\r
+\r
+#include <linux/gpio.h>\r
+#include <linux/mutex.h>\r
+#include <linux/list.h>\r
+\r
+#include <linux/clk.h>\r
+#include <linux/delay.h>\r
+#include <linux/gpio.h>\r
+#include <linux/interrupt.h>\r
+#include <linux/kernel.h>\r
+#include <linux/module.h>\r
+#include <linux/mutex.h>\r
+#include <linux/of.h>\r
+#include <linux/of_gpio.h>\r
+#include <linux/regulator/consumer.h>\r
+#include <linux/spi/spi.h>\r
+//#include <soc/qcom/scm.h>\r
+#include <linux/wakelock.h>\r
+#include <linux/clk.h>\r
+#include "et320.h"\r
+#include "navi_input.h"\r
+\r
+#define EDGE_TRIGGER_FALLING    0x0\r
+#define        EDGE_TRIGGER_RAISING    0x1\r
+#define        LEVEL_TRIGGER_LOW       0x2\r
+#define        LEVEL_TRIGGER_HIGH      0x3\r
+#define EGIS_NAVI_INPUT 0  /* 1:open ; 0:close */\r
+struct wake_lock et320_wake_lock;\r
+\r
+/*\r
+ * FPS interrupt table\r
+ */\r
+\r
+struct interrupt_desc fps_ints = {0 , 0, "BUT0" , 0};\r
+\r
+unsigned int bufsiz = 4096;\r
+\r
+int gpio_irq;\r
+int request_irq_done = 0;\r
+/* int t_mode = 255; */\r
+\r
+#define EDGE_TRIGGER_FALLING    0x0\r
+#define EDGE_TRIGGER_RISING    0x1\r
+#define LEVEL_TRIGGER_LOW       0x2\r
+#define LEVEL_TRIGGER_HIGH      0x3\r
+\r
+\r
+struct ioctl_cmd {\r
+int int_mode;\r
+int detect_period;\r
+int detect_threshold;\r
+};\r
+/* To be compatible with fpc driver */\r
+#ifndef CONFIG_SENSORS_FPC_1020\r
+static struct FPS_data {\r
+       unsigned int enabled;\r
+       unsigned int state;\r
+       struct blocking_notifier_head nhead;\r
+} *fpsData;\r
+\r
+struct FPS_data *FPS_init(void)\r
+{\r
+       struct FPS_data *mdata;\r
+       if (!fpsData) {\r
+               mdata = kzalloc(\r
+                               sizeof(struct FPS_data), GFP_KERNEL);\r
+               if (mdata) {\r
+                       BLOCKING_INIT_NOTIFIER_HEAD(&mdata->nhead);\r
+                       pr_debug("%s: FPS notifier data structure init-ed\n", __func__);\r
+               }\r
+               fpsData = mdata;\r
+       }\r
+       return fpsData;\r
+}\r
+int FPS_register_notifier(struct notifier_block *nb,\r
+       unsigned long stype, bool report)\r
+{\r
+       int error;\r
+       struct FPS_data *mdata = fpsData;\r
+\r
+       mdata = FPS_init();\r
+       if (!mdata)\r
+               return -ENODEV;\r
+       mdata->enabled = (unsigned int)stype;\r
+       pr_debug("%s: FPS sensor %lu notifier enabled\n", __func__, stype);\r
+\r
+       error = blocking_notifier_chain_register(&mdata->nhead, nb);\r
+       if (!error && report) {\r
+               int state = mdata->state;\r
+               /* send current FPS state on register request */\r
+               blocking_notifier_call_chain(&mdata->nhead,\r
+                               stype, (void *)&state);\r
+               pr_debug("%s: FPS reported state %d\n", __func__, state);\r
+       }\r
+       return error;\r
+}\r
+EXPORT_SYMBOL_GPL(FPS_register_notifier);\r
+\r
+int FPS_unregister_notifier(struct notifier_block *nb,\r
+               unsigned long stype)\r
+{\r
+       int error;\r
+       struct FPS_data *mdata = fpsData;\r
+\r
+       if (!mdata)\r
+               return -ENODEV;\r
+\r
+       error = blocking_notifier_chain_unregister(&mdata->nhead, nb);\r
+       pr_debug("%s: FPS sensor %lu notifier unregister\n", __func__, stype);\r
+\r
+       if (!mdata->nhead.head) {\r
+               mdata->enabled = 0;\r
+               pr_debug("%s: FPS sensor %lu no clients\n", __func__, stype);\r
+       }\r
+\r
+       return error;\r
+}\r
+EXPORT_SYMBOL_GPL(FPS_unregister_notifier);\r
+\r
+void FPS_notify(unsigned long stype, int state)\r
+{\r
+       struct FPS_data *mdata = fpsData;\r
+\r
+       pr_debug("%s: Enter", __func__);\r
+\r
+       if (!mdata) {\r
+               pr_err("%s: FPS notifier not initialized yet\n", __func__);\r
+               return;\r
+       }\r
+\r
+       pr_debug("%s: FPS current state %d -> (0x%x)\n", __func__,\r
+               mdata->state, state);\r
+\r
+       if (mdata->enabled && mdata->state != state) {\r
+               mdata->state = state;\r
+               blocking_notifier_call_chain(&mdata->nhead,\r
+                                               stype, (void *)&state);\r
+               pr_debug("%s: FPS notification sent\n", __func__);\r
+       } else if (!mdata->enabled) {\r
+               pr_err("%s: !mdata->enabled", __func__);\r
+       } else {\r
+               pr_err("%s: mdata->state==state", __func__);\r
+       }\r
+}\r
+#endif\r
+\r
+static struct etspi_data *g_data;\r
+\r
+DECLARE_BITMAP(minors, N_SPI_MINORS);\r
+LIST_HEAD(device_list);\r
+static DEFINE_MUTEX(device_list_lock);\r
+\r
+/* ------------------------------ Interrupt -----------------------------*/\r
+/*\r
+ * Interrupt description\r
+ */\r
+\r
+#define FP_INT_DETECTION_PERIOD  10\r
+#define FP_DETECTION_THRESHOLD 10\r
+/* struct interrupt_desc fps_ints; */\r
+static DECLARE_WAIT_QUEUE_HEAD(interrupt_waitq);\r
+/*\r
+ *     FUNCTION NAME.\r
+ *             interrupt_timer_routine\r
+ *\r
+ *     FUNCTIONAL DESCRIPTION.\r
+ *             basic interrupt timer inital routine\r
+ *\r
+ *     ENTRY PARAMETERS.\r
+ *             gpio - gpio address\r
+ *\r
+ *     EXIT PARAMETERS.\r
+ *             Function Return\r
+ */\r
+\r
+void interrupt_timer_routine(unsigned long _data)\r
+{\r
+       struct interrupt_desc *bdata = (struct interrupt_desc *)_data;\r
+\r
+       DEBUG_PRINT("FPS interrupt count = %d", bdata->int_count);\r
+       if (bdata->int_count >= bdata->detect_threshold) {\r
+               bdata->finger_on = 1;\r
+               DEBUG_PRINT("FPS triggered !!!!!!!\n");\r
+       } else {\r
+               DEBUG_PRINT("FPS not triggered !!!!!!!\n");\r
+       }\r
+\r
+       bdata->int_count = 0;\r
+       wake_up_interruptible(&interrupt_waitq);\r
+}\r
+\r
+static irqreturn_t fp_eint_func(int irq, void *dev_id)\r
+{\r
+       if (!fps_ints.int_count)\r
+               mod_timer(&fps_ints.timer, jiffies + msecs_to_jiffies(fps_ints.detect_period));\r
+       fps_ints.int_count++;\r
+       /* printk_ratelimited(KERN_WARNING "-----------   zq fp fp_eint_func  ,fps_ints.int_count=%d",fps_ints.int_count);*/\r
+       wake_lock_timeout(&et320_wake_lock, msecs_to_jiffies(1500));\r
+       return IRQ_HANDLED;\r
+}\r
+\r
+static irqreturn_t fp_eint_func_ll(int irq , void *dev_id)\r
+{\r
+       pr_debug("etspi: fp_eint_func_ll\n");\r
+       fps_ints.finger_on = 1;\r
+       /* fps_ints.int_count = 0; */\r
+       disable_irq_nosync(gpio_irq);\r
+       fps_ints.drdy_irq_flag = DRDY_IRQ_DISABLE;\r
+       wake_up_interruptible(&interrupt_waitq);\r
+       /* printk_ratelimited(KERN_WARNING "-----------   zq fp fp_eint_func  ,fps_ints.int_count=%d",fps_ints.int_count);*/\r
+       wake_lock_timeout(&et320_wake_lock, msecs_to_jiffies(1500));\r
+       return IRQ_RETVAL(IRQ_HANDLED);\r
+}\r
+\r
+/*\r
+ *     FUNCTION NAME.\r
+ *             Interrupt_Init\r
+ *\r
+ *     FUNCTIONAL DESCRIPTION.\r
+ *             button initial routine\r
+ *\r
+ *     ENTRY PARAMETERS.\r
+ *             int_mode - determine trigger mode\r
+ *                     EDGE_TRIGGER_FALLING    0x0\r
+ *                     EDGE_TRIGGER_RAISING    0x1\r
+ *                     LEVEL_TRIGGER_LOW        0x2\r
+ *                     LEVEL_TRIGGER_HIGH       0x3\r
+ *\r
+ *     EXIT PARAMETERS.\r
+ *             Function Return int\r
+ */\r
+\r
+int Interrupt_Init(struct etspi_data *etspi, int int_mode, int detect_period, int detect_threshold)\r
+{\r
+\r
+       int err = 0;\r
+       int status = 0;\r
+       static unsigned long jt;\r
+\r
+       pr_debug("etspi: --  %s mode = %d period = %d threshold = %d\n",\\r
+               __func__, int_mode, detect_period, detect_threshold);\r
+       DEBUG_PRINT("etspi: --  %s request_irq_done = %d gpio_irq = %d  pin = %d\n",\\r
+               __func__, request_irq_done, gpio_irq, etspi->irqPin);\r
+\r
+\r
+       fps_ints.detect_period = detect_period;\r
+       fps_ints.detect_threshold = detect_threshold;\r
+       fps_ints.int_count = 0;\r
+       fps_ints.finger_on = 0;\r
+\r
+\r
+       if (request_irq_done == 0)      {\r
+               gpio_irq = gpio_to_irq(etspi->irqPin);\r
+               if (gpio_irq < 0) {\r
+                       DEBUG_PRINT("etspi: %s gpio_to_irq failed\n", __func__);\r
+                       status = gpio_irq;\r
+                       goto done;\r
+               }\r
+\r
+               DEBUG_PRINT("etspi:Interrupt_Init flag current: %d disable:\\r
+                       %d enable: %d\n",\r
+               fps_ints.drdy_irq_flag, DRDY_IRQ_DISABLE, DRDY_IRQ_ENABLE);\r
+               /* t_mode = int_mode; */\r
+               if (int_mode == EDGE_TRIGGER_RISING) {\r
+                       DEBUG_PRINT("etspi:%s EDGE_TRIGGER_RISING\n", __func__);\r
+                       err = request_irq(gpio_irq, fp_eint_func, IRQ_TYPE_EDGE_RISING,\\r
+                               "fp_detect-eint", etspi);\r
+                       if (err) {\r
+                               pr_err("etspi:request_irq failed==========%s,%d\n", __func__, __LINE__);\r
+                       }\r
+               } else if (int_mode == EDGE_TRIGGER_FALLING) {\r
+                       DEBUG_PRINT("etspi:%s EDGE_TRIGGER_FALLING\n", __func__);\r
+                       err = request_irq(gpio_irq, fp_eint_func, IRQ_TYPE_EDGE_FALLING,\\r
+                               "fp_detect-eint", etspi);\r
+                       if (err) {\r
+                               pr_err("etspi:request_irq failed==========%s,%d\n",\\r
+                                       __func__, __LINE__);\r
+                       }\r
+               } else if (int_mode == LEVEL_TRIGGER_LOW) {\r
+                       DEBUG_PRINT("etspi:%s LEVEL_TRIGGER_LOW\n", __func__);\r
+                       err = request_irq(gpio_irq, fp_eint_func_ll, IRQ_TYPE_LEVEL_LOW,\\r
+                               "fp_detect-eint", etspi);\r
+                       if (err) {\r
+                               pr_err("etspi:request_irq failed==========%s,%d\n", __func__, __LINE__);\r
+                       }\r
+               } else if (int_mode == LEVEL_TRIGGER_HIGH) {\r
+                       DEBUG_PRINT("etspi:%s LEVEL_TRIGGER_HIGH\n", __func__);\r
+                       err = request_irq(gpio_irq, fp_eint_func_ll, IRQ_TYPE_LEVEL_HIGH,\\r
+                               "fp_detect-eint", etspi);\r
+                       if (err) {\r
+                               pr_err("etspi:request_irq failed==========%s,%d\n", __func__, __LINE__);\r
+                       }\r
+               }\r
+               DEBUG_PRINT("etspi:Interrupt_Init:gpio_to_irq return: %d\n", gpio_irq);\r
+               DEBUG_PRINT("etspi:Interrupt_Init:request_irq return: %d\n", err);\r
+               /* disable_irq_nosync(gpio_irq); */\r
+               fps_ints.drdy_irq_flag = DRDY_IRQ_ENABLE;\r
+               enable_irq_wake(gpio_irq);\r
+               request_irq_done = 1;\r
+       }\r
+\r
+\r
+       if (fps_ints.drdy_irq_flag == DRDY_IRQ_DISABLE) {\r
+               fps_ints.drdy_irq_flag = DRDY_IRQ_ENABLE;\r
+               enable_irq_wake(gpio_irq);\r
+               enable_irq(gpio_irq);\r
+               if (printk_timed_ratelimit(&jt, 500))\r
+                       DEBUG_PRINT("etspi: Interrupt_Init: %s irq/done:%d %d mode:%d\\r
+                       period:%d \threshold:%d \n", __func__, gpio_irq, request_irq_done,\\r
+                       int_mode, detect_period, detect_threshold);\r
+       }\r
+done:\r
+       return 0;\r
+}\r
+\r
+/*\r
+ *     FUNCTION NAME.\r
+ *             Interrupt_Free\r
+ *\r
+ *     FUNCTIONAL DESCRIPTION.\r
+ *             free all interrupt resource\r
+ *\r
+ *     EXIT PARAMETERS.\r
+ *             Function Return int\r
+ */\r
+\r
+int Interrupt_Free(struct etspi_data *etspi)\r
+{\r
+       pr_debug("etspi: %s\n", __func__);\r
+       fps_ints.finger_on = 0;\r
+\r
+       if (fps_ints.drdy_irq_flag == DRDY_IRQ_ENABLE) {\r
+               DEBUG_PRINT("etspi: %s (DISABLE IRQ)\n", __func__);\r
+               disable_irq_nosync(gpio_irq);\r
+               /* disable_irq(gpio_irq); */\r
+               del_timer_sync(&fps_ints.timer);\r
+               fps_ints.drdy_irq_flag = DRDY_IRQ_DISABLE;\r
+       }\r
+       return 0;\r
+}\r
+\r
+\r
+\r
+\r
+/*\r
+ *     FUNCTION NAME.\r
+ *             fps_interrupt_re d\r
+ *\r
+ *     FUNCTIONAL DESCRIPTION.\r
+ *             FPS interrupt read status\r
+ *\r
+ *     ENTRY PARAMETERS.\r
+ *             wait poll table structure\r
+ *\r
+ *     EXIT PARAMETERS.\r
+ *             Function Return int\r
+ */\r
+\r
+unsigned int fps_interrupt_poll(\r
+struct file *file,\r
+struct poll_table_struct *wait)\r
+{\r
+       unsigned int mask = 0;\r
+\r
+       /* DEBUG_PRINT("%s %d\n", __func__, fps_ints.finger_on);*/\r
+       /* fps_ints.int_count = 0; */\r
+       poll_wait(file, &interrupt_waitq, wait);\r
+       if (fps_ints.finger_on) {\r
+               mask |= POLLIN | POLLRDNORM;\r
+               /* fps_ints.finger_on = 0; */\r
+       }\r
+       return mask;\r
+}\r
+\r
+void fps_interrupt_abort(void)\r
+{\r
+       DEBUG_PRINT("etspi:%s\n", __func__);\r
+       fps_ints.finger_on = 0;\r
+       wake_up_interruptible(&interrupt_waitq);\r
+}\r
+\r
+/*-------------------------------------------------------------------------*/\r
+\r
+static void etspi_reset(struct etspi_data *etspi)\r
+{\r
+       DEBUG_PRINT("etspi:%s\n", __func__);\r
+       gpio_set_value(etspi->rstPin, 0);\r
+       msleep(30);\r
+       gpio_set_value(etspi->rstPin, 1);\r
+       msleep(20);\r
+}\r
+\r
+static ssize_t etspi_read(struct file *filp,\r
+       char __user *buf,\r
+       size_t count,\r
+       loff_t *f_pos)\r
+{\r
+       /*Implement by vendor if needed*/\r
+       return 0;\r
+}\r
+\r
+static ssize_t etspi_write(struct file *filp,\r
+       const char __user *buf,\r
+       size_t count,\r
+       loff_t *f_pos)\r
+{\r
+       /*Implement by vendor if needed*/\r
+       return 0;\r
+}\r
+static ssize_t etspi_enable_set(struct device *dev,\r
+               struct device_attribute *attr, const char *buf, size_t count)\r
+{\r
+       int state = (*buf == '1') ? 1 : 0;\r
+       FPS_notify(0xbeef, state);\r
+       DEBUG_PRINT("%s  state = %d\n", __func__, state);\r
+       return 1;\r
+}\r
+static DEVICE_ATTR(etspi_enable, S_IWUSR | S_IWGRP, NULL, etspi_enable_set);\r
+static struct attribute *attributes[] = {\r
+       &dev_attr_etspi_enable.attr,\r
+       NULL\r
+};\r
+\r
+static const struct attribute_group attribute_group = {\r
+       .attrs = attributes,\r
+};\r
+static long etspi_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)\r
+{\r
+\r
+       int retval = 0;\r
+       struct etspi_data *etspi;\r
+       struct ioctl_cmd data;\r
+\r
+       memset(&data, 0, sizeof(data));\r
+\r
+       pr_debug("etspi: %s\n", __func__);\r
+\r
+       etspi = filp->private_data;\r
+\r
+       switch (cmd) {\r
+       case INT_TRIGGER_INIT:\r
+               if (copy_from_user(&data, (int __user *)arg, sizeof(data))) {\r
+                       retval = -EFAULT;\r
+                       goto done;\r
+               }\r
+               pr_debug("etspi:fp_ioctl >>> fp Trigger function init\n");\r
+               retval = Interrupt_Init(etspi, data.int_mode, data.detect_period, data.detect_threshold);\r
+               pr_debug("etspi:fp_ioctl trigger init = %x\n", retval);\r
+       break;\r
+\r
+       case FP_SENSOR_RESET:\r
+               DEBUG_PRINT("etspi:fp_ioctl ioc->opcode == FP_SENSOR_RESET --");\r
+               etspi_reset(etspi);\r
+               goto done;\r
+       case INT_TRIGGER_CLOSE:\r
+               pr_debug("etspi:fp_ioctl <<< fp Trigger function close\n");\r
+               retval = Interrupt_Free(etspi);\r
+               pr_debug("etspi:fp_ioctl trigger close = %x\n", retval);\r
+               goto done;\r
+       case INT_TRIGGER_ABORT:\r
+               DEBUG_PRINT("etspi:fp_ioctl <<< fp Trigger function abort\n");\r
+               fps_interrupt_abort();\r
+               goto done;\r
+       default:\r
+       retval = -ENOTTY;\r
+       break;\r
+       }\r
+done:\r
+       return retval;\r
+}\r
+\r
+#ifdef CONFIG_COMPAT\r
+static long etspi_compat_ioctl(struct file *filp,\r
+       unsigned int cmd,\r
+       unsigned long arg)\r
+{\r
+       return etspi_ioctl(filp, cmd, (unsigned long)compat_ptr(arg));\r
+}\r
+#else\r
+#define etspi_compat_ioctl NULL\r
+#endif /* CONFIG_COMPAT */\r
+\r
+static int etspi_open(struct inode *inode, struct file *filp)\r
+{\r
+       struct etspi_data *etspi;\r
+       int                     status = -ENXIO;\r
+\r
+       DEBUG_PRINT("%s\n", __func__);\r
+\r
+       mutex_lock(&device_list_lock);\r
+\r
+       list_for_each_entry(etspi, &device_list, device_entry)  {\r
+               if (etspi->devt == inode->i_rdev) {\r
+                       status = 0;\r
+                       break;\r
+               }\r
+       }\r
+       if (status == 0) {\r
+               if (etspi->buffer == NULL) {\r
+                       etspi->buffer = kmalloc(bufsiz, GFP_KERNEL);\r
+                       if (etspi->buffer == NULL) {\r
+                               /* dev_dbg(&etspi->spi->dev, "open/ENOMEM\n"); */\r
+                               status = -ENOMEM;\r
+                       }\r
+               }\r
+               if (status == 0) {\r
+                       etspi->users++;\r
+                       filp->private_data = etspi;\r
+                       nonseekable_open(inode, filp);\r
+               }\r
+       } else {\r
+               pr_info("%s nothing for minor %d\n"\r
+                       , __func__, iminor(inode));\r
+       }\r
+       mutex_unlock(&device_list_lock);\r
+       return status;\r
+}\r
+\r
+static int etspi_release(struct inode *inode, struct file *filp)\r
+{\r
+       struct etspi_data *etspi;\r
+\r
+       DEBUG_PRINT("%s\n", __func__);\r
+\r
+       mutex_lock(&device_list_lock);\r
+       etspi = filp->private_data;\r
+       filp->private_data = NULL;\r
+\r
+       /* last close? */\r
+       etspi->users--;\r
+       if (etspi->users == 0) {\r
+               int     dofree;\r
+\r
+               kfree(etspi->buffer);\r
+               etspi->buffer = NULL;\r
+\r
+               /* ... after we unbound from the underlying device? */\r
+               spin_lock_irq(&etspi->spi_lock);\r
+               dofree = (etspi->spi == NULL);\r
+               spin_unlock_irq(&etspi->spi_lock);\r
+\r
+               if (dofree)\r
+                       kfree(etspi);\r
+       }\r
+       mutex_unlock(&device_list_lock);\r
+       return 0;\r
+\r
+}\r
+\r
+\r
+\r
+int etspi_platformInit(struct etspi_data *etspi)\r
+{\r
+       int status = 0;\r
+       DEBUG_PRINT("%s\n", __func__);\r
+\r
+       if (etspi != NULL) {\r
+               /* initial 18V power pin */\r
+#if 0          \r
+               status = gpio_request(etspi->vdd_18v_Pin, "18v-gpio");\r
+               if (status < 0) {\r
+                       pr_err("%s gpio_requset vdd_18v_Pin failed\n",\r
+                               __func__);\r
+                       goto etspi_platformInit_rst_failed;\r
+               }\r
+               gpio_direction_output(etspi->vdd_18v_Pin, 1);\r
+               if (status < 0) {\r
+                       pr_err("%s gpio_direction_output vdd_18v_Pin failed\n",\r
+                                       __func__);\r
+                       status = -EBUSY;\r
+                       goto etspi_platformInit_rst_failed;\r
+               }\r
+\r
+               gpio_set_value(etspi->vdd_18v_Pin, 1);\r
+               pr_err("etspi:  vdd_18v_Pin set to high\n");\r
+               mdelay(1);\r
+               /* initial 33V power pin */\r
+               status = gpio_request(etspi->vcc_33v_Pin, "33v-gpio");\r
+               if (status < 0) {\r
+                       pr_err("%s gpio_requset vcc_33v_Pin failed\n",\r
+                               __func__);\r
+                       goto etspi_platformInit_rst_failed;\r
+               }\r
+               gpio_direction_output(etspi->vcc_33v_Pin, 1);\r
+               if (status < 0) {\r
+                       pr_err("%s gpio_direction_output vcc_33v_Pin failed\n",\r
+                                       __func__);\r
+                       status = -EBUSY;\r
+                       goto etspi_platformInit_rst_failed;\r
+               }\r
+               gpio_set_value(etspi->vcc_33v_Pin, 1);\r
+               pr_err("etspi:  vcc_33v_Pin set to high\n");\r
+               mdelay(2);\r
+#endif\r
+               \r
+               /* Initial Reset Pin*/\r
+               status = gpio_request(etspi->rstPin, "ets_reset-gpio");\r
+               if (status < 0) {\r
+                       pr_err("%s gpio_requset etspi_Reset failed\n",\r
+                               __func__);\r
+                       goto etspi_platformInit_rst_failed;\r
+               }\r
+               gpio_direction_output(etspi->rstPin, 1);\r
+               if (status < 0) {\r
+                       pr_err("%s gpio_direction_output Reset failed\n",\r
+                                       __func__);\r
+                       status = -EBUSY;\r
+                       goto etspi_platformInit_rst_failed;\r
+               }\r
+               gpio_set_value(etspi->rstPin, 1);\r
+               pr_err("etspi:  reset to high\n");\r
+\r
+               /* Initial IRQ Pin*/\r
+               status = gpio_request(etspi->irqPin, "ets_irq-gpio");\r
+               if (status < 0) {\r
+                       pr_err("%s gpio_request etspi_irq failed\n",\r
+                               __func__);\r
+                       goto etspi_platformInit_irq_failed;\r
+               }\r
+               status = gpio_direction_input(etspi->irqPin);\r
+               if (status < 0) {\r
+                       pr_err("%s gpio_direction_input IRQ failed\n",\r
+                               __func__);\r
+                       goto etspi_platformInit_gpio_init_failed;\r
+               }\r
+\r
+       }\r
+       DEBUG_PRINT("ets320: %s successful status=%d\n", __func__, status);\r
+       return status;\r
+\r
+etspi_platformInit_gpio_init_failed:\r
+       gpio_free(etspi->irqPin);\r
+//     gpio_free(etspi->vcc_33v_Pin);\r
+//     gpio_free(etspi->vdd_18v_Pin);\r
+etspi_platformInit_irq_failed:\r
+       gpio_free(etspi->rstPin);\r
+etspi_platformInit_rst_failed:\r
+\r
+       pr_err("%s is failed\n", __func__);\r
+       return status;\r
+}\r
+\r
+static int etspi_parse_dt(struct device *dev,\r
+       struct etspi_data *data)\r
+{\r
+       struct device_node *np = dev->of_node;\r
+       int errorno = 0;\r
+       int gpio;\r
+\r
+       gpio = of_get_named_gpio(np, "egistec,gpio_rst", 0);\r
+       if (gpio < 0) {\r
+               errorno = gpio;\r
+               goto dt_exit;\r
+       } else {\r
+               data->rstPin = gpio;\r
+               DEBUG_PRINT("%s: sleepPin=%d\n", __func__, data->rstPin);\r
+       }\r
+       gpio = of_get_named_gpio(np, "egistec,gpio_irq", 0);\r
+       if (gpio < 0) {\r
+               errorno = gpio;\r
+               goto dt_exit;\r
+       } else {\r
+               data->irqPin = gpio;\r
+               DEBUG_PRINT("%s: drdyPin=%d\n", __func__, data->irqPin);\r
+       }\r
+/*\r
+       gpio = of_get_named_gpio(np, "egistec,gpio_ldo3p3_en", 0);\r
+       if (gpio < 0) {\r
+               errorno = gpio;\r
+               goto dt_exit;\r
+       } else {\r
+               data->vcc_33v_Pin = gpio;\r
+               pr_info("%s: 3.3v power pin=%d\n", __func__, data->vcc_33v_Pin);\r
+       }\r
+       gpio = of_get_named_gpio(np, "egistec,gpio_ldo1p8_en", 0);\r
+       if (gpio < 0) {\r
+               errorno = gpio;\r
+               goto dt_exit;\r
+       } else {\r
+               data->vdd_18v_Pin = gpio;\r
+               pr_info("%s: 18v power pin=%d\n", __func__, data->vdd_18v_Pin);\r
+       }\r
+*/     \r
+       DEBUG_PRINT("%s is successful\n", __func__);\r
+       return errorno;\r
+dt_exit:\r
+       pr_err("%s is failed\n", __func__);\r
+       return errorno;\r
+}\r
+\r
+static const struct file_operations etspi_fops = {\r
+       .owner = THIS_MODULE,\r
+       .write = etspi_write,\r
+       .read = etspi_read,\r
+       .unlocked_ioctl = etspi_ioctl,\r
+       .compat_ioctl = etspi_compat_ioctl,\r
+       .open = etspi_open,\r
+       .release = etspi_release,\r
+       .llseek = no_llseek,\r
+       .poll = fps_interrupt_poll\r
+};\r
+\r
+/*-------------------------------------------------------------------------*/\r
+\r
+static struct class *etspi_class;\r
+\r
+static int etspi_probe(struct platform_device *pdev);\r
+static int etspi_remove(struct platform_device *pdev);\r
+\r
+#if 0\r
+typedef struct {\r
+       struct spi_device      *spi;\r
+       struct class           *class;\r
+       struct device          *device;\r
+//     struct cdev            cdev;\r
+       dev_t                  devno;\r
+       u8                     *huge_buffer;\r
+       size_t                 huge_buffer_size;\r
+       struct input_dev       *input_dev;\r
+} et320_data_t;\r
+#endif\r
+\r
+#if 0\r
+static int et320_spi_probe(struct spi_device *spi)\r
+{\r
+//     struct device *dev = &spi->dev;\r
+       int error = 0;\r
+       et320_data_t *et320 = NULL;\r
+       /* size_t buffer_size; */\r
+\r
+       printk(KERN_ERR "et320_spi_probe enter++++++\n");\r
+//#if 1\r
+       et320 = kzalloc(sizeof(*et320), GFP_KERNEL);\r
+       if (!et320) {\r
+               /*\r
+               dev_err(&spi->dev,\r
+               "failed to allocate memory for struct et512_data\n");\r
+               */\r
+               return -ENOMEM;\r
+       }\r
+       printk(KERN_INFO"%s\n", __func__);\r
+\r
+       spi_set_drvdata(spi, et320);\r
+//#endif       \r
+       g_data->spi = spi;\r
+//     egistec_mt_spi_t=spi_master_get_devdata(spi->master);\r
+\r
+       return error;\r
+}\r
+#endif\r
+\r
+\r
+#if 0\r
+static int et320_spi_remove(struct spi_device *spi)\r
+{\r
+\r
+       return 0;\r
+}\r
+#endif\r
+\r
+\r
+#if 0\r
+static struct of_device_id et320_spi_of_match[] = {\r
+       { .compatible = "egistec,et320", },\r
+       {}\r
+};\r
+#endif\r
+\r
+\r
+//MODULE_DEVICE_TABLE(of, et320_spi_of_match);\r
+\r
+#if 0\r
+static struct spi_driver spi_driver = {\r
+       .driver = {\r
+               .name   = "et320",\r
+               .owner  = THIS_MODULE,\r
+               .of_match_table = et320_spi_of_match,\r
+        .bus   = &spi_bus_type,\r
+       },\r
+       .probe  = et320_spi_probe,\r
+       .remove = et320_spi_remove\r
+};\r
+#endif\r
+\r
+\r
+static struct of_device_id etspi_match_table[] = {\r
+       { .compatible = "egistec,et320",},\r
+//     { .compatible = "samsung,et320",},\r
+       {},\r
+};\r
+MODULE_DEVICE_TABLE(of, etspi_match_table);\r
+\r
+/* fp_id is used only when dual sensor need to be support  */\r
+#if 0\r
+static struct of_device_id fp_id_match_table[] = {\r
+       { .compatible = "fp_id,fp_id",},\r
+       {},\r
+};\r
+MODULE_DEVICE_TABLE(of, fp_id_match_table);\r
+#endif\r
+\r
+\r
+\r
+static struct platform_driver etspi_driver = {\r
+       .driver = {\r
+               .name           = "et320",\r
+               .owner          = THIS_MODULE,\r
+               .of_match_table = etspi_match_table,\r
+       },\r
+    .probe =    etspi_probe,\r
+    .remove =   etspi_remove,\r
+};\r
+/* remark for dual sensors */\r
+/* module_platform_driver(etspi_driver); */\r
+\r
+\r
+\r
+static int etspi_remove(struct platform_device *pdev)\r
+{\r
+       DEBUG_PRINT("%s(#%d)\n", __func__, __LINE__);\r
+       free_irq(gpio_irq, NULL);\r
+       del_timer_sync(&fps_ints.timer);\r
+       wake_lock_destroy(&et320_wake_lock);\r
+       request_irq_done = 0;\r
+       /* t_mode = 255; */\r
+       return 0;\r
+}\r
+\r
+#define PINCTRL_STATE_DEFAULT "default"\r
+static int etspi_probe(struct platform_device *pdev)\r
+{\r
+       struct device *dev = &pdev->dev;\r
+       struct etspi_data *etspi;\r
+       struct clk *fp_spi_clk, *fp_spi_busclk0;\r
+       struct pinctrl *pinctrlfpc;\r
+       struct pinctrl_state *gpioState;\r
+       int status = 0;\r
+       unsigned long minor;\r
+       /* int retval; */\r
+\r
+       DEBUG_PRINT("%s initial\n", __func__);\r
+       pinctrlfpc = devm_pinctrl_get(&pdev->dev);\r
+       if (IS_ERR(pinctrlfpc)) \r
+       {\r
+               status = PTR_ERR(pinctrlfpc);\r
+               pr_err("Cannot find pinctrl!\n");\r
+               return -1;\r
+       }\r
+       gpioState =  pinctrl_lookup_state(pinctrlfpc, PINCTRL_STATE_DEFAULT);\r
+       if (IS_ERR(gpioState)) \r
+        {\r
+               status = PTR_ERR(gpioState);\r
+               pr_err("%s pinctrl_lookup_state fail %d\n", __func__, status);\r
+               return -1;\r
+       } \r
+       status =pinctrl_select_state(pinctrlfpc, gpioState);\r
+       if (status)\r
+       {\r
+               pr_err("pinctrl_select_state failed\n");\r
+               return -1;\r
+       }\r
+       \r
+       fp_spi_clk = clk_get(&pdev->dev, "spi");\r
+       if (IS_ERR(fp_spi_clk)) {\r
+               pr_err("Can't get fp_spi_clk\n");\r
+               return -1;
+       }
+
+       fp_spi_busclk0 = clk_get(&pdev->dev, "spi_busclk0");\r
+       if (IS_ERR(fp_spi_busclk0)) {\r
+               pr_err("Can't get fp_spi_busclk0\n");\r
+               return -1;
+       }
+
+       clk_prepare_enable(fp_spi_clk);\r
+       clk_prepare_enable(fp_spi_busclk0);\r
+       clk_set_rate(fp_spi_clk, 10000000*4);\r
+       clk_set_rate(fp_spi_busclk0, 10000000*4);\r
+       clk_put(fp_spi_clk);\r
+       clk_put(fp_spi_busclk0);\r
+\r
+       BUILD_BUG_ON(N_SPI_MINORS > 256);\r
+       status = register_chrdev(ET320_MAJOR, "et320", &etspi_fops);\r
+       if (status < 0) {\r
+               pr_err("%s register_chrdev error.\n", __func__);\r
+               return status;\r
+       }\r
+\r
+       etspi_class = class_create(THIS_MODULE, "et320");\r
+       if (IS_ERR(etspi_class)) {\r
+               pr_err("%s class_create error.\n", __func__);\r
+               unregister_chrdev(ET320_MAJOR, etspi_driver.driver.name);\r
+               return PTR_ERR(etspi_class);\r
+       }\r
+\r
+       /* Allocate driver data */\r
+       etspi = kzalloc(sizeof(*etspi), GFP_KERNEL);\r
+       if (etspi == NULL) {\r
+               pr_err("%s - Failed to kzalloc\n", __func__);\r
+               return -ENOMEM;\r
+       }\r
+\r
+       /* device tree call */\r
+       if (pdev->dev.of_node) {\r
+               status = etspi_parse_dt(&pdev->dev, etspi);\r
+               if (status) {\r
+                       pr_err("%s - Failed to parse DT\n", __func__);\r
+                       goto etspi_probe_parse_dt_failed;\r
+               }\r
+       }\r
+\r
+       /* Initialize the driver data */\r
+       etspi->spi = pdev;\r
+//     etspi->pd = pdev;\r
+       g_data = etspi;\r
+\r
+       spin_lock_init(&etspi->spi_lock);\r
+       mutex_init(&etspi->buf_lock);\r
+       mutex_init(&device_list_lock);\r
+\r
+       INIT_LIST_HEAD(&etspi->device_entry);\r
+\r
+       /* platform init */\r
+       status = etspi_platformInit(etspi);\r
+       if (status != 0) {\r
+               pr_err("%s platforminit failed\n", __func__);\r
+               goto etspi_probe_platformInit_failed;\r
+       }\r
+\r
+       fps_ints.drdy_irq_flag = DRDY_IRQ_DISABLE;\r
+\r
+#ifdef ETSPI_NORMAL_MODE\r
+/*\r
+       spi->bits_per_word = 8;\r
+       spi->max_speed_hz = SLOW_BAUD_RATE;\r
+       spi->mode = SPI_MODE_0;\r
+       spi->chip_select = 0;\r
+       status = spi_setup(spi);\r
+       if (status != 0) {\r
+               pr_err("%s spi_setup() is failed. status : %d\n",\r
+                       __func__, status);\r
+               return status;\r
+       }\r
+*/\r
+#endif\r
+\r
+       /*\r
+        * If we can allocate a minor number, hook up this device.\r
+        * Reusing minors is fine so long as udev or mdev is working.\r
+        */\r
+       mutex_lock(&device_list_lock);\r
+       minor = find_first_zero_bit(minors, N_SPI_MINORS);\r
+       if (minor < N_SPI_MINORS) {\r
+               struct device *fdev;\r
+               etspi->devt = MKDEV(ET320_MAJOR, minor);\r
+               fdev = device_create(etspi_class, &pdev->dev, etspi->devt, etspi, "esfp0");\r
+               status = IS_ERR(fdev) ? PTR_ERR(fdev) : 0;\r
+       } else {\r
+               dev_dbg(&pdev->dev, "no minor number available!\n");\r
+               status = -ENODEV;\r
+       }\r
+       if (status == 0) {\r
+               set_bit(minor, minors);\r
+               list_add(&etspi->device_entry, &device_list);\r
+       }\r
+\r
+#if EGIS_NAVI_INPUT\r
+       /*\r
+        * William Add.\r
+        */\r
+       sysfs_egis_init(etspi);\r
+       uinput_egis_init(etspi);\r
+#endif\r
+\r
+       mutex_unlock(&device_list_lock);\r
+\r
+       if (status == 0) {\r
+               /* spi_set_drvdata(pdev, etspi); */\r
+               dev_set_drvdata(dev, etspi);\r
+       } else {\r
+               goto etspi_probe_failed;\r
+       }\r
+       etspi_reset(etspi);\r
+\r
+       fps_ints.drdy_irq_flag = DRDY_IRQ_DISABLE;\r
+\r
+       /* the timer is for ET310 */\r
+       setup_timer(&fps_ints.timer, interrupt_timer_routine, (unsigned long)&fps_ints);\r
+       add_timer(&fps_ints.timer);\r
+       wake_lock_init(&et320_wake_lock, WAKE_LOCK_SUSPEND, "et320_wake_lock");\r
+       DEBUG_PRINT("  add_timer ---- \n");\r
+       DEBUG_PRINT("%s : initialize success %d\n",\r
+               __func__, status);\r
+\r
+       status = sysfs_create_group(&dev->kobj, &attribute_group);\r
+       if (status) {\r
+               pr_err("%s could not create sysfs\n", __func__);\r
+               goto etspi_probe_failed;\r
+       }\r
+\r
+\r
+       request_irq_done = 0;\r
+       return status;\r
+\r
+etspi_probe_failed:\r
+       device_destroy(etspi_class, etspi->devt);\r
+       class_destroy(etspi_class);\r
+\r
+etspi_probe_platformInit_failed:\r
+etspi_probe_parse_dt_failed:\r
+       kfree(etspi);\r
+       pr_err("%s is failed\n", __func__);\r
+#if EGIS_NAVI_INPUT\r
+       uinput_egis_destroy(etspi);\r
+       sysfs_egis_destroy(etspi);\r
+#endif\r
+\r
+       return status;\r
+}\r
+\r
+static int __init et320_init(void)\r
+{\r
+       int status = 0;\r
+       DEBUG_PRINT("%s  enter\n", __func__);\r
+#if 0\r
+       /* fp_id is used only when dual sensor need to be support  */\r
+       struct device_node *fp_id_np = NULL;\r
+       int fp_id_gpio = 0, fp_id_gpio_value;\r
+\r
+       fp_id_np = of_find_matching_node(fp_id_np, fp_id_match_table);\r
+       if (fp_id_np)\r
+           fp_id_gpio = of_get_named_gpio(fp_id_np, "fp,gpio-id", 0);\r
+\r
+       if (fp_id_gpio < 0) {\r
+               /* errorno = gpio; */\r
+               DEBUG_PRINT("%s: device tree error \n", __func__);\r
+               return status;\r
+       } else {\r
+               /* data->rstPin = gpio; */\r
+               DEBUG_PRINT("%s: fp_id Pin=%d\n", __func__, fp_id_gpio);\r
+       }\r
+       gpio_direction_input(fp_id_gpio);\r
+       fp_id_gpio_value = gpio_get_value(fp_id_gpio);\r
+       if (fp_id_gpio_value == 0)\r
+           DEBUG_PRINT("%s:  Load et320-int driver \n", __func__);\r
+       else {\r
+               DEBUG_PRINT("%s:  Load fpc driver \n", __func__);\r
+               return status;\r
+    }\r
+#endif\r
+       status = platform_driver_register(&etspi_driver);\r
+       DEBUG_PRINT("%s  done\n", __func__);\r
+\r
+//     if (spi_register_driver(&spi_driver))\r
+//     {\r
+//             printk(KERN_ERR "register spi driver fail%s\n", __func__);\r
+//             return -EINVAL;\r
+//     }\r
+       return status;\r
+}\r
+\r
+static void __exit et320_exit(void)\r
+{\r
+       platform_driver_unregister(&etspi_driver);\r
+//      spi_unregister_driver(&spi_driver);\r
+}\r
+\r
+module_init(et320_init);\r
+module_exit(et320_exit);\r
+\r
+MODULE_AUTHOR("Wang YuWei, <robert.wang@egistec.com>");\r
+MODULE_DESCRIPTION("SPI Interface for ET320");\r
+MODULE_LICENSE("GPL");\r
diff --git a/drivers/input/egistec/et320.h b/drivers/input/egistec/et320.h
new file mode 100755 (executable)
index 0000000..1c6d262
--- /dev/null
@@ -0,0 +1,163 @@
+#ifndef _FP_LINUX_DIRVER_H_
+#define _FP_LINUX_DIRVER_H_
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/wait.h>
+#include <linux/timer.h>
+#include <linux/jiffies.h>
+#include <linux/poll.h>
+#include <linux/sched.h>
+#include <linux/irq.h>
+#include <asm/irq.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/uaccess.h>
+#include <linux/platform_device.h>
+#include <linux/cdev.h>
+#include <linux/miscdevice.h>
+#include <linux/gpio.h>
+
+#include <linux/printk.h>
+#include <linux/module.h>
+#include <linux/spi/spi.h>
+
+
+/*#define FP_SPI_DEBUG*/
+#define FP_SPI_DEBUG
+
+#ifdef FP_SPI_DEBUG
+#define DEBUG_PRINT(fmt, args...) pr_err(fmt, ## args)
+#else
+#define DEBUG_PRINT(fmt, args...)
+#endif
+
+#define ET320_MAJOR                                    100 /* assigned */
+#define N_SPI_MINORS                           32  /* ... up to 256 */
+
+#define FP_ADDRESS_0                           0x00
+#define FP_WRITE_ADDRESS                       0xAC
+#define FP_READ_DATA                           0xAF
+#define FP_WRITE_DATA                          0xAE
+
+/* ------------------------- Register Definition ------------------------*/
+/*
+ * Sensor Registers
+ */
+
+#define FDATA_FP_ADDR                          0x00
+#define FSTATUS_FP_ADDR                                0x01
+/*
+ * Detect Define
+ */
+#define FRAME_READY_MASK                       0x01
+
+/* ------------------------- Opcode -------------------------------------*/
+#define FP_REGISTER_READ                       0x01
+#define FP_REGISTER_WRITE                      0x02
+#define FP_GET_ONE_IMG                         0x03
+#define FP_SENSOR_RESET                                0x04
+#define FP_POWER_ONOFF                         0x05
+#define FP_SET_SPI_CLOCK                       0x06
+#define FP_RESET_SET                           0x07
+
+/* trigger signal initial routine*/
+#define INT_TRIGGER_INIT                       0xa4
+/* trigger signal close routine*/
+#define INT_TRIGGER_CLOSE                      0xa5
+/* read trigger status*/
+#define INT_TRIGGER_READ                       0xa6
+/* polling trigger status*/
+#define INT_TRIGGER_POLLING                    0xa7
+/* polling abort*/
+#define INT_TRIGGER_ABORT                      0xa8
+#define FP_TRANSFER_SYNC                       0xAA
+
+#define DRDY_IRQ_ENABLE                                1
+#define DRDY_IRQ_DISABLE                       0
+
+/* interrupt polling */
+unsigned int fps_interrupt_poll(
+       struct file *file,
+       struct poll_table_struct *wait
+);
+struct interrupt_desc {
+       int gpio;
+       int number;
+       char *name;
+       int int_count;
+       struct timer_list timer;
+       bool finger_on;
+       int detect_period;
+       int detect_threshold;
+       bool drdy_irq_flag;
+};
+
+/* ------------------------- Structure ------------------------------*/
+struct egis_ioc_transfer {
+       u8 *tx_buf;
+       u8 *rx_buf;
+
+       __u32 len;
+       __u32 speed_hz;
+
+       __u16 delay_usecs;
+       __u8 bits_per_word;
+       __u8 cs_change;
+       __u8 opcode;
+       __u8 pad[3];
+
+};
+
+#define EGIS_IOC_MAGIC                 'k'
+#define EGIS_MSGSIZE(N) \
+       ((((N)*(sizeof(struct egis_ioc_transfer))) < (1 << _IOC_SIZEBITS)) \
+               ? ((N)*(sizeof(struct egis_ioc_transfer))) : 0)
+#define EGIS_IOC_MESSAGE(N) _IOW(EGIS_IOC_MAGIC, 0, char[EGIS_MSGSIZE(N)])
+
+struct etspi_data {
+       dev_t devt;
+       spinlock_t spi_lock;
+//     struct spi_device  *spi;        
+       struct platform_device *spi;
+       struct list_head device_entry;
+
+       /* buffer is NULL unless this device is open (users > 0) */
+       struct mutex buf_lock;
+       unsigned users;
+       u8 *buffer;
+
+       unsigned int irqPin;        /* interrupt GPIO pin number */
+       unsigned int rstPin;        /* Reset GPIO pin number */
+
+       unsigned int vdd_18v_Pin;       /* Reset GPIO pin number */
+       unsigned int vcc_33v_Pin;       /* Reset GPIO pin number */
+    struct input_dev   *input_dev;
+       bool property_navigation_enable;
+
+};
+
+
+/* ------------------------- Interrupt ------------------------------*/
+/* interrupt init */
+int Interrupt_Init(
+       struct etspi_data *etspi,
+       int int_mode,
+       int detect_period,
+       int detect_threshold);
+
+/* interrupt free */
+int Interrupt_Free(struct etspi_data *etspi);
+
+void fps_interrupt_abort(void);
+
+/* ------------------------- Data Transfer --------------------------*/
+/*[REM] int fp_io_read_register(struct fp_data *fp, u8 *addr, u8 *buf); */
+/*[REM] int fp_io_write_register(struct fp_data *fp, u8 *buf);*/
+/*[REM] int fp_io_get_one_image(struct fp_data *fp, u8 *buf, u8 *image_buf);*/
+/*[REM] int fp_read_register(struct fp_data *fp, u8 addr, u8 *buf);*/
+/*[REM] int fp_mass_read(struct fp_data *fp, u8 addr, u8 *buf, int read_len);*/
+#endif
diff --git a/drivers/input/egistec/navi_input.c b/drivers/input/egistec/navi_input.c
new file mode 100755 (executable)
index 0000000..c56e2fe
--- /dev/null
@@ -0,0 +1,769 @@
+#include <linux/delay.h>
+#include <linux/wait.h>
+#include <linux/timer.h>
+#include <linux/jiffies.h>
+#include <linux/input.h>
+#include <linux/platform_device.h>
+#include <linux/input/mt.h>
+#include <linux/printk.h>
+
+#include "et320.h"
+#include "navi_input.h"
+
+
+enum {
+       KEY_RELEASE,
+       KEY_PRESS,
+       KEY_PRESS_RELEASE
+};
+
+#define        DISABLE         0
+#define        ENABLE          1
+
+static struct task_struct *nav_kthread;
+static DECLARE_WAIT_QUEUE_HEAD(nav_input_wait);
+static unsigned int nav_input_sig;
+static DEFINE_MUTEX(driver_mode_lock);
+struct navi_cmd_struct {
+       char cmd;
+       struct list_head list;
+};
+
+struct navi_cmd_struct cmd_list;
+
+/*****************************************************************
+*                                                                *
+*                         Configuration                          *
+*                                                                *
+*****************************************************************/
+
+
+/*
+ * @ ENABLE_SWIPE_UP_DOWN
+ *     ENABLE : Listening to swipe-up & swipe-down navigation events.
+ *              Configure ENABLE_SWIPE_UP_DOWN properties below.
+ *
+ *     DISABLE : Ignore swipe-up & swipe-down navigation events.
+ *               Don't care properties.
+ *
+ * @ ENABLE_SWIPE_LEFT_RIGHT
+ *     ENABLE : Listening to swipe-left & swipe-right navigation events.
+ *              configure ENABLE_SWIPE_LEFT_RIGHT properties below.
+ *
+ *     DISABLE : Ignore swipe-left & swipe-right navigation events.
+ *               Don't care properties.
+ */
+
+#define ENABLE_SWIPE_UP_DOWN   DISABLE
+#define ENABLE_SWIPE_LEFT_RIGHT        DISABLE
+#define ENABLE_FINGER_DOWN_UP  DISABLE
+#define KEY_FPS_DOWN   614
+#define KEY_FPS_UP     615
+#define KEY_FPS_TAP    616
+#define KEY_FPS_HOLD   617
+#define KEY_FPS_YPLUS  618
+#define KEY_FPS_YMINUS 619
+#define KEY_FPS_XPLUS  620
+#define KEY_FPS_XMINUS 621
+#define KEY_FPS_DOUBLE_TAP 622
+
+
+/*
+ * ENABLE_SWIPE_UP_DOWN properties
+ *
+ * If ENABLE_SWIPE_UP_DOWN set to DISABLE, these should neglected
+ *
+ *
+ * @ KEYEVENT_UP : The key-event should be sent when swipe-up.
+ * @ KEYEVENT_UP_ACTION : Action of KEYEVENT_UP.
+ *
+ * @ KEYEVENT_DOWN : The key-event should be sent when swipe-down.
+ * @ KEYEVENT_DOWN_ACTION : Action of KEYEVENT_UP.
+ *
+ * @ ACTION:
+ *   KEY_PRESS : Press key button
+ *   KEY_RELEASE : Release key button
+ *   KEY_PRESS_RELEASE : Combined action of press-then-release
+ */
+#define        KEYEVENT_UP                             KEY_FPS_XMINUS /*KEY_UP*/
+#define        KEYEVENT_UP_ACTION              KEY_PRESS_RELEASE
+#define        KEYEVENT_DOWN                   KEY_FPS_XPLUS /*KEY_DOWN*/
+#define        KEYEVENT_DOWN_ACTION    KEY_PRESS_RELEASE
+
+
+/*
+ *ENABLE_SWIPE_LEFT_RIGHT properties.
+ *
+ * If ENABLE_SWIPE_LEFT_RIGHT set to DISABLE, these should neglected
+ *
+ *
+ * @ KEYEVENT_RIGHT : The key-event should be sent when swipe-right.
+ * @ KEYEVENT_RIGHT_ACTION : Action of KEYEVENT_RIGHT.
+ *
+ * @ KEYEVENT_LEFT : The key-event should be sent when swipe-left.
+ * @ KEYEVENT_LEFT_ACTION : Action of KEYEVENT_LEFT.
+ *
+ * @ ACTION:
+ *   KEY_PRESS : Press key button
+ *   KEY_RELEASE : Release key button
+ *   KEY_PRESS_RELEASE : Combined action of press-then-release
+ */
+#define        KEYEVENT_RIGHT                  KEY_FPS_YMINUS /* KEY_RIGHT */
+#define        KEYEVENT_RIGHT_ACTION   KEY_PRESS_RELEASE
+#define        KEYEVENT_LEFT                   KEY_FPS_YPLUS  /* KEY_LEFT */
+#define        KEYEVENT_LEFT_ACTION    KEY_PRESS_RELEASE
+#if ENABLE_FINGER_DOWN_UP
+unsigned int prev_keycode = 0;
+#endif
+/*
+ * @ TRANSLATED_COMMAND
+ *     ENABLE : TRANSLATED command. Navigation events will be translated to
+ *              logical user-events. e.g. click, double-click, long-click
+ *              Configure TRANSLATED properties.
+ *
+ *     DISABLE : STRAIGHT command. Navigation events will be sent one-by-one
+ *               directly.
+ *               Configure STRAIGHT properties.
+ */
+#define        TRANSLATED_COMMAND              ENABLE
+
+
+
+
+#if TRANSLATED_COMMAND
+
+/*-------------------TRANSLATED properties---------------------*/
+
+/*
+ * @ ENABLE_TRANSLATED_SINGLE_CLICK
+ *     ENABLE/DISABLE : enable/disable single-click event.
+ *
+ * @ ENABLE_TRANSLATED_DOUBLE_CLICK
+ *     ENABLE/DISABLE : enable/disable double-click event.
+ *
+ * @ ENABLE_TRANSLATED_LONG_TOUCH
+ *     ENABLE/DISABLE : enable/disable long-touch event.
+ */
+#define ENABLE_TRANSLATED_SINGLE_CLICK ENABLE
+#define ENABLE_TRANSLATED_DOUBLE_CLICK ENABLE
+#define ENABLE_TRANSLATED_LONG_TOUCH   DISABLE
+
+
+/*
+ * @ LONGTOUCH_INTERVAL : Minimum time finger stay-on that counted to long-touch.
+ *     Only concerned while ENABLE_TRANSLATED_LONG_TOUCH set to ENABLE.
+ *     In millisecond (ms)
+ *
+ * @ DOUBLECLICK_INTERVAL : Maximum time between two click that counted to double-click.
+ *     Only concerned while ENABLE_TRANSLATED_DOUBLE_CLICK set to ENABLE.
+ *     In millisecond (ms)
+ *
+ * @ KEYEVENT_CLICK : The key-event should be sent when single-click.
+ * @ KEYEVENT_CLICK_ACTION : Action of KEYEVENT_CLICK.
+ *     Only concerned while ENABLE_TRANSLATED_SINGLE_CLICK set to ENABLE.
+ *
+ * @ KEYEVENT_DOUBLECLICK : The key-event should be sent when double-click.
+ * @ KEYEVENT_DOUBLECLICK_ACTION : Action of KEYEVENT_DOUBLECLICK.
+ *     Only concerned while ENABLE_TRANSLATED_DOUBLE_CLICK set to ENABLE.
+ *
+ * @ KEYEVENT_LONGTOUCH : The key-event should be sent when long-touch.
+ * @ KEYEVENT_LONGTOUCH_ACTION : Action of KEYEVENT_LONGTOUCH.
+ *     Only concerned while ENABLE_TRANSLATED_LONG_TOUCH set to ENABLE.
+ *
+ * @ ACTION:
+ *   KEY_PRESS : Press key button
+ *   KEY_RELEASE : Release key button
+ *   KEY_PRESS_RELEASE : Combined action of press-then-release
+ */
+#define LONGTOUCH_INTERVAL          400
+#define SINGLECLICK_INTERVAL        200
+#define DOUBLECLICK_INTERVAL        150
+
+
+#define        KEYEVENT_CLICK              KEY_FPS_TAP /* 0x232 */
+#define        KEYEVENT_CLICK_ACTION       KEY_PRESS_RELEASE
+#define        KEYEVENT_DOUBLECLICK        KEY_FPS_DOUBLE_TAP
+#define        KEYEVENT_DOUBLECLICK_ACTION KEY_PRESS_RELEASE
+#define        KEYEVENT_LONGTOUCH          KEY_FPS_HOLD /* 0x233 */
+#define        KEYEVENT_LONGTOUCH_ACTION   KEY_PRESS_RELEASE
+
+#define        KEYEVENT_ON                 KEY_FPS_DOWN
+#define        KEYEVENT_ON_ACTION          KEY_PRESS_RELEASE
+#define        KEYEVENT_OFF                KEY_FPS_UP
+#define        KEYEVENT_OFF_ACTION         KEY_PRESS_RELEASE
+
+
+/*---------------End of TRANSLATED properties-----------------*/
+
+
+#else  /* STRAIGHT COMMAND */
+
+
+/*-------------------STRAIGHT properties----------------------*/
+
+/*
+ * @ ENABLE_STRAIGHT_CANCEL
+ *     ENABLE/DISABLE : enable/disable cancel event.
+ *
+ * @ ENABLE_STRAIGHT_ON
+ *     ENABLE/DISABLE : enable/disable finger-on event.
+ *
+ * @ ENABLE_STRAIGHT_OFF
+ *     ENABLE/DISABLE : enable/disable finger-off event.
+ */
+#define ENABLE_STRAIGHT_CANCEL ENABLE
+#define ENABLE_STRAIGHT_ON             ENABLE
+#define ENABLE_STRAIGHT_OFF            ENABLE
+
+
+/*
+ * @ KEYEVENT_CANCEL : The key-event should be sent when cancel.
+ * @ KEYEVENT_CANCEL_ACTION : Action of KEYEVENT_CANCEL.
+ *     Only concerned while ENABLE_STRAIGHT_CANCEL set to ENABLE.
+ *
+ * @ KEYEVENT_ON : The key-event should be sent when finger-on.
+ * @ KEYEVENT_ON_ACTION : Action of KEYEVENT_ON.
+ *     Only concerned while ENABLE_STRAIGHT_ON set to ENABLE.
+ *
+ * @ KEYEVENT_OFF : The key-event should be sent when long-touch.
+ * @ KEYEVENT_OFF_ACTION : Action of KEYEVENT_OFF.
+ *     Only concerned while ENABLE_STRAIGHT_OFF set to ENABLE.
+ *
+ * @ ACTION:
+ *   KEY_PRESS : Press key button
+ *   KEY_RELEASE : Release key button
+ *   KEY_PRESS_RELEASE : Combined action of press-then-release
+ */
+#define        KEYEVENT_CANCEL                 KEY_0
+#define        KEYEVENT_CANCEL_ACTION  KEY_PRESS_RELEASE
+#define        KEYEVENT_ON                             KEY_EXIT
+#define        KEYEVENT_ON_ACTION              KEY_PRESS
+#define        KEYEVENT_OFF                    KEY_EXIT
+#define        KEYEVENT_OFF_ACTION             KEY_RELEASE
+
+/*-----------------End of STRAIGHT properties-------------------*/
+
+
+#endif
+
+
+/****************************************************************
+*                                                               *
+*                      End of Configuration                     *
+*                                                               *
+****************************************************************/
+
+
+
+
+
+
+
+
+
+
+#define PROPERTY_NAVIGATION_ENABLE_DEFAULT  true
+
+struct navi_struct {
+    char cmd;
+    struct etspi_data *etspi;
+    struct work_struct workq;
+};
+
+enum navi_event {
+       NAVI_EVENT_CANCEL,
+       NAVI_EVENT_ON,
+       NAVI_EVENT_OFF,
+       NAVI_EVENT_SWIPE,
+       NAVI_EVENT_UP,
+       NAVI_EVENT_DOWN,
+       NAVI_EVENT_RIGHT,
+       NAVI_EVENT_LEFT
+};
+#if ENABLE_TRANSLATED_LONG_TOUCH
+static struct timer_list long_touch_timer;
+#endif
+static bool g_KeyEventRaised = true;
+static unsigned long g_DoubleClickJiffies;
+static unsigned long g_SingleClickJiffies;
+static unsigned int g_SingleClick;
+
+
+
+/* Set event bits according to what events we would generate */
+void init_event_enable(struct etspi_data *etspi)
+{
+       set_bit(EV_KEY, etspi->input_dev->evbit);
+       set_bit(EV_SYN, etspi->input_dev->evbit);
+#if TRANSLATED_COMMAND
+       set_bit(KEYEVENT_ON, etspi->input_dev->keybit);
+       set_bit(KEYEVENT_OFF, etspi->input_dev->keybit);
+       set_bit(KEYEVENT_CLICK, etspi->input_dev->keybit);
+       set_bit(KEYEVENT_DOUBLECLICK, etspi->input_dev->keybit);
+       set_bit(KEYEVENT_LONGTOUCH, etspi->input_dev->keybit);
+       set_bit(KEYEVENT_UP, etspi->input_dev->keybit);
+       set_bit(KEYEVENT_DOWN, etspi->input_dev->keybit);
+       set_bit(KEYEVENT_RIGHT, etspi->input_dev->keybit);
+       set_bit(KEYEVENT_LEFT, etspi->input_dev->keybit);
+#else
+       set_bit(KEYEVENT_CANCEL, etspi->input_dev->keybit);
+       set_bit(KEYEVENT_ON, etspi->input_dev->keybit);
+       set_bit(KEYEVENT_OFF, etspi->input_dev->keybit);
+       set_bit(KEYEVENT_UP, etspi->input_dev->keybit);
+       set_bit(KEYEVENT_DOWN, etspi->input_dev->keybit);
+       set_bit(KEYEVENT_RIGHT, etspi->input_dev->keybit);
+       set_bit(KEYEVENT_LEFT, etspi->input_dev->keybit);
+#endif
+}
+
+
+static void send_key_event(struct etspi_data *etspi, unsigned int code, int value)
+{
+       struct etspi_data *obj = etspi;
+
+       if (value == KEY_PRESS_RELEASE) {
+               input_report_key(obj->input_dev, code, 1);      /* 1 is press */
+               input_sync(obj->input_dev);
+               input_report_key(obj->input_dev, code, 0);      /* 0 is release */
+               input_sync(obj->input_dev);
+#if ENABLE_FINGER_DOWN_UP
+               prev_keycode = code;
+#endif
+       } else {
+               input_report_key(obj->input_dev, code, value);
+               input_sync(obj->input_dev);
+       }
+
+       DEBUG_PRINT("Egis navigation driver, send key event: %d, action: %d\n", code, value);
+}
+
+#if ENABLE_TRANSLATED_LONG_TOUCH
+static void long_touch_handler(unsigned long arg)
+{
+       struct etspi_data *etspi = (struct etspi_data *)arg;
+
+       if (g_KeyEventRaised == false) {
+               g_KeyEventRaised = true;
+               /* Long touch event */
+               send_key_event(etspi, KEYEVENT_LONGTOUCH, KEYEVENT_LONGTOUCH_ACTION);
+       }
+}
+#endif
+
+
+#if TRANSLATED_COMMAND
+void translated_command_converter(char cmd, struct etspi_data *etspi)
+{
+       DEBUG_PRINT("Egis navigation driver, translated cmd: %d\n", cmd);
+
+       switch (cmd) {
+       case NAVI_EVENT_CANCEL:
+               g_KeyEventRaised = true;
+               g_DoubleClickJiffies = 0;
+               g_SingleClickJiffies = 0;
+               g_SingleClick = 0;
+#if ENABLE_TRANSLATED_LONG_TOUCH
+               del_timer(&long_touch_timer);
+#endif
+               break;
+
+       case NAVI_EVENT_ON: /* finger down */
+               g_KeyEventRaised = false;
+#if ENABLE_TRANSLATED_SINGLE_CLICK
+               g_SingleClickJiffies = jiffies;
+#endif
+
+#if ENABLE_FINGER_DOWN_UP
+               send_key_event(etspi, KEYEVENT_ON, KEYEVENT_ON_ACTION);
+#endif
+#if ENABLE_TRANSLATED_LONG_TOUCH
+               long_touch_timer.data = (unsigned long)etspi;
+               mod_timer(&long_touch_timer, jiffies + (HZ * LONGTOUCH_INTERVAL / 1000));
+#endif
+               break;
+
+       case NAVI_EVENT_OFF: /* finger up */
+               if (g_KeyEventRaised == false) {
+                       g_KeyEventRaised = true;
+                       pr_info("Egis : g_SingleClick %u tap interval =%u double tap interval = %u time= %u",
+                               g_SingleClick, jiffies_to_msecs(jiffies - g_SingleClickJiffies),
+                               jiffies_to_msecs(jiffies - g_DoubleClickJiffies), jiffies_to_msecs(jiffies));
+#if ENABLE_TRANSLATED_SINGLE_CLICK
+                       if((jiffies - g_SingleClickJiffies) < (HZ * SINGLECLICK_INTERVAL / 1000)) {
+                               /* Click event */
+                               send_key_event(etspi, KEYEVENT_CLICK, KEYEVENT_CLICK_ACTION);
+                               g_SingleClick++;
+                               if(g_SingleClick == 1) {
+                                       g_DoubleClickJiffies = jiffies;
+                               }
+                       }
+#endif
+#if ENABLE_TRANSLATED_DOUBLE_CLICK
+                       if (g_SingleClick >= 2 ) {
+                               if((jiffies - g_DoubleClickJiffies) < (HZ * (SINGLECLICK_INTERVAL+DOUBLECLICK_INTERVAL) / 1000)) {
+                                       /* Double click event */
+                                       send_key_event(etspi, KEYEVENT_DOUBLECLICK, KEYEVENT_DOUBLECLICK_ACTION);
+                                       g_SingleClick = 0;
+                               } else {
+                                       g_SingleClick = 1;
+                                       g_DoubleClickJiffies = jiffies;
+                               }
+
+                       }
+#endif
+                       
+#if ENABLE_FINGER_DOWN_UP
+                       send_key_event(etspi, KEYEVENT_OFF, KEYEVENT_OFF_ACTION);
+#endif
+               }
+#if ENABLE_FINGER_DOWN_UP
+               else    {
+                       if (prev_keycode == KEYEVENT_LONGTOUCH)
+                               send_key_event(etspi, KEYEVENT_OFF, KEYEVENT_OFF_ACTION);
+               }
+#endif
+#if ENABLE_TRANSLATED_LONG_TOUCH
+               del_timer(&long_touch_timer);
+#endif
+               break;
+
+       case NAVI_EVENT_UP:
+               if (g_KeyEventRaised == false) {
+                       g_KeyEventRaised = true;
+#if ENABLE_SWIPE_UP_DOWN
+                       send_key_event(etspi, KEYEVENT_UP, KEYEVENT_UP_ACTION);
+                       send_key_event(etspi, KEYEVENT_OFF, KEYEVENT_OFF_ACTION);
+
+#endif
+               }
+               break;
+
+       case NAVI_EVENT_DOWN:
+
+               if (g_KeyEventRaised == false) {
+                       g_KeyEventRaised = true;
+#if ENABLE_SWIPE_UP_DOWN
+                       send_key_event(etspi, KEYEVENT_DOWN, KEYEVENT_DOWN_ACTION);
+                       send_key_event(etspi, KEYEVENT_OFF, KEYEVENT_OFF_ACTION);
+
+#endif
+               }
+
+       break;
+
+       case NAVI_EVENT_RIGHT:
+
+               #if ENABLE_SWIPE_LEFT_RIGHT
+               if (g_KeyEventRaised == false) {
+                       g_KeyEventRaised = true;
+                       send_key_event(etspi, KEYEVENT_RIGHT, KEYEVENT_RIGHT_ACTION);
+                       send_key_event(etspi, KEYEVENT_OFF, KEYEVENT_OFF_ACTION);
+               }
+               #endif
+
+               break;
+
+       case NAVI_EVENT_LEFT:
+
+               #if ENABLE_SWIPE_LEFT_RIGHT
+               if (g_KeyEventRaised == false) {
+                       g_KeyEventRaised = true;
+                       send_key_event(etspi, KEYEVENT_LEFT, KEYEVENT_LEFT_ACTION);
+                       send_key_event(etspi, KEYEVENT_OFF, KEYEVENT_OFF_ACTION);
+
+               }
+               #endif
+
+               break;
+
+       default:
+               pr_err("Egis navigation driver, cmd not match\n");
+       }
+}
+
+#else  /* straight command (not define TRANSLATED_COMMAND) */
+
+void straight_command_converter(char cmd, struct etspi_data *etspi)
+{
+       DEBUG_PRINT("Egis navigation driver, straight cmd: %d\n", cmd);
+
+       switch (cmd) {
+       case NAVI_EVENT_CANCEL:
+
+#if ENABLE_STRAIGHT_CANCEL
+               send_key_event(etspi, KEYEVENT_CANCEL, KEYEVENT_CANCEL_ACTION);
+#endif
+
+               break;
+
+       case NAVI_EVENT_ON:
+
+#if ENABLE_STRAIGHT_ON
+               send_key_event(etspi, KEYEVENT_ON, KEYEVENT_ON_ACTION);
+#endif
+
+               break;
+
+       case NAVI_EVENT_OFF:
+
+#if ENABLE_STRAIGHT_OFF
+               send_key_event(etspi, KEYEVENT_OFF, KEYEVENT_OFF_ACTION);
+#endif
+
+               break;
+
+       case NAVI_EVENT_UP:
+
+#if ENABLE_SWIPE_UP_DOWN
+               send_key_event(etspi, KEYEVENT_UP, KEYEVENT_UP_ACTION);
+#endif
+
+               break;
+
+       case NAVI_EVENT_DOWN:
+
+#if ENABLE_SWIPE_UP_DOWN
+               send_key_event(etspi, KEYEVENT_DOWN, KEYEVENT_DOWN_ACTION);
+#endif
+
+               break;
+
+       case NAVI_EVENT_RIGHT:
+
+#if ENABLE_SWIPE_LEFT_RIGHT
+               send_key_event(etspi, KEYEVENT_RIGHT, KEYEVENT_RIGHT_ACTION);
+#endif
+
+               break;
+
+       case NAVI_EVENT_LEFT:
+
+#if ENABLE_SWIPE_LEFT_RIGHT
+               send_key_event(etspi, KEYEVENT_LEFT, KEYEVENT_LEFT_ACTION);
+#endif
+
+               break;
+
+       default:
+               pr_err("Egis navigation driver, cmd not match\n");
+       }
+}
+
+#endif  /* end of TRANSLATED_COMMAND */
+
+void navi_operator(struct work_struct *work)
+{
+    struct navi_struct *command = container_of(work, struct navi_struct, workq);
+
+#if TRANSLATED_COMMAND
+       translated_command_converter(command->cmd, command->etspi);
+#else
+       straight_command_converter(command->cmd, command->etspi);
+
+#endif
+}
+
+static ssize_t navigation_event_func(struct device *dev,
+       struct device_attribute *attr, const char *buf, size_t count)
+{
+       struct etspi_data *etspi = dev_get_drvdata(dev);
+       struct navi_cmd_struct *tempcmd;
+       DEBUG_PRINT("Egis navigation driver, %s echo :'%d'\n", __func__, *buf);
+
+       if (etspi) {
+               dev_dbg(&etspi->spi->dev, "%s spi_show\n", __func__);
+               if (etspi->spi) {
+                       dev_dbg(&etspi->spi->dev, "%s spi show\n", __func__);
+               }
+       } else
+               pr_err("Egis navigation driver, etspi is NULL\n");
+
+       if (etspi->input_dev == NULL)
+               pr_err("Egis navigation driver, etspi->input_dev is NULL\n");
+       tempcmd = kmalloc(sizeof(*tempcmd), GFP_KERNEL);
+       if (tempcmd != NULL) {
+               mutex_lock(&driver_mode_lock);
+               tempcmd->cmd = *buf;
+               list_add_tail(&tempcmd->list, &cmd_list.list);
+               nav_input_sig = 1;
+               mutex_unlock(&driver_mode_lock);
+               wake_up_interruptible(&nav_input_wait);
+       } else {
+               pr_err("navigation_event_func kmalloc failed\n");
+
+       }
+       return count;
+}
+static DEVICE_ATTR(navigation_event, S_IWUSR, NULL, navigation_event_func);
+
+static ssize_t property_navigation_enable_set(struct device *dev,
+               struct device_attribute *attr, const char *buf, size_t count)
+{
+       struct etspi_data *etspi = dev_get_drvdata(dev);
+       pr_err("Egis navigation driver, %s echo :'%d'\n", __func__, *buf);
+
+       if (!strncmp(buf, "enable", strlen("enable")))  {
+               etspi->property_navigation_enable = 1;
+       } else if (!strncmp(buf, "disable", strlen("disable")))  {
+               etspi->property_navigation_enable = 0;
+       } else {
+               pr_err("strcmp not match\n");
+       }
+       return count;
+}
+
+static ssize_t property_navigation_enable_get(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       struct etspi_data *etspi = dev_get_drvdata(dev);
+       DEBUG_PRINT("Egis navigation driver, %s echo :'%d'\n", __func__, *buf);
+
+       return scnprintf(buf, PAGE_SIZE, "%s",
+                       etspi->property_navigation_enable ? "enable":"disable");
+}
+static DEVICE_ATTR(navigation_enable, S_IRUSR|S_IWUSR,
+                               property_navigation_enable_get, property_navigation_enable_set);
+
+
+/*-------------------------------------------------------------------------*/
+/*
+ *     Sysfs node creation
+ */
+static struct attribute *attributes[] = {
+       &dev_attr_navigation_event.attr,
+       &dev_attr_navigation_enable.attr,
+       NULL
+};
+static const struct attribute_group attribute_group = {
+       .attrs = attributes,
+};
+
+
+/*-------------------------------------------------------------------------*/
+static int nav_input_thread(void *et_spi)
+{
+       struct etspi_data *etspi = et_spi;
+       struct navi_cmd_struct *tempcmd, *acmd;
+
+       set_user_nice(current, -20);
+       DEBUG_PRINT("nav_input_thread enter\n");
+
+       while (1) {
+               wait_event_interruptible(nav_input_wait,
+                       nav_input_sig || kthread_should_stop());
+               mutex_lock(&driver_mode_lock);
+               list_for_each_entry_safe(acmd, tempcmd, &cmd_list.list, list) {
+                       translated_command_converter(acmd->cmd, etspi);
+                       list_del(&acmd->list);
+                       kfree(acmd);
+               }
+               nav_input_sig = 0;
+               mutex_unlock(&driver_mode_lock);
+               if (kthread_should_stop())
+                       break;
+       }
+
+
+       DEBUG_PRINT("nav_input_thread exit\n");
+
+       return 0;
+}
+
+
+void uinput_egis_init(struct etspi_data *etspi)
+{
+       int error = 0;
+
+       DEBUG_PRINT("Egis navigation driver, %s\n", __func__);
+
+       etspi->property_navigation_enable = PROPERTY_NAVIGATION_ENABLE_DEFAULT ;
+       etspi->input_dev = input_allocate_device();
+
+       if (!etspi->input_dev) {
+               pr_err("Egis navigation driver, Input_allocate_device failed.\n");
+               return;
+       }
+
+
+       INIT_LIST_HEAD(&cmd_list.list);
+       nav_input_sig = 0;
+       if (!nav_kthread) {
+               nav_kthread = kthread_run(nav_input_thread,
+                       (void *)etspi, "nav_thread");
+       }
+#if ENABLE_TRANSLATED_LONG_TOUCH
+       init_timer(&long_touch_timer);
+       long_touch_timer.function = long_touch_handler;
+#endif
+
+
+       etspi->input_dev->name = "uinput-egis";
+
+       init_event_enable(etspi);
+
+       /* Register the input device */
+       error = input_register_device(etspi->input_dev);
+       if (error) {
+               pr_err("Egis navigation driver, Input_register_device failed.\n");
+               input_free_device(etspi->input_dev);
+               etspi->input_dev = NULL;
+       }
+       g_DoubleClickJiffies = 0;
+       g_SingleClickJiffies = 0;
+}
+
+void uinput_egis_destroy(struct etspi_data *etspi)
+{
+       DEBUG_PRINT("Egis navigation driver, %s\n", __func__);
+
+
+#if ENABLE_TRANSLATED_LONG_TOUCH
+       del_timer(&long_touch_timer);
+#endif
+
+       if (etspi->input_dev != NULL)
+               input_free_device(etspi->input_dev);
+       if (nav_kthread)
+               kthread_stop(nav_kthread);
+
+       nav_kthread = NULL;
+}
+
+
+void sysfs_egis_init(struct etspi_data *etspi)
+{
+       int status;
+
+       DEBUG_PRINT("Egis navigation driver, egis_input device init\n");
+       etspi->spi = platform_device_alloc("egis_input", -1);
+       if (!etspi->spi) {
+               pr_err("Egis navigation driver, platform_device_alloc fail\n");
+               return;
+       }
+
+       status = platform_device_add(etspi->spi);
+       if (status != 0) {
+               pr_err("Egis navigation driver, platform_device_add fail\n");
+               platform_device_put(etspi->spi);
+               return;
+       }
+
+       dev_set_drvdata(&etspi->spi->dev, etspi);
+       status = sysfs_create_group(&etspi->spi->dev.kobj, &attribute_group);
+       if (status) {
+               pr_err("Egis navigation driver, could not create sysfs\n");
+               platform_device_del(etspi->spi);
+               platform_device_put(etspi->spi);
+               return;
+       }
+}
+
+void sysfs_egis_destroy(struct etspi_data *etspi)
+{
+       DEBUG_PRINT("Egis navigation driver, %s\n", __func__);
+
+       if (etspi->spi) {
+               platform_device_del(etspi->spi);
+               platform_device_put(etspi->spi);
+       }
+}
diff --git a/drivers/input/egistec/navi_input.h b/drivers/input/egistec/navi_input.h
new file mode 100755 (executable)
index 0000000..a6dc8ef
--- /dev/null
@@ -0,0 +1,6 @@
+
+
+void uinput_egis_init(struct etspi_data *etspi);
+void uinput_egis_destroy(struct etspi_data *etspi);
+void sysfs_egis_init(struct etspi_data *etspi);
+void sysfs_egis_destroy(struct etspi_data *etspi);
\ No newline at end of file