--- /dev/null
+/*\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
--- /dev/null
+#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);
+ }
+}