Fingerprint. Driver porting.

Root cause:
N/A

How to fix:
N/A

RiskArea: Fingerprint

Change-Id: Id231c4ee49de5cd25fbdc452bfc4e806f4429597
diff --git a/arch/arm64/boot/dts/qcom/msm8953-pinctrl.dtsi b/arch/arm64/boot/dts/qcom/msm8953-pinctrl.dtsi
index 3dad2f2..957f6ac 100644
--- a/arch/arm64/boot/dts/qcom/msm8953-pinctrl.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8953-pinctrl.dtsi
@@ -399,6 +399,62 @@
 
 		};
 
+//<2020/04/23-louisliu, Fingerprint. Driver porting.
+		fps {
+			fps_int_active: fps_int_active {
+				mux {
+					pins = "gpio48";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio48";
+					drive-strength = <8>;
+					bias-pull-up;
+				};
+			};
+
+			fps_int_suspend: fps_int_suspend {
+				mux {
+					pins = "gpio48";
+					function = "gpio";
+				};
+
+			config {
+					pins = "gpio48";
+					drive-strength = <2>;
+					bias-pull-down;
+				};
+			};
+
+			fps_reset_active: fps_reset_active {
+				mux {
+					pins = "gpio140";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio140";
+					drive-strength = <8>;
+					bias-pull-up;
+				};
+			};
+
+			fps_reset_suspend1: fps_reset_suspend1 {
+				mux {
+					pins = "gpio140";
+					function = "gpio";
+				};
+
+				config {
+					pins = "gpio140";
+					drive-strength = <2>;
+					bias-pull-down;
+				};
+			};
+		};
+//>2020/04/23-louisliu
+
 		pmx_mdss: pmx_mdss {
 
 			/*[Arima_8901][Jialong] lcm driver porting begin*/
diff --git a/arch/arm64/boot/dts/qcom/msm8953.dtsi b/arch/arm64/boot/dts/qcom/msm8953.dtsi
index 1d78b6b..cd084ca 100644
--- a/arch/arm64/boot/dts/qcom/msm8953.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8953.dtsi
@@ -2319,3 +2319,16 @@
 &gdsc_usb30 {
 	status = "okay";
 };
+
+// //<2020/04/23-louisliu, Fingerprint. Driver porting.
+&soc {
+	elan {
+		compatible = "elan,elan_fp";
+		interrupt-parent = <&tlmm>;
+		interrupts = <48 0>;
+		elan,irq-gpio = <&tlmm 48 0>;
+		elan,rst-gpio = <&tlmm 140 0>;
+		elan,vdd-gpio = <&tlmm 90 0>;
+	};
+};
+// //>2020/04/23-louisliu
\ No newline at end of file
diff --git a/arch/arm64/configs/msm8953-perf_defconfig b/arch/arm64/configs/msm8953-perf_defconfig
index 78f1f97..221622c 100755
--- a/arch/arm64/configs/msm8953-perf_defconfig
+++ b/arch/arm64/configs/msm8953-perf_defconfig
@@ -684,3 +684,6 @@
 CONFIG_CRYPTO_AES_ARM64_NEON_BLK=y
 CONFIG_CRYPTO_CRC32_ARM64=y
 CONFIG_QMI_ENCDEC=y
+# //<2020/04/23-louisliu, Fingerprint. Driver porting.
+CONFIG_ELAN_FINGERPRINT=y
+# //>2020/04/23-louisliu
diff --git a/arch/arm64/configs/msm8953_defconfig b/arch/arm64/configs/msm8953_defconfig
index f30592c..ad12e19 100755
--- a/arch/arm64/configs/msm8953_defconfig
+++ b/arch/arm64/configs/msm8953_defconfig
@@ -748,3 +748,6 @@
 CONFIG_CRYPTO_AES_ARM64_NEON_BLK=y
 CONFIG_CRYPTO_CRC32_ARM64=y
 CONFIG_QMI_ENCDEC=y
+# //<2020/04/23-louisliu, Fingerprint. Driver porting.
+CONFIG_ELAN_FINGERPRINT=y
+# //>2020/04/23-louisliu
diff --git a/drivers/input/Kconfig b/drivers/input/Kconfig
index de41b16..0d48666 100644
--- a/drivers/input/Kconfig
+++ b/drivers/input/Kconfig
@@ -200,6 +200,17 @@
 	---help---
 	  Say Y here if you want to take action when some keys are pressed;
 
+# //<2020/04/23-louisliu, Fingerprint. Driver porting.
+config ELAN_FINGERPRINT
+	tristate "ELAN Fingerprint"
+	default n
+	---help---
+		Fingerprint qualcomm driver enable/disable in the kernel.
+		Say Y here if you want to use qualcomm fingerprint driver,
+		fingerprint driver will support fingerprint function in TEE,
+		it supports ELNA's all fingerprint device.
+# //>2020/04/23-louisliu
+
 comment "Input Device Drivers"
 
 source "drivers/input/keyboard/Kconfig"
diff --git a/drivers/input/Makefile b/drivers/input/Makefile
index 7ff1b70..50a5f94 100644
--- a/drivers/input/Makefile
+++ b/drivers/input/Makefile
@@ -34,3 +34,7 @@
 obj-$(CONFIG_INPUT_KEYRESET)	+= keyreset.o
 obj-$(CONFIG_INPUT_KEYCOMBO)	+= keycombo.o
 obj-$(CONFIG_SMI130)   += sensors/smi130/
+
+# //<2020/04/23-louisliu, Fingerprint. Driver porting.
+obj-$(CONFIG_ELAN_FINGERPRINT) +=fingerprint/
+# //>2020/04/23-louisliu
\ No newline at end of file
diff --git a/drivers/input/fingerprint/Makefile b/drivers/input/fingerprint/Makefile
new file mode 100644
index 0000000..4b4eb3a
--- /dev/null
+++ b/drivers/input/fingerprint/Makefile
@@ -0,0 +1,2 @@
+
+obj-$(CONFIG_ELAN_FINGERPRINT)=elan_fp_qcom_tee.o
\ No newline at end of file
diff --git a/drivers/input/fingerprint/elan_fp_qcom_tee.c b/drivers/input/fingerprint/elan_fp_qcom_tee.c
new file mode 100644
index 0000000..34d3517
--- /dev/null
+++ b/drivers/input/fingerprint/elan_fp_qcom_tee.c
@@ -0,0 +1,697 @@
+#include <linux/module.h>
+#include <linux/input.h>
+#include <linux/input/mt.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/async.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/kthread.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+#include <linux/version.h>
+#include <linux/slab.h>
+#include <linux/wait.h>
+#include <linux/io.h>
+#include <linux/ioctl.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/syscalls.h>
+#include <linux/err.h>
+#include <linux/cdev.h>
+#include <linux/types.h>
+#include <linux/pm_wakeup.h> //#include <linux/wakelock.h>
+#include <linux/sched.h>
+#include <linux/mutex.h>
+#include <linux/pm.h>
+#include <linux/time.h>
+#include <linux/namei.h>
+#include <linux/mount.h>
+#include <linux/poll.h>
+#include <linux/of_gpio.h>
+#include "elan_fp_qcom_tee.h"
+
+#define VERSION_LOG	"2.2.1"
+
+static int elan_debug = 1;
+#define ELAN_DEBUG(format, args ...) \
+do { \
+    if (elan_debug) \
+        printk("[ELAN] " format, ##args); \
+    } while(0)
+
+#define KEY_FP_INT			KEY_POWER //KEY_WAKEUP // change by customer & framework support
+#define KEY_FP_INT2			KEY_1 // change by customer & framework support
+#define SET_SPI_OWNER       (0)
+#if SET_SPI_OWNER
+#include <soc/qcom/scm.h>
+#endif
+
+#if defined(CONFIG_FB)
+#include <linux/notifier.h>
+#include <linux/fb.h>
+#include <linux/signal.h>
+#endif
+
+static int factory_status = 0;
+static DEFINE_MUTEX(elan_factory_mutex);
+static DECLARE_WAIT_QUEUE_HEAD(elan_poll_wq);
+static int elan_work_flag = 0;
+#if defined(CONFIG_FB)
+static struct notifier_block fb_notif;
+static int pid_fp = -1;
+static int display_status = -1;
+#endif
+//[Z20][fingerprint][Kent][17111801][begin]add power gpio for vdd
+#define VDD_POWER_GPIO 1
+//[Z20][fingerprint][Kent][17111801][end]add power gpio for vdd
+struct elan_data  {
+	int 					int_gpio;
+	int						irq;
+	int 					rst_gpio;
+	int						irq_is_disable;
+	struct miscdevice		elan_dev;	/* char device for ioctl */
+	struct platform_device	*pdev;
+	struct input_dev		*input_dev;
+	spinlock_t				irq_lock;
+	struct wakeup_source	    wake_lock; //struct wake_lock		wake_lock;
+    struct wakeup_source        hal_wake_lock; //struct wake_lock	    hal_wake_lock;
+//[Z20][fingerprint][Kent][17111802][begin]add power gpio for vdd
+#if VDD_POWER_GPIO
+    int 					vdd_gpio;
+#endif
+//[Z20][fingerprint][Kent][17111802][end]add power gpio for vdd
+};
+
+void elan_irq_enable(void *_fp)
+{
+	struct elan_data *fp = _fp;
+	unsigned long irqflags = 0;
+	ELAN_DEBUG("IRQ Enable = %d.\n", fp->irq);
+
+	spin_lock_irqsave(&fp->irq_lock, irqflags);
+	if (fp->irq_is_disable)
+	{
+		enable_irq(fp->irq);
+		fp->irq_is_disable = 0;
+	}
+	spin_unlock_irqrestore(&fp->irq_lock, irqflags);
+}
+
+void elan_irq_disable(void *_fp)
+{
+	struct elan_data *fp = _fp;
+	unsigned long irqflags;
+	ELAN_DEBUG("IRQ Disable = %d.\n", fp->irq);
+
+	spin_lock_irqsave(&fp->irq_lock, irqflags);
+	if (!fp->irq_is_disable)
+	{
+		fp->irq_is_disable = 1;
+		disable_irq_nosync(fp->irq);
+	}
+	spin_unlock_irqrestore(&fp->irq_lock, irqflags);
+}
+
+static ssize_t show_drv_version_value(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	return sprintf(buf, "%s\n", VERSION_LOG);
+}
+static DEVICE_ATTR(drv_version, S_IRUGO, show_drv_version_value, NULL);
+
+static ssize_t elan_debug_value(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	if(elan_debug){
+		elan_debug=0;
+	} else {
+		elan_debug=1;
+	}
+	return sprintf(buf, "[ELAN] elan debug %d\n", elan_debug);
+}
+static DEVICE_ATTR(elan_debug, S_IRUGO, elan_debug_value, NULL);
+
+static struct attribute *elan_attributes[] = {
+	&dev_attr_drv_version.attr,
+	&dev_attr_elan_debug.attr,
+	NULL
+};
+
+static struct attribute_group elan_attr_group = {
+	.attrs = elan_attributes,
+};
+
+static void elan_reset(struct elan_data *fp)
+{
+	/* Developement platform */
+	gpio_set_value(fp->rst_gpio, 0);
+	mdelay(5);
+	gpio_set_value(fp->rst_gpio, 1);
+	mdelay(50);
+}
+
+#if defined(CONFIG_FB)
+
+static int send_sig_to_pid(int sig, pid_t pid)
+{
+    struct siginfo info;
+
+    info.si_signo = sig;
+    info.si_errno = 0;
+    info.si_code = SI_USER;
+    info.si_pid = get_current()->pid;
+    info.si_uid = from_kuid_munged(current_user_ns(), current_uid());
+
+    return kill_proc_info(sig, &info, pid);
+}
+
+static int fb_notifier_callback(struct notifier_block *self, unsigned long event, void *data)
+{
+    struct fb_event *evdata = data;
+    int *blank ;
+
+    //[Z20][fingerprint][180123begin]void fb system crash
+    if (event != 0x10)
+	return 0;
+    //[Z20][fingerprint][180123end]void fb system crash
+
+//[Z20][fingerprint][180123begin]check the null pointer
+    if(evdata == NULL)
+    {
+	pr_err("%s data is NULL\n",__func__);
+	return 0;
+    }
+    blank = evdata->data;
+    if(blank == NULL)
+    {
+	pr_err("%s blank is NULL\n",__func__);
+	return 0;
+    }
+//[Z20][fingerprint][180123end]check the null pointer
+    ELAN_DEBUG("%s fb notifier callback event = %lu, evdata->data = %d\n",__func__, event, *blank);
+    if (evdata && evdata->data) {
+        if (event == 0x10) {
+            if (*blank == FB_BLANK_UNBLANK) {
+                display_status = 0;
+                if(pid_fp != -1)
+                    send_sig_to_pid(SIGUSR2,pid_fp);
+                ELAN_DEBUG("Display On\n");
+            }
+            else if (*blank == FB_BLANK_POWERDOWN) {
+                display_status = 1;
+                if(pid_fp != -1)
+                    send_sig_to_pid(SIGUSR2,pid_fp);
+                ELAN_DEBUG("Display Off\n");
+            }
+        }
+    }
+    return 0;
+}
+#endif
+
+static long elan_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+{
+	struct elan_data *fp = filp->private_data;
+    int keycode;
+    int wake_lock_arg;
+
+	ELAN_DEBUG("%s() : cmd = [%04X]\n", __func__, cmd);
+
+	switch(cmd)
+	{
+		case ID_IOCTL_RESET: //6
+			elan_reset(fp);
+			ELAN_DEBUG("[IOCTL] RESET\n");
+			break;
+
+		case ID_IOCTL_POLL_INIT: //20
+            elan_work_flag = 0;
+			ELAN_DEBUG("[IOCTL] POLL INIT\n");
+			break;
+
+		case ID_IOCTL_POLL_EXIT: //23
+            elan_work_flag = 1;
+            wake_up(&elan_poll_wq);
+			ELAN_DEBUG("[IOCTL] POLL EXIT\n");
+			break;
+
+        case ID_IOCTL_INPUT_KEYCODE: //22
+			keycode =(int __user)arg;
+			ELAN_DEBUG("[IOCTL] KEYCODE DOWN & UP, keycode = %d \n", keycode);
+			if (!keycode) {
+				ELAN_DEBUG("Keycode %d not defined, ignored\n", (int __user)arg);
+				break ;
+			}
+			input_report_key(fp->input_dev, keycode, 1); // Added for KEY Event
+			input_sync(fp->input_dev);
+			input_report_key(fp->input_dev, keycode, 0); // Added for KEY Event
+			input_sync(fp->input_dev);
+			break;
+
+		case ID_IOCTL_SET_KEYCODE: //24
+			keycode =(int __user)arg;
+			ELAN_DEBUG("[IOCTL] SET KEYCODE, keycode = %d \n", keycode);
+			if (!keycode) {
+				ELAN_DEBUG("Keycode %d not defined, ignored\n", (int __user)arg);
+				break ;
+			}
+			input_set_capability(fp->input_dev, EV_KEY, keycode);
+			set_bit(keycode, fp->input_dev->keybit);
+			break;
+
+        case ID_IOCTL_INPUT_KEYCODE_DOWN: //28
+            keycode =(int __user)arg;
+            ELAN_DEBUG("[IOCTL] KEYCODE DOWN, keycode = %d \n", keycode);
+            if(!keycode) {
+                ELAN_DEBUG("Keycode %d not defined, ignored\n", (int __user)arg);
+				break ;
+            }
+            input_report_key(fp->input_dev, keycode, 1);
+			input_sync(fp->input_dev);
+            break;
+
+        case ID_IOCTL_INPUT_KEYCODE_UP: //29
+            keycode =(int __user)arg;
+            ELAN_DEBUG("[IOCTL] KEYCODE UP, keycode = %d \n", keycode);
+            if(!keycode) {
+                ELAN_DEBUG("Keycode %d not defined, ignored\n", (int __user)arg);
+				break ;
+            }
+            input_report_key(fp->input_dev, keycode, 0);
+			input_sync(fp->input_dev);
+            break;
+
+        case ID_IOCTL_READ_FACTORY_STATUS: //26
+            mutex_lock(&elan_factory_mutex);
+            ELAN_DEBUG("[IOCTL] READ factory_status = %d\n", factory_status);
+            mutex_unlock(&elan_factory_mutex);
+            return factory_status;
+            break;
+
+        case ID_IOCTL_WRITE_FACTORY_STATUS: //27
+            mutex_lock(&elan_factory_mutex);
+            factory_status = (int __user)arg;
+            ELAN_DEBUG("[IOCTL] WRITE factory_status = %d\n", factory_status);
+            mutex_unlock(&elan_factory_mutex);
+            break;
+
+        case ID_IOCTL_INT_STATUS: //40
+            return gpio_get_value(fp->int_gpio);
+
+        case ID_IOCTL_WAKE_LOCK_UNLOCK: //41
+            wake_lock_arg = (int __user)arg;
+            if(!wake_lock_arg)
+            {
+                __pm_relax(&fp->hal_wake_lock); //wake_unlock(&fp->hal_wake_lock);
+                ELAN_DEBUG("[IOCTL] HAL WAKE UNLOCK = %d\n", wake_lock_arg);
+            }
+            else if(wake_lock_arg)
+            {
+                __pm_stay_awake(&fp->hal_wake_lock); //wake_lock(&fp->hal_wake_lock);
+                ELAN_DEBUG("[IOCTL] HAL WAKE LOCK = %d\n", wake_lock_arg);
+            }
+            else
+                ELAN_DEBUG("[IOCTL] ERROR WAKE LOCK ARGUMENT\n");
+            break;
+
+		case ID_IOCTL_EN_IRQ: //55
+			elan_irq_enable(fp);
+			ELAN_DEBUG("[IOCTL] ENABLE IRQ\n");
+			break;
+
+		case ID_IOCTL_DIS_IRQ: //66
+			elan_irq_disable(fp);
+			ELAN_DEBUG("[IOCTL] DISABLE IRQ\n");
+			break;
+
+        case ID_IOCTL_SET_IRQ_TYPE: //91
+            ELAN_DEBUG("[IOCTL] SET IRQ TYPE\n");
+            irq_set_irq_type(fp->irq, IRQF_TRIGGER_FALLING | IRQF_NO_SUSPEND | IRQF_ONESHOT);
+            break;
+
+        case ID_IOCTL_DISPLAY_STATUS: //93
+            ELAN_DEBUG("[IOCTL] DISPLAY_STATUS = %d\n", display_status);
+            return display_status;
+
+        case ID_IOCTL_DISPLAY_NOTIFY: //94
+            break;
+
+        case ID_IOCTL_SET_PID: //94
+            pid_fp = (int __user)arg;
+            ELAN_DEBUG("[IOCTL] ID_IOCTL_SET_PID = %d\n", pid_fp);
+            break;
+
+		default:
+			ELAN_DEBUG("INVALID COMMAND\n");
+			break;
+	}
+	return 0;
+}
+
+static unsigned int elan_poll(struct file *file, poll_table *wait)
+{
+	int mask=0;
+    ELAN_DEBUG("%s()\n",__func__);
+
+	wait_event_interruptible(elan_poll_wq, elan_work_flag > 0);
+	if(elan_work_flag > 0)
+		mask = elan_work_flag;
+
+	elan_work_flag = 0;
+	return mask;
+}
+
+static int elan_open(struct inode *inode, struct file *filp)
+{
+	struct elan_data *fp = container_of(filp->private_data, struct elan_data, elan_dev);
+	filp->private_data = fp;
+	ELAN_DEBUG("%s()\n", __func__);
+	return 0;
+}
+
+static int elan_close(struct inode *inode, struct file *filp)
+{
+	ELAN_DEBUG("%s()\n", __func__);
+	return 0;
+}
+
+static const struct file_operations elan_fops = {
+	.owner 			= THIS_MODULE,
+	.open 			= elan_open,
+	.unlocked_ioctl = elan_ioctl,
+	.poll			= elan_poll,
+	.release 		= elan_close,
+};
+
+#if SET_SPI_OWNER
+static int set_pipe_ownership(void)
+{
+	const u32 TZ_BLSP_MODIFY_OWNERSHIP_ID = 3;
+	const u32 TZBSP_TZ_ID = 3;
+	int rc;
+	struct scm_desc desc = {
+		.arginfo = SCM_ARGS(2),
+		.args[0] = 3,
+		.args[1] = TZBSP_TZ_ID,
+	};
+
+	rc = scm_call2(SCM_SIP_FNID(SCM_SVC_TZ, TZ_BLSP_MODIFY_OWNERSHIP_ID), &desc);
+
+	if(rc || desc.ret[0])
+	{
+		ELAN_DEBUG("%s() FAIL\n", __func__);
+		return -EINVAL;
+	}
+	ELAN_DEBUG("%s() Success\n", __func__);
+	return 0;
+}
+#endif
+
+static irqreturn_t elan_irq_handler(int irq, void *dev_id)
+{
+	struct elan_data *fp = (struct elan_data *)dev_id;
+
+	ELAN_DEBUG("%s()\n", __func__);
+	__pm_wakeup_event(&fp->wake_lock, msecs_to_jiffies(1000)); //wake_lock_timeout(&fp->wake_lock, msecs_to_jiffies(1000));
+    if(fp == NULL)
+		return IRQ_NONE;
+    elan_work_flag = 1;
+    wake_up(&elan_poll_wq);
+
+	return IRQ_HANDLED;
+}
+
+static int elan_setup_cdev(struct elan_data *fp)
+{
+
+	fp->elan_dev.minor = MISC_DYNAMIC_MINOR;
+	fp->elan_dev.name = "elan_fp";
+	fp->elan_dev.fops = &elan_fops;
+	fp->elan_dev.mode = S_IFREG|S_IRWXUGO;
+	if (misc_register(&fp->elan_dev) < 0) {
+		ELAN_DEBUG("misc_register failed\n");
+		return -1;
+	}
+	else {
+		ELAN_DEBUG("misc_register finished\n");
+	}
+	return 0;
+}
+
+static int elan_sysfs_create(struct elan_data *sysfs)
+{
+	struct elan_data *fp = platform_get_drvdata(sysfs->pdev);
+	int ret = 0;
+
+	/* Register sysfs */
+	ret = sysfs_create_group(&fp->pdev->dev.kobj, &elan_attr_group);
+	if (ret) {
+		ELAN_DEBUG("create sysfs attributes failed, ret = %d\n", ret);
+		goto fail_un;
+	}
+	return 0;
+fail_un:
+	/* Remove sysfs */
+	sysfs_remove_group(&fp->pdev->dev.kobj, &elan_attr_group);
+
+	return ret;
+}
+
+static int elan_gpio_config(struct elan_data *fp)
+{
+	int ret = 0;
+
+    // Configure INT GPIO (Input)
+	ret = gpio_request(fp->int_gpio, "elan-irq");
+	if (ret < 0)
+		ELAN_DEBUG("interrupt pin request gpio failed, ret = %d\n", ret);
+	else {
+		gpio_direction_input(fp->int_gpio);
+		fp->irq = gpio_to_irq(fp->int_gpio);
+        if(fp->irq < 0) {
+            ELAN_DEBUG("gpio to irq failed, irq = %d\n", fp->irq);
+            ret = -1;
+        }
+        else
+            ELAN_DEBUG("gpio to irq success, irq = %d\n",fp->irq);
+	}
+
+	// Configure RST GPIO (Output)
+	ret =  gpio_request(fp->rst_gpio, "elan-rst");
+	if (ret < 0) {
+		gpio_free(fp->int_gpio);
+		free_irq(fp->irq, fp);
+		ELAN_DEBUG("reset pin request gpio failed, ret = %d\n", ret);
+	}
+	else
+        gpio_direction_output(fp->rst_gpio, 1);
+//[Z20][fingerprint][Kent][17111803][begin]add power gpio for vdd
+#if VDD_POWER_GPIO
+	// Configure VDD GPIO (Output)
+	ret =  gpio_request(fp->vdd_gpio, "elan-vdd");
+	if (ret < 0) {
+		gpio_free(fp->rst_gpio);
+		gpio_free(fp->int_gpio);
+		free_irq(fp->irq, fp);
+		ELAN_DEBUG("reset pin request gpio failed, ret = %d\n", ret);
+	}
+	else
+        gpio_direction_output(fp->vdd_gpio, 1);
+#endif
+//[Z20][fingerprint][Kent][17111803][end]add power gpio for vdd
+	return ret;
+}
+
+static int elan_dts_init(struct elan_data *fp, struct device_node *np)
+{
+	fp->rst_gpio = of_get_named_gpio(np, "elan,rst-gpio", 0);
+	ELAN_DEBUG("rst_gpio = %d\n", fp->rst_gpio);
+	if (fp->rst_gpio < 0)
+		return fp->rst_gpio;
+
+	fp->int_gpio = of_get_named_gpio(np, "elan,irq-gpio", 0);
+	ELAN_DEBUG("int_gpio = %d\n", fp->int_gpio);
+	if (fp->int_gpio < 0)
+		return fp->int_gpio;
+//[Z20][fingerprint][Kent][17111804][begin]add power gpio for vdd
+#if VDD_POWER_GPIO
+	fp->vdd_gpio = of_get_named_gpio(np, "elan,vdd-gpio", 0);
+		ELAN_DEBUG("vdd_gpio = %d\n", fp->vdd_gpio);
+		if (fp->vdd_gpio < 0)
+			return fp->vdd_gpio;
+#endif
+//[Z20][fingerprint][Kent][17111804][end]add power gpio for vdd
+    return 0;
+}
+
+static int elan_probe(struct platform_device *pdev)
+{
+	struct elan_data *fp = NULL;
+	struct input_dev *input_dev = NULL;
+	int ret = 0;
+
+	ELAN_DEBUG("%s(), version = %s\n", __func__, VERSION_LOG);
+
+	/* Allocate Device Data */
+	fp = devm_kzalloc(&pdev->dev, sizeof(struct elan_data), GFP_KERNEL);
+	if(!fp)
+		ELAN_DEBUG("kzmalloc elan data failed\n");
+
+	/* Init Input Device */
+	input_dev = input_allocate_device();
+	if (!input_dev)
+		ELAN_DEBUG("alloc input_dev failed\n");
+
+	fp->pdev = pdev;
+
+	platform_set_drvdata(pdev, fp);
+
+	input_dev->name = "elan";
+	input_dev->id.bustype = BUS_SPI;
+	input_dev->dev.parent = &pdev->dev;
+	input_set_drvdata(input_dev, fp);
+
+	input_dev->evbit[0] = BIT_MASK(EV_SYN) | BIT_MASK(EV_KEY);
+	input_set_capability(input_dev, EV_KEY, KEY_FP_INT); // change by customer, send key event to framework. KEY_xxx could be changed.
+	input_set_capability(input_dev, EV_KEY, KEY_FP_INT2); // change by customer, send key event to framework. KEY_xxx could be changed.
+
+	fp->input_dev = input_dev;
+
+	/* Init Sysfs */
+	ret = elan_sysfs_create(fp);
+	if(ret < 0)
+		ELAN_DEBUG("sysfs create failed, ret = %d\n", ret);
+
+	/* Init Char Device */
+	ret = elan_setup_cdev(fp);
+	if(ret < 0)
+		ELAN_DEBUG("setup device failed, ret = %d\n", ret);
+
+	/* Register Input Device */
+	ret = input_register_device(input_dev);
+	if(ret)
+		ELAN_DEBUG("register input device failed, ret = %d\n", ret);
+
+    ret = elan_dts_init(fp, pdev->dev.of_node);
+    if(ret < 0)
+		ELAN_DEBUG("device tree initial failed, ret = %d\n", ret);
+
+	ret = elan_gpio_config(fp);
+	if(ret < 0)
+		ELAN_DEBUG("gpio config failed, ret = %d\n", ret);
+
+    wakeup_source_init(&fp->wake_lock, "fp_wake_lock"); //wake_lock_init(&fp->wake_lock, WAKE_LOCK_SUSPEND, "fp_wake_lock");
+    wakeup_source_init(&fp->hal_wake_lock, "hal_fp_wake_lock"); //wake_lock_init(&fp->hal_wake_lock, WAKE_LOCK_SUSPEND, "hal_fp_wake_lock");
+
+	ret = request_irq(fp->irq, elan_irq_handler,
+			IRQF_NO_SUSPEND | IRQF_TRIGGER_RISING | IRQF_ONESHOT,
+			pdev->dev.driver->name, fp);
+	if(ret)
+		ELAN_DEBUG("request irq failed, ret = %d\n", ret);
+
+	irq_set_irq_wake(fp->irq, 1);
+
+	spin_lock_init(&fp->irq_lock);
+
+#if defined(CONFIG_FB)
+	fb_notif.notifier_call = fb_notifier_callback;
+	fb_register_client(&fb_notif);
+#endif
+
+	/* Set Spi to TZ */
+#if SET_SPI_OWNER
+	ret = set_pipe_ownership();
+#endif
+
+    ELAN_DEBUG("%s() End\n", __func__);
+	return 0;
+}
+
+static int elan_remove(struct platform_device *pdev)
+{
+	struct elan_data *fp = platform_get_drvdata(pdev);
+
+	if (fp->irq)
+		free_irq(fp->irq, fp);
+//[Z20][fingerprint][Kent][17111805][begin]add power gpio for vdd
+#if VDD_POWER_GPIO
+	gpio_free(fp->vdd_gpio);
+#endif
+//[Z20][fingerprint][Kent][17111805][end]add power gpio for vdd
+	gpio_free(fp->int_gpio);
+	gpio_free(fp->rst_gpio);
+
+	misc_deregister(&fp->elan_dev);
+	input_free_device(fp->input_dev);
+
+#if defined(CONFIG_FB)
+	fb_unregister_client(&fb_notif);
+#endif
+
+	kfree(fp);
+
+	platform_set_drvdata(pdev, NULL);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int elan_suspend(struct device *dev)
+{
+	ELAN_DEBUG("elan suspend!\n");
+	return 0;
+}
+
+static int elan_resume(struct device *dev)
+{
+	ELAN_DEBUG("elan resume!\n");
+	return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(elan_pm_ops, elan_suspend, elan_resume);
+
+#ifdef CONFIG_OF
+static struct of_device_id elan_metallica_table[] = {
+	{ .compatible = "elan,elan_fp",},
+	{ },
+};
+#else
+#define elan_metallica_table NULL
+#endif
+
+static struct platform_driver elan_driver = {
+	.driver = {
+		.name 	= "elan",
+		.owner = THIS_MODULE,
+		.pm 	= &elan_pm_ops,
+		.of_match_table = elan_metallica_table,
+	},
+	.probe 	= elan_probe,
+	.remove = elan_remove,
+};
+
+static int __init elan_init(void)
+{
+	int ret = 0;
+	ELAN_DEBUG("%s() Start\n", __func__);
+
+	ret = platform_driver_register(&elan_driver);
+	if(ret < 0)
+		ELAN_DEBUG("%s FAIL !\n", __func__);
+
+    ELAN_DEBUG("%s() End\n", __func__);
+	return 0;
+}
+
+static void __exit elan_exist(void)
+{
+	platform_driver_unregister(&elan_driver);
+}
+
+module_init(elan_init);
+module_exit(elan_exist);
+
+MODULE_AUTHOR("Elan");
+MODULE_DESCRIPTION("ELAN SPI FingerPrint driver");
+MODULE_VERSION(VERSION_LOG);
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/fingerprint/elan_fp_qcom_tee.h b/drivers/input/fingerprint/elan_fp_qcom_tee.h
new file mode 100644
index 0000000..1c6f9aa
--- /dev/null
+++ b/drivers/input/fingerprint/elan_fp_qcom_tee.h
@@ -0,0 +1,25 @@
+#ifndef _LINUX_ELAN_FP_H
+#define _LINUX_ELAN_FP_H
+
+#define FINGERPRINT_IOCTL               0x80
+#define ID_IOCTL_RESET                  _IOW(FINGERPRINT_IOCTL, 6,  int)
+#define ID_IOCTL_POLL_INIT              _IOW(FINGERPRINT_IOCTL, 20, int)
+#define ID_IOCTL_INPUT_KEYCODE          _IOW(FINGERPRINT_IOCTL, 22, int)
+#define ID_IOCTL_POLL_EXIT              _IOW(FINGERPRINT_IOCTL, 23, int)
+#define ID_IOCTL_SET_KEYCODE            _IOW(FINGERPRINT_IOCTL, 24, int)
+#define ID_IOCTL_READ_FACTORY_STATUS    _IOW(FINGERPRINT_IOCTL, 26, int)
+#define ID_IOCTL_WRITE_FACTORY_STATUS   _IOW(FINGERPRINT_IOCTL, 27, int)
+#define ID_IOCTL_INPUT_KEYCODE_DOWN     _IOW(FINGERPRINT_IOCTL, 28, int)
+#define ID_IOCTL_INPUT_KEYCODE_UP       _IOW(FINGERPRINT_IOCTL, 29, int)
+#define ID_IOCTL_INT_STATUS             _IOW(FINGERPRINT_IOCTL, 40, int)
+#define ID_IOCTL_WAKE_LOCK_UNLOCK	    _IOW(FINGERPRINT_IOCTL, 41, int)
+#define ID_IOCTL_EN_IRQ                 _IOW(FINGERPRINT_IOCTL, 55, int)
+#define ID_IOCTL_DIS_IRQ                _IOW(FINGERPRINT_IOCTL, 66, int)
+#define ID_IOCTL_SET_IRQ_TYPE           _IOW(FINGERPRINT_IOCTL, 91, int)
+#define ID_IOCTL_DISPLAY_STATUS         _IOW(FINGERPRINT_IOCTL, 93, int)
+#define ID_IOCTL_DISPLAY_NOTIFY         _IOW(FINGERPRINT_IOCTL, 94, int)
+#define ID_IOCTL_SET_PID                            _IOW(FINGERPRINT_IOCTL, 95, int)
+
+#define CUSTOMER_IOCTLID                0xD0 //For customer define
+
+#endif /* _LINUX_ELAN_FP_H */