[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);
+