[Feature]add MT2731_MP2_MR2_SVN388 baseline version

Change-Id: Ief04314834b31e27effab435d3ca8ba33b499059
diff --git a/src/kernel/modules/connectivity/gps_driver/Android.mk b/src/kernel/modules/connectivity/gps_driver/Android.mk
new file mode 100644
index 0000000..c2d822a
--- /dev/null
+++ b/src/kernel/modules/connectivity/gps_driver/Android.mk
@@ -0,0 +1,20 @@
+LOCAL_PATH := $(call my-dir)
+
+ifeq ($(MTK_GPS_SUPPORT), true)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := gps_drv.ko
+LOCAL_PROPRIETARY_MODULE := true
+LOCAL_MODULE_OWNER := mtk
+LOCAL_INIT_RC := init.gps_drv.rc
+
+ifeq ($(MTK_GPS_CHIP), MT3303)
+GPS_OPTS := CONFIG_MTK_CONN_MT3303_CHIP_SUPPORT=y
+include $(MTK_KERNEL_MODULE)
+$(linked_module): OPTS +=$(GPS_OPTS)
+else
+LOCAL_REQUIRED_MODULES := wmt_drv.ko
+include $(MTK_KERNEL_MODULE)
+endif
+
+endif
diff --git a/src/kernel/modules/connectivity/gps_driver/Makefile b/src/kernel/modules/connectivity/gps_driver/Makefile
new file mode 100644
index 0000000..1e607ef
--- /dev/null
+++ b/src/kernel/modules/connectivity/gps_driver/Makefile
@@ -0,0 +1,69 @@
+# drivers/barcelona/gps/Makefile
+#
+# Makefile for the Barcelona GPS driver.
+#
+# Copyright (C) 2004,2005 TomTom BV <http://www.tomtom.com/>
+# Author: Dimitry Andric <dimitry.andric@tomtom.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 as
+# published by the Free Software Foundation.
+
+MODULE_NAME := gps_drv
+EXTRA_SYMBOLS = ${TOPDIR}/tmp/work/${PACKAGE_ARCH}${TARGET_VENDOR}-${TARGET_OS}/mt66xx-wmt-drv/1.0-r0/mt66xx-wmt-drv-1.0/Module.symvers
+
+ccflags-y += -DSOC_CO_CLOCK_FLAG=1
+ccflags-y += -DWMT_CREATE_NODE_DYNAMIC=1
+ccflags-y += -DREMOVE_MK_NODE=0
+ccflags-y += \
+	-I$(CONNECTIVITY_SRC)/wmt_mt66xx/common_main/$(MTK_PLATFORM)/include \
+	-I$(srctree)/drivers/misc/mediatek/include/mt-plat \
+	-I$(srctree)/drivers/misc/mediatek/include/mt-plat/$(MTK_PLATFORM)/include/mach
+
+ccflags-y += \
+	-I$(CONNECTIVITY_SRC)/wmt_mt66xx/common_main/include \
+	-I$(CONNECTIVITY_SRC)/wmt_mt66xx/common_main/linux/include \
+	-I$(CONNECTIVITY_SRC)/wmt_mt66xx/common_main/core/include \
+	-I$(CONNECTIVITY_SRC)/wmt_mt66xx/common_main/platform/include
+
+WMT_SRC_FOLDER := $(TOP)/vendor/mediatek/kernel_modules/connectivity/common
+ccflags-y += \
+	-I$(WMT_SRC_FOLDER)/common_main/include \
+	-I$(WMT_SRC_FOLDER)/common_main/linux/include \
+	-I$(WMT_SRC_FOLDER)/common_main/core/include \
+	-I$(WMT_SRC_FOLDER)/common_main/platform/include \
+	-I$(srctree)/drivers/misc/mediatek/include/mt-plat
+
+ccflags-y += -D MTK_WCN_WMT_STP_EXP_SYMBOL_ABSTRACT
+
+ifeq ($(CONFIG_MTK_CONN_LTE_IDC_SUPPORT),y)
+    ccflags-y += -D WMT_IDC_SUPPORT=1
+else
+    ccflags-y += -D WMT_IDC_SUPPORT=0
+endif
+
+ifeq ($(CONFIG_WLAN_DRV_BUILD_IN),y)
+$(warning $(MODULE_NAME) build-in boot.img)
+obj-y += $(MODULE_NAME).o
+else
+$(warning $(MODULE_NAME) is kernel module)
+obj-m += $(MODULE_NAME).o
+endif
+
+ifeq ($(CONFIG_MTK_CONN_MT3303_CHIP_SUPPORT),y)
+        ccflags-y += -D CONFIG_MTK_GPS_SUPPORT
+        $(MODULE_NAME)-objs += gps.o
+else
+ifeq ($(PLATFORM),2731_YOCTO_33xx)
+        ccflags-y += -D CONFIG_MTK_GPS_SUPPORT
+        $(MODULE_NAME)-objs += gps.o
+else
+        $(MODULE_NAME)-objs += stp_chrdev_gps.o
+endif
+endif
+
+ifneq ($(CONFIG_MTK_GPS_EMI),)
+$(MODULE_NAME)-objs += gps_emi.o
+endif
+
+# EOF
diff --git a/src/kernel/modules/connectivity/gps_driver/Makefile.ce b/src/kernel/modules/connectivity/gps_driver/Makefile.ce
new file mode 100644
index 0000000..c37b0b8
--- /dev/null
+++ b/src/kernel/modules/connectivity/gps_driver/Makefile.ce
@@ -0,0 +1,32 @@
+# Makefile for MT66xx/MT33xx gps driver
+
+##############################################################
+# Common settings
+##############################################################
+
+
+##############################################################
+# Platform specific
+##############################################################
+
+
+##############################################################
+# Compile settings
+##############################################################
+
+all: driver
+
+driver:
+	+cd $(DRIVER_DIR) && make -C $(LINUX_SRC) M=$(DRIVER_DIR) MODULE_NAME=$(MODULE_NAME) PLATFORM_FLAGS="$(PLATFORM_FLAGS)" PLATFORM=${PLATFORM}  modules
+
+
+clean: driver_clean
+
+
+driver_clean:
+	cd $(DRIVER_DIR) && make -C $(LINUX_SRC) M=$(DRIVER_DIR) MODULE_NAME=$(MODULE_NAME) clean
+	if [ -e $(DRIVER_DIR)/$(MODULE_NAME).ko ]; then rm $(DRIVER_DIR)/$(MODULE_NAME).ko; fi;
+
+
+.PHONY: all clean driver driver_clean
+
diff --git a/src/kernel/modules/connectivity/gps_driver/gps.c b/src/kernel/modules/connectivity/gps_driver/gps.c
new file mode 100644
index 0000000..2a0be3c
--- /dev/null
+++ b/src/kernel/modules/connectivity/gps_driver/gps.c
@@ -0,0 +1,1291 @@
+ /*
+  * Copyright (C) 2011-2014 MediaTek Inc.
+  *
+  * This program is free software: you can redistribute it and/or modify it
+  * under the terms of the GNU General Public License version 2 as
+  * published by the Free Software Foundation.
+  *
+  * This program is distributed in the hope that it will be useful,
+  * but WITHOUT ANY WARRANTY; without even the implied warranty of
+  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+  * See the GNU General Public License for more details.
+  *
+  * You should have received a copy of the GNU General Public License along
+  * with this program. If not, see <http://www.gnu.org/licenses/>.
+  */
+
+/******************************************************************************
+ * Dependency
+ ******************************************************************************/
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/wait.h>
+#include <linux/slab.h>
+#include <linux/fs.h>
+#include <linux/sched/signal.h>
+#include <linux/poll.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/of.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/cdev.h>
+#include <linux/errno.h>
+#include <linux/io.h>
+#include <linux/uaccess.h>
+/* #include <linux/xlog.h> */
+#include <linux/printk.h>
+#include <linux/semaphore.h>
+#include <linux/version.h>
+#include <linux/regulator/consumer.h>
+
+static int antSwitchFlag;
+static struct regulator *vmch_reg;
+
+#ifdef pr_fmt
+#undef pr_fmt
+#endif
+#define pr_fmt(fmt) "["KBUILD_MODNAME"]" fmt
+
+/******************************************************************************
+ * Function Configuration
+ ******************************************************************************/
+/* #define FAKE_DATA */
+#define GPS_SUSPEND_RESUME
+#define GPS_CONFIGURABLE_RESET_DELAY
+/******************************************************************************
+ * Definition
+ ******************************************************************************/
+/* device name and major number */
+#define GPS_DEVNAME            "gps"
+/******************************************************************************
+ * structure & enumeration
+ ******************************************************************************/
+enum {
+	GPS_PWRCTL_UNSUPPORTED = 0xFF,
+	GPS_PWRCTL_OFF = 0x00,
+	GPS_PWRCTL_ON = 0x01,
+	GPS_PWRCTL_RST = 0x02,
+	GPS_PWRCTL_OFF_FORCE = 0x03,
+	GPS_PWRCTL_RST_FORCE = 0x04,
+	GPS_PWRCTL_MAX = 0x05,
+};
+enum {
+	GPS_PWR_UNSUPPORTED = 0xFF,
+	GPS_PWR_RESUME = 0x00,
+	GPS_PWR_SUSPEND = 0x01,
+	GPS_PWR_MAX = 0x02,
+};
+enum {
+	GPS_STATE_UNSUPPORTED = 0xFF,
+	GPS_STATE_OFF = 0x00,	/*cleanup/power off, default state */
+	GPS_STATE_INIT = 0x01,	/*init */
+	GPS_STATE_START = 0x02,	/*start navigating */
+	GPS_STATE_STOP = 0x03,	/*stop navigating */
+	GPS_STATE_DEC_FREQ = 0x04,
+	GPS_STATE_SLEEP = 0x05,
+	GPS_STATE_MAX = 0x06,
+};
+enum {
+	GPS_PWRSAVE_UNSUPPORTED = 0xFF,
+	GPS_PWRSAVE_DEC_FREQ = 0x00,
+	GPS_PWRSAVE_SLEEP = 0x01,
+	GPS_PWRSAVE_OFF = 0x02,
+	GPS_PWRSAVE_MAX = 0x03,
+};
+/*---------------------------------------------------------------------------*/
+struct gps_data {
+	int dat_len;
+	int dat_pos;
+	char dat_buf[4096];
+	spinlock_t lock;
+	wait_queue_head_t read_wait;
+	struct semaphore sem;
+};
+/*---------------------------------------------------------------------------*/
+struct gps_sta_itm {		/*gps status record */
+	unsigned char year;	/*current year - 1900 */
+	unsigned char month;	/*1~12 */
+	unsigned char day;	/*1~31 */
+	unsigned char hour;	/*0~23 */
+
+	unsigned char minute;	/*0~59 */
+	unsigned char sec;	/*0~59 */
+	unsigned char count;	/*reborn count */
+	unsigned char reason;	/*reason: 0: timeout; 1: force */
+};
+/*---------------------------------------------------------------------------*/
+struct gps_sta_obj {
+	int index;
+	struct gps_sta_itm items[32];
+};
+/*---------------------------------------------------------------------------*/
+struct gps_drv_obj {
+	unsigned char pwrctl;
+	unsigned char suspend;
+	unsigned char state;
+	unsigned char pwrsave;
+	int rdelay;		/*power reset delay */
+	struct kobject *kobj;
+	struct mutex sem;
+	struct gps_sta_obj status;
+	struct mt3326_gps_hardware *hw;
+};
+/*---------------------------------------------------------------------------*/
+struct gps_dev_obj {
+	struct class *cls;
+	struct device *dev;
+	dev_t devno;
+	struct cdev chdev;
+	struct mt3326_gps_hardware *hw;
+};
+/******************************************************************************
+ * GPS driver
+ ******************************************************************************/
+#ifdef CONFIG_OF
+static void mt3303_gps_get_dts_data(void);
+#endif
+static int mt3303_power_on(struct regulator *, int state);
+static int mt3303_power_off(struct regulator *, int state);
+
+struct mt3326_gps_hardware {
+	int (*ext_power_on)(struct regulator *, int);
+	int (*ext_power_off)(struct regulator *, int);
+	struct regulator *reg_id;
+};
+
+static struct mt3326_gps_hardware mt3326_gps_hw = {
+	.ext_power_on =  mt3303_power_on,
+	.ext_power_off = mt3303_power_off,
+};
+
+#define min_uV 3300000
+#define max_uV 3500000
+/******************************************************************************
+ * local variables
+ ******************************************************************************/
+static struct gps_data gps_private = { 0 };
+
+#if defined(FAKE_DATA)
+static char fake_data[] = {
+"$GPGGA,135036.000,2446.3713,N,12101.3605,E,1,5,1.61,191.1,M,15.1,M,,*51\r\n"
+"$GPGSA,A,3,22,18,14,30,31,,,,,,,,1.88,1.61,0.98*09\r\n"
+"$GPGSV,2,1,6,18,83,106,32,22,58,324,35,30,45,157,35,14,28,308,32*44\r\n"
+"$GPGSV,2,2,6,40,21,254,,31,17,237,29*42\r\n"
+"$GPRMC,135036.000,A,2446.37125,N,12101.36054,E,0.243,56.48,140109,,A*46\r\n"
+"$GPVTG,56.48,T,,M,0.243,N,0.451,K,A*07\r\n"
+};
+#endif /* FAKE_DATA */
+
+/*
+ * this should be synchronous with mnld.c
+ * enum {
+ *     MNL_RESTART_NONE            = 0x00, //recording the 1st of mnld
+ *     MNL_RESTART_TIMEOUT_INIT    = 0x01, //restart due to timeout
+ *     MNL_RESTART_TIMEOUT_MONITOR = 0x02, //restart due to timeout
+ *     MNL_RESTART_TIMEOUT_WAKEUP  = 0x03, //restart due to timeout
+ *     MNL_RESTART_TIMEOUT_TTFF    = 0x04, //restart due to TTFF timeout
+ *     MNL_RESTART_FORCE           = 0x04, //restart due to external command
+ * };
+ */
+/*---------------------------------------------------------------------------*/
+static char *str_reason[] = {
+	"none",
+	"init",
+	"monitor",
+	"wakeup",
+	"TTFF",
+	"force",
+	"unknown"
+};
+
+/******************************************************************************
+ * Functions
+ ******************************************************************************/
+static inline void mt3326_gps_power(struct mt3326_gps_hardware *hw,
+		unsigned int on, unsigned int force)
+{
+	/*FIX ME: PM_api should provide a function to get current status */
+	static unsigned int power_on = 1;
+	int err;
+
+	pr_info("Switching GPS device %s\n", (on != 0U) ? "on" : "off");
+
+	if (hw == NULL) {
+		pr_debug("null pointer!!\n");
+		return;
+	}
+
+	if (power_on == on) {
+		pr_info("ignore power control: %d\n", on);
+	} else if (on != 0U) {
+		(void)pr_info("power on: %d\n", on);
+		/*power on */
+		if (hw->ext_power_on != NULL) {
+			err = hw->ext_power_on(hw->reg_id, 0);
+			if (err != 0)
+				(void)pr_info("ext_power_on fail\n");
+		}
+		if (hw->ext_power_on != NULL) {
+			err = hw->ext_power_on(hw->reg_id, 1);
+			if (err != 0)
+				(void)pr_info("ext_power_on fail\n");
+		}
+		mdelay(120UL);
+	} else {
+		pr_info("power off: %d\n", on);
+		if (hw->ext_power_off != NULL) {
+			err = hw->ext_power_off(hw->reg_id, force);
+			if (err != 0)
+				(void)pr_info("ext_power_off fail\n");
+		}
+		pr_info("power off ok: %d\n", on);
+	}
+	power_on = on;
+}
+
+/*****************************************************************************/
+static inline void mt3326_gps_reset(struct mt3326_gps_hardware *hw,
+		int delay, int force)
+{
+	mt3326_gps_power(hw, 1, 0);
+	mdelay((unsigned long)delay);
+	mt3326_gps_power(hw, 0, (unsigned int)force);
+	mdelay((unsigned long)delay);
+	mt3326_gps_power(hw, 1, 0);
+}
+
+/******************************************************************************/
+static inline int mt3326_gps_set_suspend(struct gps_drv_obj *obj,
+		unsigned char suspend)
+{
+	if (obj == NULL)
+		return -1;
+	mutex_lock(&obj->sem);
+	if (obj->suspend != suspend) {
+		pr_debug("issue sysfs_notify : %p\n", obj->kobj->sd);
+		sysfs_notify(obj->kobj, NULL, "suspend");
+	}
+	obj->suspend = suspend;
+	mutex_unlock(&obj->sem);
+	return 0;
+}
+
+/******************************************************************************/
+static inline int mt3326_gps_set_pwrctl(struct gps_drv_obj *obj,
+		unsigned char pwrctl)
+{
+	int err = 0;
+
+	if (obj == NULL)
+		return -1;
+	mutex_lock(&obj->sem);
+
+	if ((pwrctl == (unsigned char)GPS_PWRCTL_ON) ||
+		(pwrctl == (unsigned char)GPS_PWRCTL_OFF)) {
+		obj->pwrctl = pwrctl;
+		mt3326_gps_power(obj->hw, pwrctl, 0);
+	} else if (pwrctl == (unsigned char)GPS_PWRCTL_OFF_FORCE) {
+		obj->pwrctl = pwrctl;
+		mt3326_gps_power(obj->hw, pwrctl, 1);
+	} else if (pwrctl == (unsigned char)GPS_PWRCTL_RST) {
+		mt3326_gps_reset(obj->hw, obj->rdelay, 0);
+		obj->pwrctl = (unsigned char)GPS_PWRCTL_ON;
+	} else if (pwrctl == (unsigned char)GPS_PWRCTL_RST_FORCE) {
+		mt3326_gps_reset(obj->hw, obj->rdelay, 1);
+		obj->pwrctl = (unsigned char)GPS_PWRCTL_ON;
+	} else {
+		err = -1;
+	}
+	mutex_unlock(&obj->sem);
+	return err;
+}
+
+/******************************************************************************/
+static inline int mt3326_gps_set_status(struct gps_drv_obj *obj,
+		const char *buf, size_t count)
+{
+	int err = 0;
+	int year, mon, day, hour, minute, sec, cnt, reason, idx;
+
+	if (obj == NULL)
+		return -1;
+
+	mutex_lock(&obj->sem);
+	if (sscanf(buf, "(%d/%d/%d %d:%d:%d) - %d/%d", &year, &mon, &day,
+			&hour, &minute, &sec, &cnt, &reason) == 8) {
+		int number = (int)ARRAY_SIZE(obj->status.items);
+
+		idx = obj->status.index % number;
+		obj->status.items[idx].year = (unsigned char)year;
+		obj->status.items[idx].month = (unsigned char)mon;
+		obj->status.items[idx].day = (unsigned char)day;
+		obj->status.items[idx].hour = (unsigned char)hour;
+		obj->status.items[idx].minute = (unsigned char)minute;
+		obj->status.items[idx].sec = (unsigned char)sec;
+		obj->status.items[idx].count = (unsigned char)cnt;
+		obj->status.items[idx].reason = (unsigned char)reason;
+		obj->status.index++;
+	} else {
+		err = -1;
+	}
+	mutex_unlock(&obj->sem);
+	return err;
+}
+
+/******************************************************************************/
+static inline int mt3326_gps_set_state(struct gps_drv_obj *obj,
+		unsigned char state)
+{
+	int err = 0;
+
+	if (obj == NULL)
+		return -1;
+	mutex_lock(&obj->sem);
+	if (state < (unsigned char)GPS_STATE_MAX)
+		obj->state = state;
+	else
+		err = -1;
+	mutex_unlock(&obj->sem);
+	return err;
+}
+
+/******************************************************************************/
+static inline int mt3326_gps_set_pwrsave(struct gps_drv_obj *obj,
+		unsigned char pwrsave)
+{
+	int err = 0;
+
+	if (obj == NULL)
+		return -1;
+	mutex_lock(&obj->sem);
+	if (pwrsave < (unsigned char)GPS_PWRSAVE_MAX)
+		obj->pwrsave = pwrsave;
+	else
+		err = -1;
+	mutex_unlock(&obj->sem);
+	return err;
+}
+
+/******************************************************************************/
+static inline int mt3326_gps_dev_suspend(struct gps_drv_obj *obj)
+{
+#if defined(GPS_SUSPEND_RESUME)
+	int err;
+
+	err = mt3326_gps_set_suspend(obj, GPS_PWR_SUSPEND);
+	if (err != 0)
+		pr_debug("set suspend fail: %d\n", err);
+	err = mt3326_gps_set_pwrctl(obj, GPS_PWRCTL_OFF);
+	if (err != 0)
+		pr_debug("set pwrctl fail: %d\n", err);
+	return err;
+#endif
+}
+
+/******************************************************************************/
+static inline int mt3326_gps_dev_resume(struct gps_drv_obj *obj)
+{
+#if defined(GPS_SUSPEND_RESUME)
+	int err;
+
+	err = mt3326_gps_set_suspend(obj, GPS_PWR_RESUME);
+	if (err != 0)
+		pr_debug("set suspend fail: %d\n", err);
+	/*don't power on device automatically */
+	return err;
+#endif
+}
+
+/******************************************************************************/
+static ssize_t mt3326_show_pwrctl(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct gps_drv_obj *obj;
+	ssize_t res;
+
+	if (dev == NULL) {
+		pr_debug("dev is null!!\n");
+		return 0;
+	}
+	obj = (struct gps_drv_obj *)dev_get_drvdata(dev);
+	if (obj == NULL) {
+		pr_debug("drv data is null!!\n");
+		return 0;
+	}
+	mutex_lock(&obj->sem);
+	res = snprintf(buf, PAGE_SIZE, "%d\n", obj->pwrctl);
+	mutex_unlock(&obj->sem);
+	return res;
+}
+
+/******************************************************************************/
+static ssize_t mt3326_store_pwrctl(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t count)
+{
+	struct gps_drv_obj *obj;
+
+	if (dev == NULL) {
+		pr_debug("dev is null!!\n");
+		return 0;
+	}
+	obj = (struct gps_drv_obj *)dev_get_drvdata(dev);
+	if (obj == NULL) {
+		pr_debug("drv data is null!!\n");
+		return 0;
+	}
+	if ((count == (size_t)1) || ((count == (size_t)2)
+		&& (buf[1] == '\n')))	{
+		unsigned char pwrctl = (unsigned char)(buf[0] - '0');
+
+		if (mt3326_gps_set_pwrctl(obj, pwrctl) == 0)
+			return (ssize_t)count;
+	}
+	return (ssize_t)count;
+}
+
+/******************************************************************************/
+static ssize_t mt3326_show_suspend(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct gps_drv_obj *obj;
+	ssize_t res;
+
+	if (dev == NULL) {
+		pr_debug("dev is null!!\n");
+		return 0;
+	}
+	obj = (struct gps_drv_obj *)dev_get_drvdata(dev);
+	if (obj == NULL) {
+		pr_debug("drv data is null!!\n");
+		return 0;
+	}
+	mutex_lock(&obj->sem);
+	res = snprintf(buf, PAGE_SIZE, "%d\n", obj->suspend);
+	mutex_unlock(&obj->sem);
+	return res;
+}
+
+/******************************************************************************/
+static ssize_t mt3326_store_suspend(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t count)
+{
+	struct gps_drv_obj *obj;
+
+	if (dev == NULL) {
+		pr_debug("dev is null!!\n");
+		return 0;
+	}
+	obj = (struct gps_drv_obj *)dev_get_drvdata(dev);
+	if (obj == NULL) {
+		pr_debug("drv data is null!!\n");
+		return 0;
+	}
+	if ((count == (size_t)1) || ((count == (size_t)2)
+		&& (buf[1] == '\n'))) {
+		int suspend = buf[0] - '0';
+
+		if (suspend == GPS_PWR_SUSPEND) {
+			if (mt3326_gps_dev_suspend(obj) == 0)
+				return (ssize_t)count;
+		} else if (suspend == GPS_PWR_RESUME) {
+			if (mt3326_gps_dev_resume(obj) == 0)
+				return (ssize_t)count;
+		} else {
+			pr_debug("suspend value error: %d!!\n", suspend);
+			return 0;
+		}
+	}
+	return (ssize_t)count;
+}
+
+/******************************************************************************/
+static ssize_t mt3326_show_status(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	int res, idx, num, left, cnt, len;
+	struct gps_drv_obj *obj;
+	char *reason = NULL;
+	int reason_max = (int)ARRAY_SIZE(str_reason);
+
+	if (dev == NULL) {
+		pr_debug("dev is null!!\n");
+		return 0;
+	}
+	obj = (struct gps_drv_obj *)dev_get_drvdata(dev);
+	if (obj == NULL) {
+		pr_debug("drv data is null!!\n");
+		return 0;
+	}
+	mutex_lock(&obj->sem);
+	num = (int)ARRAY_SIZE(obj->status.items);
+	left = (int)PAGE_SIZE;
+	cnt = 0;
+	len = 0;
+	for (idx = 0; idx < num; idx++) {
+		if (obj->status.items[idx].month == 0)
+			continue;
+		if (obj->status.items[idx].reason >= reason_max)
+			reason = str_reason[reason_max - 1];
+		else
+			reason = str_reason[obj->status.items[idx].reason];
+		cnt = snprintf(&buf[len], left,
+			"[%d] %.4d/%.2d/%.2d %.2d:%.2d:%.2d - %d, %s\n",
+			idx, obj->status.items[idx].year + 1900,
+			obj->status.items[idx].month,
+			obj->status.items[idx].day,
+			obj->status.items[idx].hour,
+			obj->status.items[idx].minute,
+			obj->status.items[idx].sec,
+			obj->status.items[idx].count, reason);
+		left -= cnt;
+		len += cnt;
+	}
+	res = PAGE_SIZE - left;
+	mutex_unlock(&obj->sem);
+	return res;
+}
+
+/******************************************************************************/
+static ssize_t mt3326_store_status(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t count)
+{
+	int res = 0;
+	struct gps_drv_obj *obj;
+
+	if (dev == NULL) {
+		pr_debug("dev is null!!\n");
+		return 0;
+	}
+	obj = (struct gps_drv_obj *)dev_get_drvdata(dev);
+	if (obj == NULL) {
+		pr_debug("drv data is null!!\n");
+		return 0;
+	}
+	res = mt3326_gps_set_status(obj, buf, count);
+	if (res == 0)
+		return (ssize_t)count;
+
+	pr_debug("invalid content: '%p', length = %zu\n", buf, count);
+	return (ssize_t)count;
+}
+
+/******************************************************************************/
+static ssize_t mt3326_show_state(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	ssize_t res;
+	struct gps_drv_obj *obj;
+
+	if (dev == NULL) {
+		pr_debug("dev is null!!\n");
+		return 0;
+	}
+	obj = (struct gps_drv_obj *)dev_get_drvdata(dev);
+	if (obj == NULL) {
+		pr_debug("drv data is null!!\n");
+		return 0;
+	}
+	mutex_lock(&obj->sem);
+	res = snprintf(buf, PAGE_SIZE, "%d\n", obj->state);
+	mutex_unlock(&obj->sem);
+	return res;
+}
+
+/******************************************************************************/
+static ssize_t mt3326_store_state(struct device *dev,
+	struct device_attribute *attr, const char *buf, size_t count)
+{
+	struct gps_drv_obj *obj;
+
+	if (dev == NULL) {
+		pr_debug("dev is null!!\n");
+		return 0;
+	}
+	obj = (struct gps_drv_obj *)dev_get_drvdata(dev);
+	if (obj == NULL) {
+		pr_debug("drv data is null!!\n");
+		return 0;
+	}
+	if ((count == (size_t)1) || ((count == (size_t)2) &&
+		(buf[1] == '\n'))) {
+	/*To Do: dynamic change according to input */
+		unsigned char state = (unsigned char)(buf[0] - '0');
+
+		if (mt3326_gps_set_state(obj, state) == 0)
+			return (ssize_t)count;
+	}
+	pr_debug("invalid content: '%p', length = %zu\n", buf, count);
+	return (ssize_t)count;
+}
+
+/******************************************************************************/
+static ssize_t mt3326_show_pwrsave(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	ssize_t res;
+	struct gps_drv_obj *obj;
+
+	if (dev == NULL) {
+		pr_debug("dev is null!!\n");
+		return 0;
+	}
+	obj = (struct gps_drv_obj *)dev_get_drvdata(dev);
+	if (obj == NULL) {
+		pr_debug("drv data is null!!\n");
+		return 0;
+	}
+	mutex_lock(&obj->sem);
+	res = snprintf(buf, PAGE_SIZE, "%d\n", obj->pwrsave);
+	mutex_unlock(&obj->sem);
+	return res;
+}
+
+/******************************************************************************/
+static ssize_t mt3326_store_pwrsave(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t count)
+{
+	struct gps_drv_obj *obj;
+
+	if (dev == NULL) {
+		pr_debug("dev is null!!\n");
+		return 0;
+	}
+	obj = (struct gps_drv_obj *)dev_get_drvdata(dev);
+	if (obj == NULL) {
+		pr_debug("drv data is null!!\n");
+		return 0;
+	}
+	if ((count == (size_t)1) || ((count == (size_t)2) &&
+		(buf[1] == '\n')))	{
+		unsigned char pwrsave = (unsigned char)(buf[0] - '0');
+
+		if (mt3326_gps_set_pwrsave(obj, pwrsave) == 0)
+			return (ssize_t)count;
+	}
+	pr_debug("invalid content: '%p', length = %zu\n", buf, count);
+	return (ssize_t)count;
+}
+
+/******************************************************************************/
+#if defined(GPS_CONFIGURABLE_RESET_DELAY)
+/******************************************************************************/
+static ssize_t mt3326_show_rdelay(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	ssize_t res;
+	struct gps_drv_obj *obj;
+
+	if (dev == NULL) {
+		pr_debug("dev is null!!\n");
+		return 0;
+	}
+	obj = (struct gps_drv_obj *)dev_get_drvdata(dev);
+	if (obj == NULL) {
+		pr_debug("drv data is null!!\n");
+		return 0;
+	}
+	mutex_lock(&obj->sem);
+	res = snprintf(buf, PAGE_SIZE, "%d\n", obj->rdelay);
+	mutex_unlock(&obj->sem);
+	return res;
+}
+
+/******************************************************************************/
+static ssize_t mt3326_store_rdelay(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t count)
+{
+	struct gps_drv_obj *obj;
+	int rdelay;
+	unsigned long val = 0;
+
+	if (dev == NULL) {
+		pr_debug("dev is null!!\n");
+		return 0;
+	}
+	obj = (struct gps_drv_obj *)dev_get_drvdata(dev);
+	if (obj == NULL) {
+		pr_debug("drv data is null!!\n");
+		return 0;
+	}
+	rdelay = (int)kstrtol(buf, 10, &val);
+	if (rdelay == 0 && val <= 2000) {
+		mutex_lock(&obj->sem);
+		obj->rdelay = val;
+		mutex_unlock(&obj->sem);
+		return (ssize_t)count;
+	}
+	pr_debug("invalid content: '%p', length = %zu\n", buf, count);
+	return (ssize_t)count;
+}
+
+/******************************************************************************/
+#endif
+/******************************************************************************/
+DEVICE_ATTR(pwrctl, 0664, mt3326_show_pwrctl, mt3326_store_pwrctl);
+DEVICE_ATTR(suspend, 0664, mt3326_show_suspend, mt3326_store_suspend);
+DEVICE_ATTR(status, 0664, mt3326_show_status, mt3326_store_status);
+DEVICE_ATTR(state, 0664, mt3326_show_state, mt3326_store_state);
+DEVICE_ATTR(pwrsave, 0664, mt3326_show_pwrsave, mt3326_store_pwrsave);
+#if defined(GPS_CONFIGURABLE_RESET_DELAY)
+DEVICE_ATTR(rdelay, 0664, mt3326_show_rdelay, mt3326_store_rdelay);
+#endif
+static struct device_attribute *gps_attr_list[] = {
+	&dev_attr_pwrctl,
+	&dev_attr_suspend,
+	&dev_attr_status,
+	&dev_attr_state,
+	&dev_attr_pwrsave,
+#if defined(GPS_CONFIGURABLE_RESET_DELAY)
+	&dev_attr_rdelay,
+#endif
+};
+
+/******************************************************************************/
+static int mt3326_gps_create_attr(struct device *dev)
+{
+	int idx, err = 0;
+	int num = (int)ARRAY_SIZE(gps_attr_list);
+
+	if (dev == NULL)
+		return -EINVAL;
+
+	for (idx = 0; idx < num; idx++) {
+		err = device_create_file(dev, gps_attr_list[idx]);
+		if (err != 0) {
+			pr_debug("device_create_file (%s) = %d\n",
+				gps_attr_list[idx]->attr.name, err);
+			break;
+		}
+	}
+
+	return err;
+}
+
+/******************************************************************************/
+static int mt3326_gps_delete_attr(struct device *dev)
+{
+	int idx, err = 0;
+	int num = (int)ARRAY_SIZE(gps_attr_list);
+
+	if (dev == NULL)
+		return -EINVAL;
+
+	for (idx = 0; idx < num; idx++)
+		device_remove_file(dev, gps_attr_list[idx]);
+
+	return err;
+}
+
+/******************************************************************************/
+static long mt3326_gps_unlocked_ioctl(struct file *file, unsigned int cmd,
+		unsigned long arg)
+{
+	pr_debug("%s!!\n", __func__);
+	return -ENOIOCTLCMD;
+}
+
+/******************************************************************************/
+static long mt3326_gps_compat_ioctl(struct file *file, unsigned int cmd,
+		unsigned long arg)
+{
+	long ret;
+
+	pr_debug("%s!!\n", __func__);
+	ret = mt3326_gps_unlocked_ioctl(file, cmd, arg);
+	return ret;
+}
+
+/*****************************************************************************/
+static int mt3326_gps_open(struct inode *inode, struct file *file)
+{
+	/* all files share the same buffer */
+	file->private_data = &gps_private;
+	return nonseekable_open(inode, file);
+}
+
+/*****************************************************************************/
+static int mt3326_gps_release(struct inode *inode, struct file *file)
+{
+	struct gps_data *dev = file->private_data;
+
+	if (dev != NULL)
+		file->private_data = NULL;
+
+	return 0;
+}
+
+/******************************************************************************/
+static ssize_t mt3326_gps_read(struct file *file, char __user *buf,
+		size_t count, loff_t *ppos)
+{
+	struct gps_data *dev = file->private_data;
+	ssize_t ret = 0;
+	int copy_len = 0;
+
+	if (dev == NULL)
+		return -EINVAL;
+
+	if (signal_pending(current) != 0)
+		return -ERESTARTSYS;
+
+	if (down_interruptible(&dev->sem) != 0)
+		return -ERESTARTSYS;
+
+	if (dev->dat_len == 0) {	/*no data to be read */
+		up(&dev->sem);
+		/*non-block mode */
+		if ((file->f_flags &
+			(unsigned int)O_NONBLOCK) == (unsigned int)O_NONBLOCK)
+			return -EAGAIN;
+		do {		/*block mode */
+			ret = wait_event_interruptible
+				(dev->read_wait, (dev->dat_len > 0));
+			if (ret == -ERESTARTSYS)
+				return -ERESTARTSYS;
+		} while (ret == 0);
+		if (down_interruptible(&dev->sem) != 0)
+			return -ERESTARTSYS;
+	}
+
+	/*data is available */
+	copy_len = (dev->dat_len < (int)count) ? (dev->dat_len) : (int)(count);
+	if (copy_to_user(buf, (dev->dat_buf + dev->dat_pos),
+			(unsigned long)copy_len) != 0UL) {
+		ret = -EFAULT;
+	} else {
+		/*pr_debug("mt3326_gps_read(%ld,%d,%d) = %d\n",
+		 *count, dev->dat_pos, dev->dat_len, copy_len);
+		 */
+		if (dev->dat_len > (copy_len + dev->dat_pos)) {
+			dev->dat_pos += copy_len;
+		} else {
+			dev->dat_len = 0;
+			dev->dat_pos = 0;
+		}
+		ret = copy_len;
+	}
+
+	up(&dev->sem);
+	/* pr_debug("%s return %ld bytes\n", __func__, ret); */
+	return ret;
+}
+
+/******************************************************************************/
+static ssize_t mt3326_gps_write(struct file *file, const char __user *buf,
+		size_t count, loff_t *ppos)
+{
+	struct gps_data *dev = file->private_data;
+	ssize_t ret = 0;
+	size_t copy_size = 0;
+
+	if (dev == NULL)
+		return -EINVAL;
+
+	if (count == 0UL)		/*no data written */
+		return 0;
+
+	if (signal_pending(current) != 0)
+		return -ERESTARTSYS;
+
+	if (down_interruptible(&dev->sem) != 0)
+		return -ERESTARTSYS;
+
+	copy_size = (count < (size_t)4096) ? count : (size_t)4096;
+	if (copy_from_user(dev->dat_buf, buf, copy_size) != 0UL) {
+		pr_debug("copy_from_user error");
+		ret = -EFAULT;
+	} else {
+		dev->dat_len = (int)count;
+		dev->dat_pos = 0;
+		ret = (ssize_t)count;
+	}
+	up(&dev->sem);
+	wake_up_interruptible(&dev->read_wait);
+	pr_debug("%s: write %d bytes\n", __func__, dev->dat_len);
+	return ret;
+}
+
+/******************************************************************************/
+static unsigned int mt3326_gps_poll(struct file *file, poll_table *wait)
+{
+	struct gps_data *dev = file->private_data;
+	unsigned int mask = 0;
+
+	if (dev == NULL)
+		return 0;
+
+	down(&dev->sem);
+	poll_wait(file, &dev->read_wait, wait);
+	if (dev->dat_len != 0)	/*readable if data is available */
+		mask = (((unsigned int)POLLIN | (unsigned int)POLLRDNORM)
+			| ((unsigned int)POLLOUT | (unsigned int)POLLWRNORM));
+	else			/*always writable */
+		mask = ((unsigned int)POLLOUT | (unsigned int)POLLWRNORM);
+	up(&dev->sem);
+	pr_debug("%s: mask : 0x%X\n", __func__, mask);
+	return mask;
+}
+
+/*****************************************************************************/
+/* Kernel interface */
+static const struct file_operations mt3326_gps_fops = {
+	.owner = THIS_MODULE,
+	.unlocked_ioctl = mt3326_gps_unlocked_ioctl,
+	.compat_ioctl = mt3326_gps_compat_ioctl,
+	.open = mt3326_gps_open,
+	.read = mt3326_gps_read,
+	.write = mt3326_gps_write,
+	.release = mt3326_gps_release,
+	.poll = mt3326_gps_poll,
+};
+
+/*****************************************************************************/
+static void mt3326_gps_hw_init(struct mt3326_gps_hardware *hw)
+{
+	mt3326_gps_power(hw, 1, 0);
+}
+
+/*****************************************************************************/
+static void mt3326_gps_hw_exit(struct mt3326_gps_hardware *hw)
+{
+	mt3326_gps_power(hw, 0, 0);
+}
+
+/*****************************************************************************/
+static int mt3326_gps_probe(struct platform_device *dev)
+{
+	int ret = 0;
+	int err = 0;
+	struct gps_drv_obj *drvobj = NULL;
+	/*struct mt3326_gps_hardware *hw =
+	 *(struct mt3326_gps_hardware *)dev->dev.platform_data;
+	 */
+	struct mt3326_gps_hardware *hw = &mt3326_gps_hw;
+	struct gps_dev_obj *devobj = NULL;
+
+#ifdef CONFIG_OF
+	mt3303_gps_get_dts_data();
+#endif
+
+	devobj = kzalloc(sizeof(*devobj), GFP_KERNEL);
+	if (devobj  == NULL) {
+		/*(void)pr_err("kzalloc fail\n");*/
+		err = -ENOMEM;
+		return -1;
+	}
+
+	pr_info("get regulator");
+#ifdef CONFIG_MTK_PMIC_CHIP_MT6356
+	hw->reg_id = regulator_get(&dev->dev, "vcn33_wifi");
+#else
+	hw->reg_id = regulator_get(&dev->dev, "vcn33");
+#endif
+	if (!hw->reg_id) {
+		pr_info("regulator_get reg_id failed.\n");
+		return -1;
+	}
+
+	pr_info("regulator_get_voltage reg_id = %d uV\n",
+		regulator_get_voltage(hw->reg_id));
+
+	/*set voltage*/
+	if (regulator_set_voltage(hw->reg_id, min_uV, max_uV)) {
+		pr_info("regulator_set_voltage reg_id failed.\n");
+	};
+
+	mt3326_gps_hw_init(hw);
+	ret = alloc_chrdev_region(&devobj->devno, 0, 1, GPS_DEVNAME);
+	if (ret != 0) {
+		(void)pr_err("alloc_chrdev_region fail: %d\n", ret);
+		goto error;
+	} else {
+		pr_debug("major: %d, minor: %d\n", MAJOR(devobj->devno),
+				MINOR(devobj->devno));
+	}
+	cdev_init(&devobj->chdev, &mt3326_gps_fops);
+	devobj->chdev.owner = THIS_MODULE;
+	err = cdev_add(&devobj->chdev, devobj->devno, 1);
+	if (err != 0) {
+		(void)pr_err("cdev_add fail: %d\n", err);
+		goto error;
+	}
+	drvobj = kmalloc(sizeof(*drvobj), GFP_KERNEL);
+	if (drvobj == NULL) {
+		err = -ENOMEM;
+		goto error;
+	}
+	memset(drvobj, 0, sizeof(*drvobj));
+
+	devobj->cls = class_create(THIS_MODULE, "gpsdrv");
+	if (IS_ERR(devobj->cls)) {
+		(void)pr_err("Unable to create class, err = %d\n",
+				(int)PTR_ERR(devobj->cls));
+		goto error;
+	}
+	devobj->dev = device_create(devobj->cls, NULL,
+		devobj->devno, drvobj, "gps");
+	drvobj->hw = hw;
+	drvobj->pwrctl = 0;
+	drvobj->suspend = 0;
+	drvobj->state = GPS_STATE_UNSUPPORTED;
+	drvobj->pwrsave = GPS_PWRSAVE_UNSUPPORTED;
+	drvobj->rdelay = 50;
+	drvobj->kobj = &devobj->dev->kobj;
+	mutex_init(&drvobj->sem);
+
+	err = mt3326_gps_create_attr(devobj->dev);
+	if (err != 0)
+		goto error;
+
+	/* initialize members */
+	spin_lock_init(&gps_private.lock);
+	init_waitqueue_head(&gps_private.read_wait);
+	sema_init(&gps_private.sem, 1);
+
+	gps_private.dat_len = 0;
+	gps_private.dat_pos = 0;
+	(void)memset(gps_private.dat_buf, 0x00, sizeof(gps_private.dat_buf));
+
+	/* set platform data: a new device created for gps */
+	platform_set_drvdata(dev, devobj);
+
+	if (antSwitchFlag) {
+		pr_info("mt3303 get regulator");
+		vmch_reg = regulator_get(devobj->dev, "vmch");
+		if (!vmch_reg) {
+			pr_info("mt3303 regulator_get vmch failed.\n");
+			return -1;
+		}
+
+		pr_info("mt3303 regulator_get_voltage reg_id = %d uV\n",
+			regulator_get_voltage(vmch_reg));
+	}
+	pr_debug("Done\n");
+
+	return 0;
+
+error:
+	if (err == 0)
+		cdev_del(&devobj->chdev);
+	if (ret == 0)
+		unregister_chrdev_region(devobj->devno, 1);
+	kfree(devobj);
+	kfree(drvobj);
+
+	return -1;
+}
+
+/*****************************************************************************/
+static int mt3326_gps_remove(struct platform_device *dev)
+{
+	int err;
+	struct gps_dev_obj *devobj =
+		(struct gps_dev_obj *)platform_get_drvdata(dev);
+	struct gps_drv_obj *drvobj;
+
+	if (devobj == NULL) {
+		(void)pr_err("null pointer: %p\n", devobj);
+		return -1;
+	}
+
+	drvobj = (struct gps_drv_obj *)dev_get_drvdata(devobj->dev);
+	if (drvobj == NULL) {
+		(void)pr_err("null pointer: %p\n", drvobj);
+		return -1;
+	}
+	pr_debug("Unregistering chardev\n");
+
+	cdev_del(&devobj->chdev);
+	unregister_chrdev_region(devobj->devno, 1);
+
+	mt3326_gps_hw_exit(devobj->hw);
+	err = mt3326_gps_delete_attr(devobj->dev);
+	if (err != 0)
+		pr_debug("delete attr fails: %d\n", err);
+	device_destroy(devobj->cls, devobj->devno);
+	class_destroy(devobj->cls);
+
+	kfree(devobj);
+	pr_debug("Done\n");
+	return 0;
+}
+
+/*****************************************************************************/
+static void mt3326_gps_shutdown(struct platform_device *dev)
+{
+	struct gps_dev_obj *devobj =
+		(struct gps_dev_obj *)platform_get_drvdata(dev);
+
+	pr_debug("Shutting down\n");
+	mt3326_gps_hw_exit(devobj->hw);
+}
+
+/*****************************************************************************/
+#ifdef CONFIG_PM
+/*****************************************************************************/
+static int mt3326_gps_suspend(struct platform_device *dev,
+	pm_message_t state)
+{
+	int err = 0;
+	struct gps_dev_obj *devobj =
+		(struct gps_dev_obj *)platform_get_drvdata(dev);
+	struct gps_drv_obj *drvobj;
+
+	if (devobj == NULL) {
+		(void)pr_err("null pointer: %p\n", devobj);
+		return -1;
+	}
+
+	drvobj = (struct gps_drv_obj *)dev_get_drvdata(devobj->dev);
+	if (drvobj == NULL) {
+		(void)pr_err("null pointer: %p\n", drvobj);
+		return -1;
+	}
+
+	pr_debug("dev = %p, event = %u,", dev, state.event);
+	if (state.event == PM_EVENT_SUSPEND)
+		err = mt3326_gps_dev_suspend(drvobj);
+	return err;
+}
+
+/*****************************************************************************/
+static int mt3326_gps_resume(struct platform_device *dev)
+{
+	struct gps_dev_obj *devobj =
+		(struct gps_dev_obj *)platform_get_drvdata(dev);
+	struct gps_drv_obj *drvobj =
+		(struct gps_drv_obj *)dev_get_drvdata(devobj->dev);
+
+	return mt3326_gps_dev_resume(drvobj);
+}
+
+/*****************************************************************************/
+#endif /* CONFIG_PM */
+/*****************************************************************************/
+#ifdef CONFIG_OF
+static const struct of_device_id apgps_of_ids[] = {
+	{.compatible = "mediatek,mt3303",},
+	{}
+};
+#endif
+static struct platform_driver mt3326_gps_driver = {
+	.probe = mt3326_gps_probe,
+	.remove = mt3326_gps_remove,
+	.shutdown = mt3326_gps_shutdown,
+#if defined(CONFIG_PM)
+	.suspend = mt3326_gps_suspend,
+	.resume = mt3326_gps_resume,
+#endif
+	.driver = {
+		   .name = GPS_DEVNAME,
+		   .bus = &platform_bus_type,
+#ifdef CONFIG_OF
+		   .of_match_table = apgps_of_ids,
+#endif
+	},
+};
+
+#ifdef CONFIG_OF
+static void mt3303_gps_get_dts_data(void)
+{
+	struct device_node *node = NULL;
+
+	pr_info("mt3303 before: %d", antSwitchFlag);
+	node = of_find_matching_node(node, apgps_of_ids);
+	if (node) {
+		pr_info("of_property_read_u32");
+		of_property_read_u32(node, "antSwitchFlag", &antSwitchFlag);
+	}
+	pr_info("mt3303 after: %d", antSwitchFlag);
+}
+#endif
+
+/*****************************************************************************/
+static int __init mt3326_gps_mod_init(void)
+{
+	int ret = 0;
+	(void)pr_info("%s", __func__);
+	/* ret = driver_register(&mt3326_gps_driver); */
+	ret = platform_driver_register(&mt3326_gps_driver);
+
+	return ret;
+}
+
+/*****************************************************************************/
+static void __exit mt3326_gps_mod_exit(void)
+{
+	platform_driver_unregister(&mt3326_gps_driver);
+}
+
+static int mt3303_power_on(struct regulator *reg_id, int state)
+{
+	int ret;
+
+	if (antSwitchFlag && vmch_reg) {
+		if (!regulator_is_enabled(vmch_reg)) {
+			if (regulator_enable(vmch_reg)) {
+				pr_info("mt3303 regulator_enable vmch failed\n");
+				return 1;
+			}
+		}
+		pr_info("mt3303 regulator_enabled vmch is %s\n",
+			regulator_is_enabled(vmch_reg)?"enable":"non-enable");
+	}
+
+	if (reg_id) {
+		if (!regulator_is_enabled(reg_id)) {
+			ret = regulator_enable(reg_id);
+			if (ret) {
+				pr_info("mt3303 regulator_enable failed\n");
+				return 1;
+			}
+		}
+		pr_info("mt3303 regulator_enabled is %s\n",
+			regulator_is_enabled(reg_id)?"enable":"non-enable");
+		return 0;
+	}
+
+	return 1;
+}
+
+static int mt3303_power_off(struct regulator *reg_id, int state)
+{
+	int ret;
+
+	if (antSwitchFlag && vmch_reg) {
+		if (regulator_is_enabled(vmch_reg)) {
+			if (regulator_disable(vmch_reg)) {
+				pr_info("mt3303 regulator_disable vmch failed\n");
+				return 1;
+			}
+		}
+		pr_info("mt3303 regulator_disable vmch is %s\n",
+			regulator_is_enabled(vmch_reg)?"enable":"non-enable");
+	}
+
+	if (reg_id) {
+		if (regulator_is_enabled(reg_id)) {
+			ret = regulator_disable(reg_id);
+			if (ret) {
+				pr_info("mt3303 regulator_disable failed\n");
+				return 1;
+			}
+		}
+		pr_info("mt3303 regulator_disable is %s\n",
+			regulator_is_enabled(reg_id)?"enable":"non-enable");
+		return 0;
+	}
+
+	return 1;
+}
+
+/*****************************************************************************/
+module_init(mt3326_gps_mod_init);
+module_exit(mt3326_gps_mod_exit);
+/*****************************************************************************/
+MODULE_AUTHOR("MingHsien Hsieh <MingHsien.Hsieh@mediatek.com>");
+MODULE_DESCRIPTION("MT3326 GPS Driver");
+MODULE_LICENSE("GPL");
diff --git a/src/kernel/modules/connectivity/gps_driver/gps.h b/src/kernel/modules/connectivity/gps_driver/gps.h
new file mode 100644
index 0000000..2a619a5
--- /dev/null
+++ b/src/kernel/modules/connectivity/gps_driver/gps.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2016 MediaTek Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See http://www.gnu.org/licenses/gpl-2.0.html for more details.
+ *
+ * brief  Declaration of library functions
+ * Any definitions in this file will be shared among GLUE Layer and
+ * internal Driver Stack.
+ */
+
+#ifndef _GPS_H_
+#define _GPS_H_
+
+#include "wmt_core.h"
+#include "wmt_dev.h"
+#include "osal.h"
+#include "mtk_wcn_consys_hw.h"
+
+extern phys_addr_t gConEmiPhyBase;
+
+
+#endif
diff --git a/src/kernel/modules/connectivity/gps_driver/gps_emi.c b/src/kernel/modules/connectivity/gps_driver/gps_emi.c
new file mode 100644
index 0000000..a0c14ec
--- /dev/null
+++ b/src/kernel/modules/connectivity/gps_driver/gps_emi.c
@@ -0,0 +1,394 @@
+/*
+ * Implementation of the GPS EMI driver.
+ *
+ * Copyright (C) 2014 Mediatek
+ * Authors:
+ * Heiping <Heiping.Lei@mediatek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+/******************************************************************************
+ * Dependency
+ ******************************************************************************/
+#ifdef CONFIG_MTK_GPS_EMI
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/fs.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/cdev.h>
+#include <linux/errno.h>
+#include <linux/io.h>
+#include <linux/uaccess.h>
+#include <linux/printk.h>
+#include <linux/version.h>
+#include <asm/memblock.h>
+#include <mach/emi_mpu.h>
+#include "gps.h"
+
+#ifdef pr_fmt
+#undef pr_fmt
+#endif
+#define pr_fmt(fmt) "["KBUILD_MODNAME"]" fmt
+
+/******************************************************************************
+ * Definition
+ ******************************************************************************/
+/* device name and major number */
+#define GPSEMI_DEVNAME            "gps_emi"
+#define IOCTL_MNL_IMAGE_FILE_TO_MEM  1
+#define IOCTL_MNL_NVRAM_FILE_TO_MEM  2
+#define IOCTL_MNL_NVRAM_MEM_TO_FILE  3
+
+/******************************************************************************
+ * Debug configuration
+ ******************************************************************************/
+#define GPS_DBG_NONE(fmt, arg...)    do {} while (0)
+#define GPS_DBG pr_err
+#define GPS_TRC GPS_DBG_NONE
+#define GPS_VER pr_err
+#define GPS_ERR pr_err
+/******************************************************************************
+ * structure & enumeration
+ ******************************************************************************/
+/*---------------------------------------------------------------------------*/
+struct gps_emi_dev {
+	struct class *cls;
+	struct device *dev;
+	dev_t devno;
+	struct cdev chdev;
+};
+/*typedef unsigned char   UINT8, *PUINT8, **PPUINT8;*/
+
+/******************************************************************************
+ * local variables
+ ******************************************************************************/
+phys_addr_t gGpsEmiPhyBase;
+UINT8 __iomem *pGpsEmibaseaddr;
+struct gps_emi_dev *devobj;
+#define EMI_MPU_PROTECTION_IS_READY 1
+
+void mtk_wcn_consys_gps_memory_reserve(void)
+{
+#if 0
+#ifdef MTK_WCN_ARM64
+	gGpsEmiPhyBase = arm64_memblock_steal(SZ_1M, SZ_1M);
+#else
+	gGpsEmiPhyBase = arm_memblock_steal(SZ_1M, SZ_1M);
+#endif
+#else
+	gGpsEmiPhyBase = gConEmiPhyBase + SZ_1M;
+
+#endif
+	if (gGpsEmiPhyBase)
+		GPS_DBG("memblock done: 0x%zx\n", (size_t)gGpsEmiPhyBase);
+	else
+		GPS_DBG("memblock fail\n");
+}
+INT32 mtk_wcn_consys_gps_emi_init(void)
+{
+	INT32 iRet = -1;
+
+	mtk_wcn_consys_gps_memory_reserve();
+	if (gGpsEmiPhyBase) {
+    #if CONSYS_EMI_MPU_SETTING
+		/*set MPU for EMI share Memory*/
+		GPS_DBG("setting MPU for EMI share memory\n");
+    #if EMI_MPU_PROTECTION_IS_READY
+		emi_mpu_set_region_protection(gGpsEmiPhyBase,
+			gGpsEmiPhyBase + SZ_1M - 1,
+			20,
+			SET_ACCESS_PERMISSON(FORBIDDEN, FORBIDDEN,
+				FORBIDDEN, FORBIDDEN, FORBIDDEN, NO_PROTECTION,
+				FORBIDDEN, NO_PROTECTION));
+    #endif
+
+    #endif
+		GPS_DBG("get consys start phy address(0x%zx)\n",
+			(size_t)gGpsEmiPhyBase);
+    #if 0
+		/*consys to ap emi remapping register:10001310,
+		 *cal remapping address
+		 */
+		addrPhy = (gGpsEmiPhyBase & 0xFFF00000) >> 20;
+
+		/*enable consys to ap emi remapping bit12*/
+		addrPhy -= 0x400;/*Gavin ??*/
+		addrPhy = addrPhy | 0x1000;
+
+		CONSYS_REG_WRITE(conn_reg.topckgen_base +
+			CONSYS_EMI_MAPPING_OFFSET, CONSYS_REG_READ
+			(conn_reg.topckgen_base + CONSYS_EMI_MAPPING_OFFSET)
+			| addrPhy);
+
+		GPS_DBG("GPS_EMI_MAPPING dump(0x%08x)\n",
+			CONSYS_REG_READ(conn_reg.topckgen_base
+			+ CONSYS_EMI_MAPPING_OFFSET));
+    #endif
+
+		pGpsEmibaseaddr = ioremap_nocache(gGpsEmiPhyBase, SZ_1M);
+		if (pGpsEmibaseaddr != NULL) {
+			UINT8 *pFullPatchName = "/system/etc/firmware/MNL.bin";
+			firmware *pPatch = NULL;
+
+			GPS_DBG("EMI mapping OK(0x%p)\n", pGpsEmibaseaddr);
+			memset_io(pGpsEmibaseaddr, 0, SZ_1M);
+			if ((pFullPatchName != NULL)
+				&& (wmt_dev_patch_get(pFullPatchName, &pPatch,
+				0/*BCNT_PATCH_BUF_HEADROOM*/) == 0)) {
+				if (pPatch != NULL) {
+					/*get full name patch success*/
+					GPS_DBG("get full patch name(%s) ",
+						pFullPatchName);
+					GPS_DBG("buf(0x%p) ", (pPatch)->data);
+					GPS_DBG("size(%ld)\n", (pPatch)->size);
+					GPS_DBG("AF get patch, pPatch(0x%p)\n",
+						pPatch);
+				}
+			}
+			if (pPatch != NULL) {
+				if ((pPatch)->size <= SZ_1M) {
+					memcpy(pGpsEmibaseaddr,
+						(pPatch)->data, (pPatch)->size);
+					iRet = 1;
+				}
+			}
+		} else {
+			GPS_DBG("EMI mapping fail\n");
+		}
+	} else {
+		GPS_DBG("gps emi memory address gGpsEmiPhyBase invalid\n");
+	}
+	return iRet;
+}
+
+/*---------------------------------------------------------------------------*/
+long gps_emi_unlocked_ioctl(struct file *file,
+	unsigned int cmd, unsigned long arg)
+{
+	int retval = 0;
+
+	GPS_DBG("cmd (%d),arg(%ld)\n", cmd, arg);
+
+	switch (cmd) {
+	case IOCTL_MNL_IMAGE_FILE_TO_MEM:
+		retval = mtk_wcn_consys_gps_emi_init();
+		GPS_DBG("IOCTL_MNL_IMAGE_FILE_TO_MEM\n");
+		break;
+
+	case IOCTL_MNL_NVRAM_FILE_TO_MEM:
+		GPS_DBG("IOCTL_MNL_NVRAM_FILE_TO_MEM\n");
+		break;
+
+	case IOCTL_MNL_NVRAM_MEM_TO_FILE:
+		GPS_DBG("IOCTL_MNL_NVRAM_MEM_TO_FILE\n");
+		break;
+
+	default:
+		GPS_DBG("unknown cmd (%d)\n", cmd);
+		retval = 0;
+		break;
+	}
+	return retval;
+
+}
+
+/******************************************************************************/
+/*****************************************************************************/
+static int gps_emi_open(struct inode *inode, struct file *file)
+{
+	GPS_TRC();
+	return nonseekable_open(inode, file);
+}
+
+/*****************************************************************************/
+
+
+/*****************************************************************************/
+static int gps_emi_release(struct inode *inode, struct file *file)
+{
+	GPS_TRC();
+
+	return 0;
+}
+
+/******************************************************************************/
+static ssize_t gps_emi_read(struct file *file,
+	char __user *buf, size_t count, loff_t *ppos)
+{
+	ssize_t ret = 0;
+
+	GPS_TRC();
+
+	return ret;
+}
+/******************************************************************************/
+static ssize_t gps_emi_write(struct file *file,
+	const char __user *buf, size_t count,
+		loff_t *ppos)
+{
+	ssize_t ret = 0;
+
+	GPS_TRC();
+
+	return ret;
+}
+
+
+/*****************************************************************************/
+/* Kernel interface */
+static const struct file_operations gps_emi_fops = {
+	.owner = THIS_MODULE,
+	.unlocked_ioctl = gps_emi_unlocked_ioctl,
+	.open = gps_emi_open,
+	.read = gps_emi_read,
+	.write = gps_emi_write,
+	.release = gps_emi_release,
+};
+
+/*****************************************************************************/
+static int gps_emi_probe(struct platform_device *dev)
+{
+	int ret = 0, err = 0;
+
+	devobj = kzalloc(sizeof(*devobj), GFP_KERNEL);
+	if (devobj == NULL) {
+		err = -ENOMEM;
+		ret = -ENOMEM;
+		goto err_out;
+	}
+
+	GPS_DBG("Registering chardev\n");
+	ret = alloc_chrdev_region(&devobj->devno, 0, 1, GPSEMI_DEVNAME);
+	if (ret) {
+		GPS_ERR("alloc_chrdev_region fail: %d\n", ret);
+		kfree(devobj);
+		err = -ENOMEM;
+		goto err_out;
+	} else {
+		GPS_DBG("major: %d, minor: %d\n",
+			MAJOR(devobj->devno), MINOR(devobj->devno));
+	}
+	cdev_init(&devobj->chdev, &gps_emi_fops);
+	devobj->chdev.owner = THIS_MODULE;
+	err = cdev_add(&devobj->chdev, devobj->devno, 1);
+	if (err) {
+		GPS_ERR("cdev_add fail: %d\n", err);
+		kfree(devobj);
+		goto err_out;
+	}
+	devobj->cls = class_create(THIS_MODULE, "gpsemi");
+	if (IS_ERR(devobj->cls)) {
+		GPS_ERR("Unable to create class, err = %d\n",
+			(int)PTR_ERR(devobj->cls));
+		kfree(devobj);
+		goto err_out;
+	}
+	devobj->dev = device_create(devobj->cls, NULL,
+		devobj->devno, devobj, "gps_emi");
+
+	GPS_DBG("Done\n");
+	return 0;
+
+err_out:
+	if (err == 0)
+		cdev_del(&devobj->chdev);
+	if (ret == 0)
+		unregister_chrdev_region(devobj->devno, 1);
+	return -1;
+}
+
+/*****************************************************************************/
+static int gps_emi_remove(struct platform_device *dev)
+{
+	if (!devobj) {
+		GPS_ERR("null pointer: %p\n", devobj);
+		return -1;
+	}
+
+	GPS_DBG("Unregistering chardev\n");
+	cdev_del(&devobj->chdev);
+	unregister_chrdev_region(devobj->devno, 1);
+	device_destroy(devobj->cls, devobj->devno);
+	class_destroy(devobj->cls);
+	kfree(devobj);
+	GPS_DBG("Done\n");
+	return 0;
+}
+
+/*****************************************************************************/
+#ifdef CONFIG_PM
+/*****************************************************************************/
+static int gps_emi_suspend(struct platform_device *dev, pm_message_t state)
+{
+	GPS_DBG("dev = %p, event = %u,", dev, state.event);
+	if (state.event == PM_EVENT_SUSPEND)
+		GPS_DBG("Receive PM_EVENT_SUSPEND!!\n");
+	return 0;
+}
+
+/*****************************************************************************/
+static int gps_emi_resume(struct platform_device *dev)
+{
+	GPS_DBG("");
+	return 0;
+}
+
+/*****************************************************************************/
+#endif        /* CONFIG_PM */
+/*****************************************************************************/
+#ifdef CONFIG_OF
+static const struct of_device_id apgps_of_ids[] = {
+	{ .compatible = "mediatek,gps_emi-v1", },
+	{}
+};
+#endif
+static struct platform_driver gps_emi_driver = {
+	.probe = gps_emi_probe,
+	.remove = gps_emi_remove,
+#if defined(CONFIG_PM)
+	.suspend = gps_emi_suspend,
+	.resume = gps_emi_resume,
+#endif
+	.driver = {
+		.name = GPSEMI_DEVNAME,
+		.bus = &platform_bus_type,
+#ifdef CONFIG_OF
+		.of_match_table = apgps_of_ids,
+#endif
+	},
+};
+
+/*****************************************************************************/
+static int __init gps_emi_mod_init(void)
+{
+	int ret = 0;
+
+	GPS_TRC();
+
+	ret = platform_driver_register(&gps_emi_driver);
+
+	return ret;
+}
+
+/*****************************************************************************/
+static void __exit gps_emi_mod_exit(void)
+{
+	GPS_TRC();
+	platform_driver_unregister(&gps_emi_driver);
+}
+
+/*****************************************************************************/
+module_init(gps_emi_mod_init);
+module_exit(gps_emi_mod_exit);
+/*****************************************************************************/
+MODULE_AUTHOR("Heiping Lei <Heiping.Lei@mediatek.com>");
+MODULE_DESCRIPTION("GPS EMI Driver");
+MODULE_LICENSE("GPL");
+#endif
diff --git a/src/kernel/modules/connectivity/gps_driver/init.gps_drv.rc b/src/kernel/modules/connectivity/gps_driver/init.gps_drv.rc
new file mode 100644
index 0000000..258aa68
--- /dev/null
+++ b/src/kernel/modules/connectivity/gps_driver/init.gps_drv.rc
@@ -0,0 +1,4 @@
+
+# load gps_drv
+on property:vendor.connsys.driver.ready=yes
+  insmod /vendor/lib/modules/gps_drv.ko
diff --git a/src/kernel/modules/connectivity/gps_driver/stp_chrdev_gps.c b/src/kernel/modules/connectivity/gps_driver/stp_chrdev_gps.c
new file mode 100644
index 0000000..a3ddaa8
--- /dev/null
+++ b/src/kernel/modules/connectivity/gps_driver/stp_chrdev_gps.c
@@ -0,0 +1,749 @@
+/*
+ * Copyright (C) 2011-2014 MediaTek Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License version 2 as published by the
+ * Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/cdev.h>
+#include <linux/sched.h>
+#include <asm/current.h>
+#include <linux/uaccess.h>
+#include <linux/skbuff.h>
+#include <linux/of.h>
+#if WMT_CREATE_NODE_DYNAMIC || REMOVE_MK_NODE
+#include <linux/device.h>
+#endif
+#include <linux/platform_device.h>
+#include "osal_typedef.h"
+#include "stp_exp.h"
+#include "wmt_exp.h"
+#if defined(CONFIG_MACH_MT6580)
+#include <mt_clkbuf_ctl.h>
+#endif
+#include <linux/version.h>
+
+MODULE_LICENSE("GPL");
+
+#define GPS_DRIVER_NAME "mtk_stp_GPS_chrdev"
+#define GPS_DEV_MAJOR 191	/* never used number */
+#define GPS_DEBUG_TRACE_GPIO         0
+#define GPS_DEBUG_DUMP               0
+
+#define PFX                         "[GPS] "
+#define GPS_LOG_DBG                  3
+#define GPS_LOG_INFO                 2
+#define GPS_LOG_WARN                 1
+#define GPS_LOG_ERR                  0
+
+#define COMBO_IOC_GPS_HWVER           6
+#define COMBO_IOC_GPS_IC_HW_VERSION   7
+#define COMBO_IOC_GPS_IC_FW_VERSION   8
+#define COMBO_IOC_D1_EFUSE_GET       9
+#define COMBO_IOC_RTC_FLAG	     10
+#define COMBO_IOC_CO_CLOCK_FLAG	     11
+#define COMBO_IOC_TRIGGER_WMT_ASSERT 12
+#define COMBO_IOC_WMT_STATUS         13
+
+static int GPS_devs = 1;	/* device count */
+static unsigned int GPS_major = GPS_DEV_MAJOR;	/* dynamic allocation */
+module_param(GPS_major, uint, 0000);
+static struct cdev GPS_cdev;
+
+static struct wakeup_source *gps_wake_lock_ptr;
+static unsigned char wake_lock_acquired;   /* default: 0 */
+
+#if (defined(CONFIG_MTK_GMO_RAM_OPTIMIZE) && !defined(CONFIG_MTK_ENG_BUILD))
+#define STP_GPS_BUFFER_SIZE 2048
+#else
+#define STP_GPS_BUFFER_SIZE MTKSTP_BUFFER_SIZE
+#endif
+/* input buffer of read() */
+static unsigned char i_buf[STP_GPS_BUFFER_SIZE];
+/* output buffer of write() */
+static unsigned char o_buf[STP_GPS_BUFFER_SIZE];
+static struct semaphore wr_mtx, rd_mtx;
+static DECLARE_WAIT_QUEUE_HEAD(GPS_wq);
+static int flag;
+/*static volatile int rstflag;*/
+static int rstflag;
+
+static int antSwitchFlag;
+#include <linux/regulator/consumer.h>
+
+static struct regulator *reg_id;
+
+static int gps_probe(struct platform_device *plat_dev);
+static int gps_remove(struct platform_device *plat_dev);
+
+static void GPS_event_cb(void);
+
+static void gps_hold_wake_lock(int hold)
+{
+	if (hold == 1) {
+		if (wake_lock_acquired == 0) {
+			pr_debug("acquire gps wake_lock acquired = %d\n",
+				wake_lock_acquired);
+			__pm_stay_awake(gps_wake_lock_ptr);
+			wake_lock_acquired = 1;
+		}
+	} else if (hold == 0) {
+		if (wake_lock_acquired != 0) {
+			pr_debug("release gps wake_lock acquired = %d\n",
+				wake_lock_acquired);
+			__pm_relax(gps_wake_lock_ptr);
+			wake_lock_acquired = 0;
+		}
+	} else {
+		pr_info("hold value incorrect:%d\n", hold);
+	}
+}
+
+static bool rtc_GPS_low_power_detected(void)
+{
+	static bool first_query = true;
+
+	if (first_query) {
+		first_query = false;
+		/*return rtc_low_power_detected();*/
+		return 0;
+	} else {
+		return false;
+	}
+}
+static ssize_t GPS_write(struct file *filp, const char __user *buf,
+		size_t count, loff_t *f_pos)
+{
+	int retval = 0;
+	int written = 0;
+
+	down(&wr_mtx);
+
+	if (count > 0UL) {
+		size_t copy_size = (count < (size_t)MTKSTP_BUFFER_SIZE) ?
+			count : (size_t)MTKSTP_BUFFER_SIZE;
+
+		if (copy_from_user(&o_buf[0], &buf[0], copy_size) != 0UL) {
+			retval = -EFAULT;
+			goto out;
+		}
+#if GPS_DEBUG_TRACE_GPIO
+		mtk_wcn_stp_debug_gpio_assert(IDX_GPS_TX, DBG_TIE_LOW);
+#endif
+		written = mtk_wcn_stp_send_data(&o_buf[0],
+			(UINT32)copy_size, GPS_TASK_INDX);
+#if GPS_DEBUG_TRACE_GPIO
+		mtk_wcn_stp_debug_gpio_assert(IDX_GPS_TX, DBG_TIE_HIGH);
+#endif
+
+#if GPS_DEBUG_DUMP
+		{
+			unsigned char *buf_ptr = &o_buf[0];
+			int k = 0;
+
+			pr_debug("--[GPS-WRITE]--");
+			for (k = 0; k < 10; k++) {
+				if (k % 16 == 0)
+					pr_debug("\n");
+				pr_debug("0x%02x ", o_buf[k]);
+			}
+			pr_debug("\n");
+		}
+#endif
+		if (written == 0) {
+			retval = -ENOSPC;
+		/* no windowspace in STP is available, native process should not
+		 * call GPS_write with no delay at all
+		 */
+		pr_info("target packet length:%zd, ", count);
+		pr_info("write success length:%d, ", written);
+		pr_info("retval = %d.\n", retval);
+		} else {
+			retval = written;
+		}
+	} else {
+		retval = -EFAULT;
+		pr_info("target packet length:%zd is not allowed, ", count);
+		pr_info("retval = %d.\n", retval);
+	}
+out:
+	up(&wr_mtx);
+	return retval;
+}
+
+static ssize_t GPS_read(struct file *filp, char __user *buf, size_t count,
+		loff_t *f_pos)
+{
+	int val = 0;
+	int retval;
+
+	down(&rd_mtx);
+
+	if (rstflag == 1) {
+		if ((filp->f_flags & (unsigned int)O_NONBLOCK) ==
+			(unsigned int)O_NONBLOCK) {
+			retval = -EIO;
+			goto OUT;
+		}
+	}
+
+	if (count > (size_t)MTKSTP_BUFFER_SIZE)
+		count = (size_t)MTKSTP_BUFFER_SIZE;
+
+#if GPS_DEBUG_TRACE_GPIO
+	mtk_wcn_stp_debug_gpio_assert(IDX_GPS_RX, DBG_TIE_LOW);
+#endif
+	retval = mtk_wcn_stp_receive_data(i_buf, (UINT32)count, GPS_TASK_INDX);
+#if GPS_DEBUG_TRACE_GPIO
+	mtk_wcn_stp_debug_gpio_assert(IDX_GPS_RX, DBG_TIE_HIGH);
+#endif
+
+	while (retval == 0) {
+		/* got nothing, wait for STP's signal */
+		/* wait_event(GPS_wq, flag != 0); */
+		/* George: let signal wake up */
+		if ((filp->f_flags & (unsigned int)O_NONBLOCK) ==
+			(unsigned int)O_NONBLOCK) {
+			retval = -EAGAIN;
+			goto OUT;
+		}
+
+		val = wait_event_interruptible(GPS_wq, flag != 0);
+		flag = 0;
+
+#if GPS_DEBUG_TRACE_GPIO
+		mtk_wcn_stp_debug_gpio_assert(IDX_GPS_RX, DBG_TIE_LOW);
+#endif
+
+		retval = mtk_wcn_stp_receive_data(i_buf,
+			(UINT32)count, GPS_TASK_INDX);
+
+#if GPS_DEBUG_TRACE_GPIO
+		mtk_wcn_stp_debug_gpio_assert(IDX_GPS_RX, DBG_TIE_HIGH);
+#endif
+		/* if we are signaled */
+		if (val != 0) {
+			if (-ERESTARTSYS == val)
+				pr_debug("signaled by -ERESTARTSYS(%d)\n ",
+					 val);
+			else
+				pr_debug("signaled by %d\n ", val);
+
+			break;
+		}
+	}
+
+#if GPS_DEBUG_DUMP
+	{
+		unsigned char *buf_ptr = &i_buf[0];
+		int k = 0;
+
+		pr_debug("--[GPS-READ]--");
+		for (k = 0; k < 10; k++) {
+			if (k % 16 == 0)
+				pr_debug("\n");
+			pr_debug("0x%02x ", i_buf[k]);
+		}
+		pr_debug("--\n");
+	}
+#endif
+
+	if (retval > 0) {
+		/* we got something from STP driver */
+		if (copy_to_user(buf, i_buf, (unsigned long)retval) != 0UL) {
+			retval = -EFAULT;
+			goto OUT;
+		} else {
+			/* success */
+		}
+	} else {
+		/* we got nothing from STP driver, being signaled */
+		retval = val;
+	}
+
+OUT:
+	up(&rd_mtx);
+	return (ssize_t)retval;
+}
+
+/* int GPS_ioctl(struct inode *inode, struct file *filp,
+ * unsigned int cmd, unsigned long arg)
+ */
+static long GPS_unlocked_ioctl(struct file *filp, unsigned int cmd,
+	unsigned long arg)
+{
+	int retval = 0;
+	ENUM_WMTHWVER_TYPE_T hw_ver_sym = WMTHWVER_INVALID;
+	UINT32 hw_version = 0;
+	UINT32 fw_version = 0;
+
+	pr_debug("GPS_ioctl(): cmd (%d)\n", cmd);
+
+	switch (cmd) {
+	case 0:		/* enable/disable STP */
+		pr_debug("GPS_ioctl(): disable STP control from GPS dev\n");
+		retval = -EINVAL;
+#if 1
+#else
+		/* George: STP is controlled by WMT only */
+		mtk_wcn_stp_enable(arg);
+#endif
+		break;
+
+	case 1:		/* send raw data */
+		pr_debug("GPS_ioctl(): disable raw data from GPS dev\n");
+		retval = -EINVAL;
+		break;
+
+	case COMBO_IOC_GPS_HWVER:
+		/*get combo hw version */
+		hw_ver_sym = mtk_wcn_wmt_hwver_get();
+
+		pr_debug("GPS_ioctl(): get hw version = %d, ", hw_ver_sym);
+		pr_debug("sizeof(hw_ver_sym) = %zd\n", sizeof(hw_ver_sym));
+		if (copy_to_user((int __user *)arg, &hw_ver_sym,
+			sizeof(hw_ver_sym)) != 0UL)
+			retval = -EFAULT;
+
+		break;
+	case COMBO_IOC_GPS_IC_HW_VERSION:
+		/*get combo hw version from ic,  without wmt mapping */
+		hw_version = mtk_wcn_wmt_ic_info_get(WMTCHIN_HWVER);
+
+		pr_debug("GPS_ioctl(): get hw version = 0x%x\n", hw_version);
+		if (copy_to_user((int __user *)arg, &hw_version,
+			sizeof(hw_version)) != 0UL)
+			retval = -EFAULT;
+
+		break;
+
+	case COMBO_IOC_GPS_IC_FW_VERSION:
+		/*get combo fw version from ic, without wmt mapping */
+		fw_version = mtk_wcn_wmt_ic_info_get(WMTCHIN_FWVER);
+
+		pr_debug("GPS_ioctl(): get fw version = 0x%x\n", fw_version);
+		if (copy_to_user((int __user *)arg, &fw_version,
+			sizeof(fw_version)) != 0UL)
+			retval = -EFAULT;
+
+		break;
+	case COMBO_IOC_RTC_FLAG:
+
+		retval = (int)rtc_GPS_low_power_detected();
+
+		pr_debug("low power flag (%d)\n", retval);
+		break;
+	case COMBO_IOC_CO_CLOCK_FLAG:
+#if SOC_CO_CLOCK_FLAG
+		retval = mtk_wcn_wmt_co_clock_flag_get();
+#endif
+		pr_debug("GPS co_clock_flag (%d)\n", retval);
+		break;
+	case COMBO_IOC_D1_EFUSE_GET:
+#if defined(CONFIG_MACH_MT6735)
+		do {
+			char *addr = ioremap(0x10206198, 0x4);
+
+			/*retval = *(volatile unsigned int *)addr;*/
+			retval = *(unsigned int *)addr;
+			pr_debug("D1 efuse (0x%x)\n", retval);
+			iounmap(addr);
+		} while (0);
+#else
+		pr_info("Read Efuse not supported in this platform\n");
+#endif
+		break;
+
+	case COMBO_IOC_TRIGGER_WMT_ASSERT:
+		/* Trigger FW assert for debug */
+		pr_info("%s: Host trigger FW assert......, reason:%lu\n",
+			__func__, arg);
+		retval = mtk_wcn_wmt_assert(WMTDRV_TYPE_GPS, (UINT32)arg);
+		if (retval == MTK_WCN_BOOL_TRUE) {
+			pr_info("Host trigger FW assert succeed\n");
+			retval = 0;
+		} else {
+			pr_info("Host trigger FW assert Failed\n");
+			retval = (-EBUSY);
+		}
+		break;
+	case COMBO_IOC_WMT_STATUS:
+		if (rstflag == 1) {
+			/* chip resetting */
+			retval = -888;
+		} else if (rstflag == 2) {
+			/* chip reset end */
+			retval = -889;
+			rstflag = 0;
+		} else {
+			/* normal */
+			retval = 0;
+		}
+		pr_debug("rstflag(%d), retval(%d)\n", rstflag, retval);
+		break;
+	default:
+		retval = -EFAULT;
+		pr_debug("GPS_ioctl(): unknown cmd (%d)\n", cmd);
+		break;
+	}
+
+/*OUT:*/
+	return retval;
+}
+
+static long GPS_compat_ioctl(struct file *filp, unsigned int cmd,
+		unsigned long arg)
+{
+	long ret;
+
+	pr_debug("%s: cmd (%d)\n", __func__, cmd);
+	ret = GPS_unlocked_ioctl(filp, cmd, arg);
+	pr_debug("%s: cmd (%d)\n", __func__, cmd);
+	return ret;
+}
+
+static void gps_cdev_rst_cb(ENUM_WMTDRV_TYPE_T src,
+		ENUM_WMTDRV_TYPE_T dst, ENUM_WMTMSG_TYPE_T type,
+		void *buf, unsigned int sz)
+{
+
+	/* To handle reset procedure please */
+	ENUM_WMTRSTMSG_TYPE_T rst_msg;
+
+	pr_debug("sizeof(ENUM_WMTRSTMSG_TYPE_T) = %zd\n",
+		sizeof(ENUM_WMTRSTMSG_TYPE_T));
+	if (sz <= sizeof(ENUM_WMTRSTMSG_TYPE_T)) {
+		(void)memcpy((char *)&rst_msg, (char *)buf, sz);
+		pr_debug("src = %d, dst = %d, type = %d, ", src, dst, type);
+		pr_debug("buf = 0x%x sz = %d, ", rst_msg, sz);
+		pr_debug("max = %d\n", WMTRSTMSG_RESET_MAX);
+
+		if ((src == WMTDRV_TYPE_WMT) && (dst == WMTDRV_TYPE_GPS)
+			&& (type == WMTMSG_TYPE_RESET)) {
+			switch (rst_msg) {
+			case WMTRSTMSG_RESET_START:
+				pr_info("Whole chip reset start!\n");
+				rstflag = 1;
+				break;
+			case WMTRSTMSG_RESET_END:
+			case WMTRSTMSG_RESET_END_FAIL:
+				if (rst_msg == WMTRSTMSG_RESET_END)
+					pr_info("Whole chip reset end!\n");
+				else
+					pr_info("Whole chip reset fail!\n");
+				rstflag = 2;
+				break;
+			default:
+				break;
+			}
+		}
+	} else {
+		/*message format invalid */
+		pr_info("Invalid message format!\n");
+	}
+}
+
+static int GPS_open(struct inode *inode, struct file *file)
+{
+	pr_debug("%s: major %d minor %d (pid %d)\n",
+		__func__, imajor(inode), iminor(inode), current->pid);
+	if (current->pid == 1)
+		return 0;
+	if (rstflag == 1) {
+		pr_info("whole chip resetting...\n");
+		return -EPERM;
+	}
+
+#if 1	/* GeorgeKuo: turn on function before check stp ready */
+	/* turn on BT */
+
+	if (mtk_wcn_wmt_func_on(WMTDRV_TYPE_GPS) == MTK_WCN_BOOL_FALSE) {
+		pr_info("WMT turn on GPS fail!\n");
+		return -ENODEV;
+	}
+
+	(void)mtk_wcn_wmt_msgcb_reg(WMTDRV_TYPE_GPS, gps_cdev_rst_cb);
+	pr_debug("WMT turn on GPS OK!\n");
+	rstflag = 0;
+
+#endif
+
+	if (mtk_wcn_stp_is_ready()) {
+		(void)mtk_wcn_stp_register_event_cb
+			(GPS_TASK_INDX, GPS_event_cb);
+	} else {
+		pr_info("STP is not ready, Cannot open GPS Devices\n\r");
+
+		/*return error code */
+		return -ENODEV;
+	}
+	gps_hold_wake_lock(1);
+	pr_debug("gps_hold_wake_lock(1)\n");
+#if defined(CONFIG_MACH_MT6580)
+	clk_buf_ctrl(CLK_BUF_AUDIO, 1);
+#endif
+	/* init_MUTEX(&wr_mtx); */
+	sema_init(&wr_mtx, 1);
+	/* init_MUTEX(&rd_mtx); */
+	sema_init(&rd_mtx, 1);
+
+	if (antSwitchFlag && reg_id) {
+		if (!regulator_is_enabled(reg_id)) {
+			if (regulator_enable(reg_id)) {
+				pr_info("regulator_enable failed\n");
+				return -ENODEV;
+			}
+		}
+	pr_info("regulator_enabled is %s\n",
+		regulator_is_enabled(reg_id)?"enable":"non-enable");
+	}
+
+	return 0;
+}
+
+static int GPS_close(struct inode *inode, struct file *file)
+{
+	pr_debug("%s: major %d minor %d (pid %d)\n",
+		__func__, imajor(inode), iminor(inode), current->pid);
+	if (current->pid == 1)
+		return 0;
+	if (rstflag == 1) {
+		pr_info("whole chip resetting...\n");
+		return -EPERM;
+	}
+
+	if (mtk_wcn_wmt_func_off(WMTDRV_TYPE_GPS) == MTK_WCN_BOOL_FALSE) {
+		pr_info("WMT turn off GPS fail!\n");
+		return -EIO;
+		/* mostly, native programer does not care this return vlaue, */
+		/* but we still return error code. */
+	}
+	pr_debug("WMT turn off GPS OK!\n");
+	rstflag = 0;
+	/*Flush Rx Queue */
+	/* unregister event callback function */
+	(void)mtk_wcn_stp_register_event_cb(GPS_TASK_INDX, 0x0);
+	(void)mtk_wcn_wmt_msgcb_unreg(WMTDRV_TYPE_GPS);
+
+	gps_hold_wake_lock(0);
+	pr_debug("gps_hold_wake_lock(0)\n");
+
+#if defined(CONFIG_MACH_MT6580)
+	clk_buf_ctrl(CLK_BUF_AUDIO, 0);
+#endif
+
+	if (antSwitchFlag && reg_id) {
+		if (regulator_is_enabled(reg_id)) {
+			if (regulator_disable(reg_id)) {
+				pr_info("regulator_disable failed\n");
+				return -EIO;
+			}
+		}
+		pr_info("regulator_disable is %s\n",
+			regulator_is_enabled(reg_id)?"enable":"non-enable");
+	}
+
+	return 0;
+}
+
+static const struct file_operations GPS_fops = {
+	.open = GPS_open,
+	.release = GPS_close,
+	.read = GPS_read,
+	.write = GPS_write,
+/* .ioctl = GPS_ioctl */
+	.unlocked_ioctl = GPS_unlocked_ioctl,
+	.compat_ioctl = GPS_compat_ioctl,
+};
+
+void GPS_event_cb(void)
+{
+	flag = 1;
+	wake_up(&GPS_wq);
+}
+
+
+/*****************************************************************************/
+#ifdef CONFIG_OF
+static const struct of_device_id gps_of_ids[] = {
+	{.compatible = "mediatek,mt6630-gps",},
+	{}
+};
+#endif
+static struct platform_driver gps_driver = {
+	.probe = gps_probe,
+	.remove = gps_remove,
+	.driver = {
+		   .name = GPS_DRIVER_NAME,
+		   .bus = &platform_bus_type,
+#ifdef CONFIG_OF
+		   .of_match_table = gps_of_ids,
+#endif
+	},
+};
+
+#if WMT_CREATE_NODE_DYNAMIC || REMOVE_MK_NODE
+static struct class *stpgps_class;
+#endif
+
+#ifdef CONFIG_OF
+static void gps_get_dts_data(void)
+{
+	struct device_node *node = NULL;
+
+	pr_info("before: %d", antSwitchFlag);
+	node = of_find_matching_node(node, gps_of_ids);
+	if (node) {
+		pr_info("of_property_read_u32");
+		of_property_read_u32(node, "antSwitchFlag", &antSwitchFlag);
+	}
+	pr_info("after: %d", antSwitchFlag);
+}
+#endif
+
+/*****************************************************************************/
+static int gps_probe(struct platform_device *plat_dev)
+{
+	dev_t dev = MKDEV(GPS_major, 0);
+	int alloc_ret = 0;
+	int cdev_err = 0;
+#if WMT_CREATE_NODE_DYNAMIC || REMOVE_MK_NODE
+	struct device *stpgps_dev = NULL;
+#endif
+
+#ifdef CONFIG_OF
+	gps_get_dts_data();
+#endif
+
+	/*static allocate chrdev */
+	alloc_ret = register_chrdev_region(dev, 1, GPS_DRIVER_NAME);
+	if (alloc_ret != 0) {
+		pr_info("fail to register chrdev\n");
+		return alloc_ret;
+	}
+
+	cdev_init(&GPS_cdev, &GPS_fops);
+	GPS_cdev.owner = THIS_MODULE;
+
+	cdev_err = cdev_add(&GPS_cdev, dev, GPS_devs);
+	if (cdev_err != 0)
+		goto error;
+#if WMT_CREATE_NODE_DYNAMIC || REMOVE_MK_NODE
+
+	stpgps_class = class_create(THIS_MODULE, "stpgps");
+	if (IS_ERR(stpgps_class))
+		goto error;
+	stpgps_dev = device_create(stpgps_class, NULL, dev, NULL, "stpgps");
+	if (IS_ERR(stpgps_dev))
+		goto error;
+#endif
+	pr_info("%s driver(major %d) installed.\n", GPS_DRIVER_NAME, GPS_major);
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 80)
+	gps_wake_lock_ptr = wakeup_source_register(NULL, "gpswakelock");
+#else
+	gps_wake_lock_ptr = wakeup_source_register("gpswakelock");
+#endif
+	if (!gps_wake_lock_ptr) {
+		pr_info("%s %d: init wakeup source fail!", __func__, __LINE__);
+		goto error;
+	}
+
+	if (antSwitchFlag) {
+		pr_info("get regulator");
+		reg_id = regulator_get(stpgps_dev, "vmch");
+		if (!reg_id) {
+			pr_info("regulator_get vmch failed.\n");
+			return -1;
+		}
+
+		pr_info("regulator_get_voltage reg_id = %d uV\n",
+			regulator_get_voltage(reg_id));
+	}
+
+	return 0;
+
+error:
+
+#if WMT_CREATE_NODE_DYNAMIC || REMOVE_MK_NODE
+	if (!IS_ERR(stpgps_dev))
+		device_destroy(stpgps_class, dev);
+	if (!IS_ERR(stpgps_class)) {
+		class_destroy(stpgps_class);
+		stpgps_class = NULL;
+	}
+#endif
+	if (cdev_err == 0)
+		cdev_del(&GPS_cdev);
+
+	if (alloc_ret == 0)
+		unregister_chrdev_region(dev, GPS_devs);
+
+	return -1;
+}
+
+/*****************************************************************************/
+static int gps_remove(struct platform_device *plat_dev)
+{
+	dev_t dev = MKDEV(GPS_major, 0);
+#if WMT_CREATE_NODE_DYNAMIC || REMOVE_MK_NODE
+	device_destroy(stpgps_class, dev);
+	class_destroy(stpgps_class);
+	stpgps_class = NULL;
+#endif
+
+	cdev_del(&GPS_cdev);
+	unregister_chrdev_region(dev, GPS_devs);
+	pr_info("%s driver removed.\n", GPS_DRIVER_NAME);
+
+	wakeup_source_unregister(gps_wake_lock_ptr);
+
+	return 0;
+}
+
+/*****************************************************************************/
+static int __init gps_mod_init(void)
+{
+	int ret = 0;
+
+	pr_info("%s", __func__);
+	ret = platform_driver_register(&gps_driver);
+
+	return ret;
+}
+
+/*****************************************************************************/
+static void __exit gps_mod_exit(void)
+{
+	pr_info("%s", __func__);
+	platform_driver_unregister(&gps_driver);
+}
+
+int __init mtk_wcn_stpgps_drv_init(void)
+{
+	return gps_mod_init();
+}
+EXPORT_SYMBOL(mtk_wcn_stpgps_drv_init);
+
+void __exit mtk_wcn_stpgps_drv_exit(void)
+{
+	gps_mod_exit();
+}
+EXPORT_SYMBOL(mtk_wcn_stpgps_drv_exit);
+
+module_init(gps_mod_init);
+module_exit(gps_mod_exit);
+