qcacld-3.0: Add gettime of PTP for NON-QC platform

Implement NON-QC platform TSF and TSF PLUS.
Implement gettime of PTP.
Implement TSF PLUS for SAP/GO

CRs-Fixed: 2399624
Change-Id: Id4f41a94256a8f035ae408c168c246569185c534
diff --git a/Kbuild b/Kbuild
index 64a02f9..94de5cf 100644
--- a/Kbuild
+++ b/Kbuild
@@ -2209,6 +2209,8 @@
 cppflags-$(CONFIG_FEATURE_HL_DBS_GROUP_CREDIT_SHARING) += -DFEATURE_HL_DBS_GROUP_CREDIT_SHARING
 cppflags-$(CONFIG_CREDIT_REP_THROUGH_CREDIT_UPDATE) += -DCONFIG_CREDIT_REP_THROUGH_CREDIT_UPDATE
 
+cppflags-$(CONFIG_WLAN_SYNC_TSF_PTP) += -DWLAN_FEATURE_TSF_PTP
+cppflags-$(CONFIG_WLAN_SYNC_TSF_PLUS_EXT_GPIO_IRQ) += -DWLAN_FEATURE_TSF_PLUS_EXT_GPIO_IRQ
 cppflags-$(CONFIG_TX_DESC_HI_PRIO_RESERVE) += -DCONFIG_TX_DESC_HI_PRIO_RESERVE
 
 #Enable FW logs through ini
diff --git a/components/fw_offload/core/inc/wlan_fw_offload_main.h b/components/fw_offload/core/inc/wlan_fw_offload_main.h
index 84bc8eb..824afa3 100644
--- a/components/fw_offload/core/inc/wlan_fw_offload_main.h
+++ b/components/fw_offload/core/inc/wlan_fw_offload_main.h
@@ -158,6 +158,7 @@
  * @enable_fw_module_log_level_num: enablefw module log level num
  * @is_rate_limit_enabled: Enable/disable RA rate limited
  * @tsf_gpio_pin: TSF GPIO Pin config
+ * @tsf_irq_host_gpio_pin: TSF GPIO Pin config
  * @tsf_ptp_options: TSF Plus feature options config
  * @lprx_enable: LPRx feature enable config
  * @sae_enable: SAE feature enable config
@@ -196,6 +197,9 @@
 	uint32_t tsf_gpio_pin;
 #ifdef WLAN_FEATURE_TSF_PLUS
 	uint32_t tsf_ptp_options;
+#ifdef WLAN_FEATURE_TSF_PLUS_EXT_GPIO_IRQ
+	uint32_t tsf_irq_host_gpio_pin;
+#endif
 #endif
 #endif
 	bool lprx_enable;
diff --git a/components/fw_offload/core/src/wlan_fw_offload_main.c b/components/fw_offload/core/src/wlan_fw_offload_main.c
index 860789e..4a1305f 100644
--- a/components/fw_offload/core/src/wlan_fw_offload_main.c
+++ b/components/fw_offload/core/src/wlan_fw_offload_main.c
@@ -356,6 +356,32 @@
 }
 #endif
 
+#ifdef WLAN_FEATURE_TSF_PLUS_EXT_GPIO_IRQ
+/**
+ * ucfg_fwol_fetch_tsf_irq_host_gpio_pin: Populate the
+ * tsf_irq_host_gpio_pin from cfg
+ * @psoc: The global psoc handler
+ * @fwol_cfg: The cfg structure
+ *
+ * This function is used to populate the cfg value of host platform
+ * gpio pin configured to receive tsf interrupt from fw.
+ *
+ * Return: none
+ */
+static void
+ucfg_fwol_fetch_tsf_irq_host_gpio_pin(struct wlan_objmgr_psoc *psoc,
+				      struct wlan_fwol_cfg *fwol_cfg)
+{
+	fwol_cfg->tsf_irq_host_gpio_pin =
+		cfg_get(psoc, CFG_SET_TSF_IRQ_HOST_GPIO_PIN);
+}
+#else
+static void
+ucfg_fwol_fetch_tsf_irq_host_gpio_pin(struct wlan_objmgr_psoc *psoc,
+				      struct wlan_fwol_cfg *fwol_cfg)
+{
+}
+#endif
 /**
  * ucfg_fwol_init_sae_cfg: Populate the sae control config from cfg
  * @psoc: The global psoc handler
@@ -448,6 +474,7 @@
 	fwol_init_adapt_dwelltime_in_cfg(psoc, &fwol_cfg->dwelltime_params);
 	ucfg_fwol_fetch_ra_filter(psoc, fwol_cfg);
 	ucfg_fwol_fetch_tsf_gpio_pin(psoc, fwol_cfg);
+	ucfg_fwol_fetch_tsf_irq_host_gpio_pin(psoc, fwol_cfg);
 	ucfg_fwol_fetch_dhcp_server_settings(psoc, fwol_cfg);
 
 	return status;
diff --git a/components/fw_offload/dispatcher/inc/cfg_fwol_generic.h b/components/fw_offload/dispatcher/inc/cfg_fwol_generic.h
index b37bf19..d090008 100644
--- a/components/fw_offload/dispatcher/inc/cfg_fwol_generic.h
+++ b/components/fw_offload/dispatcher/inc/cfg_fwol_generic.h
@@ -434,6 +434,34 @@
 		CFG_VALUE_OR_DEFAULT, \
 		"GPIO pin to toggle when capture tsf")
 
+#ifdef WLAN_FEATURE_TSF_PLUS_EXT_GPIO_IRQ
+/* <ini>
+ * gtsf_irq_host_gpio_pin
+ * @Min: 0
+ * @Max: 254
+ * @Default: 255
+ *
+ * TSF irq GPIO pin of host platform
+ *
+ * Related: None
+ *
+ * Usage: Internal
+ *
+ * </ini>
+ */
+#define CFG_SET_TSF_IRQ_HOST_GPIO_PIN CFG_INI_INT( \
+		"gtsf_irq_host_gpio_pin", \
+		0, \
+		254, \
+		255, \
+		CFG_VALUE_OR_DEFAULT, \
+		"TSF irq GPIO pin of host platform")
+
+#define __CFG_SET_TSF_IRQ_HOST_GPIO_PIN CFG(CFG_SET_TSF_IRQ_HOST_GPIO_PIN)
+#else
+#define __CFG_SET_TSF_IRQ_HOST_GPIO_PIN
+#endif
+
 #if defined(WLAN_FEATURE_TSF) && defined(WLAN_FEATURE_TSF_PLUS)
 /* <ini>
  * gtsf_ptp_options: TSF Plus feature options
@@ -464,6 +492,7 @@
 		0xf, \
 		CFG_VALUE_OR_DEFAULT, \
 		"TSF Plus feature options")
+
 #define __CFG_SET_TSF_PTP_OPT CFG(CFG_SET_TSF_PTP_OPT)
 #else
 #define __CFG_SET_TSF_PTP_OPT
@@ -655,6 +684,7 @@
 	CFG(CFG_ENABLE_FW_MODULE_LOG_LEVEL) \
 	CFG(CFG_RA_FILTER_ENABLE) \
 	CFG(CFG_SET_TSF_GPIO_PIN) \
+	__CFG_SET_TSF_IRQ_HOST_GPIO_PIN \
 	__CFG_SET_TSF_PTP_OPT \
 	CFG(CFG_LPRX) \
 	__CFG_IS_SAE_ENABLED \
diff --git a/components/fw_offload/dispatcher/inc/wlan_fwol_ucfg_api.h b/components/fw_offload/dispatcher/inc/wlan_fwol_ucfg_api.h
index a29a161..32b14db 100644
--- a/components/fw_offload/dispatcher/inc/wlan_fwol_ucfg_api.h
+++ b/components/fw_offload/dispatcher/inc/wlan_fwol_ucfg_api.h
@@ -304,6 +304,19 @@
 QDF_STATUS ucfg_fwol_get_tsf_gpio_pin(struct wlan_objmgr_psoc *psoc,
 				      uint32_t *tsf_gpio_pin);
 
+#ifdef WLAN_FEATURE_TSF_PLUS_EXT_GPIO_IRQ
+/**
+ * ucfg_fwol_get_tsf_irq_host_gpio_pin() - Assigns tsf_irq_host_gpio_pin value
+ * @psoc: pointer to the psoc object
+ *
+ * Return: QDF Status
+ */
+
+QDF_STATUS
+ucfg_fwol_get_tsf_irq_host_gpio_pin(struct wlan_objmgr_psoc *psoc,
+				    uint32_t *tsf_irq_host_gpio_pin);
+#endif
+
 #ifdef DHCP_SERVER_OFFLOAD
 /**
  * ucfg_fwol_get_enable_dhcp_server_offload()-Assign enable_dhcp_server_offload
diff --git a/components/fw_offload/dispatcher/src/wlan_fwol_ucfg_api.c b/components/fw_offload/dispatcher/src/wlan_fwol_ucfg_api.c
index ed270b6..fc7f59a 100644
--- a/components/fw_offload/dispatcher/src/wlan_fwol_ucfg_api.c
+++ b/components/fw_offload/dispatcher/src/wlan_fwol_ucfg_api.c
@@ -558,6 +558,27 @@
 	*tsf_ptp_options = fwol_obj->cfg.tsf_ptp_options;
 	return QDF_STATUS_SUCCESS;
 }
+
+#ifdef WLAN_FEATURE_TSF_PLUS_EXT_GPIO_IRQ
+QDF_STATUS
+ucfg_fwol_get_tsf_irq_host_gpio_pin(struct wlan_objmgr_psoc *psoc,
+				    uint32_t *tsf_irq_host_gpio_pin)
+{
+	struct wlan_fwol_psoc_obj *fwol_obj;
+
+	fwol_obj = fwol_get_psoc_obj(psoc);
+	if (!fwol_obj) {
+		fwol_err("Failed to get FWOL obj");
+		*tsf_irq_host_gpio_pin =
+			cfg_default(CFG_SET_TSF_IRQ_HOST_GPIO_PIN);
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	*tsf_irq_host_gpio_pin = fwol_obj->cfg.tsf_irq_host_gpio_pin;
+	return QDF_STATUS_SUCCESS;
+}
+
+#endif
 #endif
 #else
 QDF_STATUS ucfg_fwol_get_tsf_gpio_pin(struct wlan_objmgr_psoc *psoc,
@@ -571,6 +592,7 @@
 {
 	return QDF_STATUS_E_NOSUPPORT;
 }
+
 #endif
 
 QDF_STATUS ucfg_fwol_get_lprx_enable(struct wlan_objmgr_psoc *psoc,
@@ -594,6 +616,7 @@
 {
 	return cfg_get(psoc, CFG_IS_SAE_ENABLED);
 }
+
 #else
 bool ucfg_fwol_get_sae_enable(struct wlan_objmgr_psoc *psoc)
 {
diff --git a/configs/genoa.pci.debug_defconfig b/configs/genoa.pci.debug_defconfig
index d64cb5f..d8edee4 100644
--- a/configs/genoa.pci.debug_defconfig
+++ b/configs/genoa.pci.debug_defconfig
@@ -47,6 +47,13 @@
        CONFIG_WLAN_POWER_DEBUGFS := y
 endif
 
+ifeq ($(CONFIG_NETWORK_PHY_TIMESTAMPING), y)
+	CONFIG_WLAN_SYNC_TSF_PLUS := y
+	CONFIG_WLAN_SYNC_TSF_PTP := y
+	CONFIG_WLAN_SYNC_TSF_PLUS_EXT_GPIO_IRQ := y
+endif
+
+
 ifeq ($(CONFIG_SLUB_DEBUG_ON), y)
 CONFIG_DESC_DUP_DETECT_DEBUG := y
 CONFIG_DEBUG_RX_RING_BUFFER := y
diff --git a/configs/genoa.pci.perf_defconfig b/configs/genoa.pci.perf_defconfig
index 0c6617e..f76490c 100644
--- a/configs/genoa.pci.perf_defconfig
+++ b/configs/genoa.pci.perf_defconfig
@@ -46,6 +46,12 @@
        CONFIG_WLAN_POWER_DEBUGFS := n
 endif
 
+ifeq ($(CONFIG_NETWORK_PHY_TIMESTAMPING), y)
+	CONFIG_WLAN_SYNC_TSF_PLUS := y
+	CONFIG_WLAN_SYNC_TSF_PTP := y
+	CONFIG_WLAN_SYNC_TSF_PLUS_EXT_GPIO_IRQ := y
+endif
+
 ifeq ($(CONFIG_SLUB_DEBUG_ON), y)
 CONFIG_DESC_DUP_DETECT_DEBUG := n
 CONFIG_DEBUG_RX_RING_BUFFER := n
diff --git a/configs/genoa.usb.debug_defconfig b/configs/genoa.usb.debug_defconfig
index f6cd57e..ca4720e 100644
--- a/configs/genoa.usb.debug_defconfig
+++ b/configs/genoa.usb.debug_defconfig
@@ -27,6 +27,12 @@
        CONFIG_WLAN_POWER_DEBUGFS := y
 endif
 
+ifeq ($(CONFIG_NETWORK_PHY_TIMESTAMPING), y)
+	CONFIG_WLAN_SYNC_TSF_PLUS := y
+	CONFIG_WLAN_SYNC_TSF_PTP := y
+	CONFIG_WLAN_SYNC_TSF_PLUS_EXT_GPIO_IRQ := y
+endif
+
 # Features gets enabled on slub debug
 CONFIG_WLAN_DEBUG_CRASH_INJECT := y
 CONFIG_FEATURE_MEMDUMP_ENABLE := y
diff --git a/configs/genoa.usb.perf_defconfig b/configs/genoa.usb.perf_defconfig
index 5cfd4ca..de73a4a 100644
--- a/configs/genoa.usb.perf_defconfig
+++ b/configs/genoa.usb.perf_defconfig
@@ -32,6 +32,11 @@
 CONFIG_LEAK_DETECTION := n
 endif
 
+ifeq ($(CONFIG_NETWORK_PHY_TIMESTAMPING), y)
+	CONFIG_WLAN_SYNC_TSF_PLUS := y
+	CONFIG_WLAN_SYNC_TSF_PTP := y
+	CONFIG_WLAN_SYNC_TSF_PLUS_EXT_GPIO_IRQ := y
+endif
 
 CONFIG_ENABLE_SIZE_OPTIMIZE := y
 
diff --git a/core/hdd/inc/wlan_hdd_main.h b/core/hdd/inc/wlan_hdd_main.h
index d855172..057101c 100644
--- a/core/hdd/inc/wlan_hdd_main.h
+++ b/core/hdd/inc/wlan_hdd_main.h
@@ -61,6 +61,10 @@
 #if defined(WLAN_OPEN_SOURCE) && defined(CONFIG_HAS_WAKELOCK)
 #include <linux/wakelock.h>
 #endif
+#ifdef WLAN_FEATURE_TSF_PTP
+#include <linux/ptp_classify.h>
+#include <linux/ptp_clock_kernel.h>
+#endif
 #include <wlan_hdd_ftm.h>
 #include "wlan_hdd_tdls.h"
 #include "wlan_hdd_tsf.h"
@@ -1807,6 +1811,10 @@
 	/* the context that is capturing tsf */
 	struct hdd_adapter *cap_tsf_context;
 #endif
+#ifdef WLAN_FEATURE_TSF_PTP
+	struct ptp_clock_info ptp_cinfo;
+	struct ptp_clock *ptp_clock;
+#endif
 	uint8_t bt_a2dp_active:1;
 	uint8_t bt_vo_active:1;
 	enum band_info curr_band;
diff --git a/core/hdd/inc/wlan_hdd_tsf.h b/core/hdd/inc/wlan_hdd_tsf.h
index 81235ec..547e19d 100644
--- a/core/hdd/inc/wlan_hdd_tsf.h
+++ b/core/hdd/inc/wlan_hdd_tsf.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2018 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2019 The Linux Foundation. All rights reserved.
  *
  * Permission to use, copy, modify, and/or distribute this software for
  * any purpose with or without fee is hereby granted, provided that the
@@ -316,4 +316,15 @@
 }
 #endif
 
+#ifdef WLAN_FEATURE_TSF_PTP
+/**
+ * wlan_get_ts_info() - return ts info to uplayer
+ * @dev: pointer to net_device
+ * @info: pointer to ethtool_ts_info
+ *
+ * Return: Describe the execute result of this routine
+ */
+int wlan_get_ts_info(struct net_device *dev, struct ethtool_ts_info *info);
+
+#endif
 #endif
diff --git a/core/hdd/src/wlan_hdd_hostapd.c b/core/hdd/src/wlan_hdd_hostapd.c
index 3606d98..05dcdee 100644
--- a/core/hdd/src/wlan_hdd_hostapd.c
+++ b/core/hdd/src/wlan_hdd_hostapd.c
@@ -36,6 +36,7 @@
 #include <cds_sched.h>
 #include <linux/etherdevice.h>
 #include "osif_sync.h"
+#include <linux/ethtool.h>
 #include <wlan_hdd_includes.h>
 #include <qc_sap_ioctl.h>
 #include "osif_sync.h"
@@ -1896,6 +1897,7 @@
 						    ap_ctx->operating_channel);
 
 		hostapd_state->bss_state = BSS_START;
+		hdd_start_tsf_sync(adapter);
 
 		/* Set default key index */
 		hdd_debug("default key index %hu", ap_ctx->wep_def_key_idx);
@@ -2642,6 +2644,7 @@
 		 * re-enabled
 		 */
 		hostapd_state->bss_state = BSS_STOP;
+		hdd_stop_tsf_sync(adapter);
 
 #ifdef FEATURE_WLAN_AUTO_SHUTDOWN
 		wlan_hdd_auto_shutdown_enable(hdd_ctx, true);
@@ -3162,6 +3165,12 @@
 }
 #endif
 
+#ifdef WLAN_FEATURE_TSF_PTP
+static const struct ethtool_ops wlan_hostapd_ethtool_ops = {
+	.get_ts_info = wlan_get_ts_info,
+};
+#endif
+
 const struct net_device_ops net_ops_struct = {
 	.ndo_open = hdd_hostapd_open,
 	.ndo_stop = hdd_hostapd_stop,
@@ -3175,10 +3184,18 @@
 	.ndo_select_queue = hdd_select_queue,
 };
 
+#ifdef WLAN_FEATURE_TSF_PTP
+void hdd_set_ap_ops(struct net_device *dev)
+{
+	dev->netdev_ops = &net_ops_struct;
+	dev->ethtool_ops = &wlan_hostapd_ethtool_ops;
+}
+#else
 void hdd_set_ap_ops(struct net_device *dev)
 {
 	dev->netdev_ops = &net_ops_struct;
 }
+#endif
 
 bool hdd_sap_create_ctx(struct hdd_adapter *adapter)
 {
diff --git a/core/hdd/src/wlan_hdd_main.c b/core/hdd/src/wlan_hdd_main.c
index c3f798e..7d6000e 100644
--- a/core/hdd/src/wlan_hdd_main.c
+++ b/core/hdd/src/wlan_hdd_main.c
@@ -79,6 +79,7 @@
 #include <linux/ctype.h>
 #include <linux/compat.h>
 #include <linux/reboot.h>
+#include <linux/ethtool.h>
 #ifdef MSM_PLATFORM
 #include <soc/qcom/subsystem_restart.h>
 #endif
@@ -3743,6 +3744,12 @@
 	osif_vdev_sync_op_stop(vdev_sync);
 }
 
+#ifdef WLAN_FEATURE_TSF_PTP
+static const struct ethtool_ops wlan_ethtool_ops = {
+	.get_ts_info = wlan_get_ts_info,
+};
+#endif
+
 static const struct net_device_ops wlan_drv_ops = {
 	.ndo_open = hdd_open,
 	.ndo_stop = hdd_stop,
@@ -3764,6 +3771,7 @@
 	.ndo_get_stats = hdd_get_stats,
 };
 
+#ifdef WLAN_FEATURE_TSF_PTP
 /**
  * hdd_set_station_ops() - update net_device ops for monitor mode
  * @dev: Handle to struct net_device to be updated.
@@ -3771,17 +3779,37 @@
  */
 void hdd_set_station_ops(struct net_device *dev)
 {
-	if (QDF_GLOBAL_MONITOR_MODE == cds_get_conparam())
+	if (cds_get_conparam() == QDF_GLOBAL_MONITOR_MODE) {
+		dev->netdev_ops = &wlan_mon_drv_ops;
+	} else {
+		dev->netdev_ops = &wlan_drv_ops;
+		dev->ethtool_ops = &wlan_ethtool_ops;
+	}
+}
+#else
+void hdd_set_station_ops(struct net_device *dev)
+{
+	if (cds_get_conparam() == QDF_GLOBAL_MONITOR_MODE)
 		dev->netdev_ops = &wlan_mon_drv_ops;
 	else
 		dev->netdev_ops = &wlan_drv_ops;
 }
+
+#endif
+#else
+#ifdef WLAN_FEATURE_TSF_PTP
+void hdd_set_station_ops(struct net_device *dev)
+{
+	dev->netdev_ops = &wlan_drv_ops;
+	dev->ethtool_ops = &wlan_ethtool_ops;
+}
 #else
 void hdd_set_station_ops(struct net_device *dev)
 {
 	dev->netdev_ops = &wlan_drv_ops;
 }
 #endif
+#endif
 
 /**
  * hdd_alloc_station_adapter() - allocate the station hdd adapter
diff --git a/core/hdd/src/wlan_hdd_tsf.c b/core/hdd/src/wlan_hdd_tsf.c
index 1cd28ad..8149cca 100644
--- a/core/hdd/src/wlan_hdd_tsf.c
+++ b/core/hdd/src/wlan_hdd_tsf.c
@@ -27,6 +27,10 @@
 #include "wlan_fwol_ucfg_api.h"
 #include <qca_vendor.h>
 #include <linux/errqueue.h>
+#ifdef WLAN_FEATURE_TSF_PLUS_EXT_GPIO_IRQ
+#include <linux/gpio.h>
+static int tsf_gpio_irq_num = -1;
+#endif
 #include "ol_txrx_api.h"
 
 static struct completion tsf_sync_get_completion_evt;
@@ -35,6 +39,16 @@
 #define WLAN_HDD_CAPTURE_TSF_INIT_INTERVAL_MS 100
 #define WLAN_HDD_SOFTAP_INTERVEL_TIMES 100
 
+#ifdef WLAN_FEATURE_TSF_PLUS
+#ifdef WLAN_FEATURE_TSF_PLUS_NOIRQ
+static void hdd_update_timestamp(struct hdd_adapter *adapter);
+#else
+static void
+hdd_update_timestamp(struct hdd_adapter *adapter,
+		     uint64_t target_time, uint64_t host_time);
+#endif
+#endif
+
 /**
  * enum hdd_tsf_op_result - result of tsf operation
  *
@@ -116,6 +130,7 @@
 	return true;
 }
 
+#if defined(WLAN_FEATURE_TSF_PLUS_NOIRQ) && defined(WLAN_FEATURE_TSF_PLUS)
 /**
  * hdd_tsf_reset_gpio() - Reset TSF GPIO used for host timer sync
  * @adapter: pointer to adapter
@@ -125,7 +140,6 @@
  *
  * Return: TSF_RETURN on Success, TSF_RESET_GPIO_FAIL on failure
  */
-#if defined(WLAN_FEATURE_TSF_PLUS_NOIRQ) && defined(WLAN_FEATURE_TSF_PLUS)
 static int hdd_tsf_reset_gpio(struct hdd_adapter *adapter)
 {
 	/* No GPIO Host timer sync for integrated WIFI Device */
@@ -145,7 +159,54 @@
 {
 	return QDF_STATUS_SUCCESS;
 }
+#else
+static int hdd_tsf_reset_gpio(struct hdd_adapter *adapter)
+{
+	int ret;
 
+	ret = wma_cli_set_command((int)adapter->vdev_id,
+				  (int)GEN_PARAM_RESET_TSF_GPIO,
+				  adapter->vdev_id,
+				  GEN_CMD);
+
+	if (ret != 0) {
+		hdd_err("tsf reset GPIO fail ");
+		ret = TSF_RESET_GPIO_FAIL;
+	} else {
+		ret = TSF_RETURN;
+	}
+	return ret;
+}
+
+/**
+ * hdd_tsf_set_gpio() - Set TSF GPIO used for host timer sync
+ * @hdd_ctx: pointer to hdd context
+ *
+ * This function check GPIO and set GPIO as IRQ to FW side on
+ * none Adrastea arch
+ *
+ * Return: QDF_STATUS_SUCCESS on Success, others on Failure.
+ */
+static QDF_STATUS hdd_tsf_set_gpio(struct hdd_context *hdd_ctx)
+{
+	QDF_STATUS status;
+	uint32_t tsf_gpio_pin = TSF_GPIO_PIN_INVALID;
+
+	status = ucfg_fwol_get_tsf_gpio_pin(hdd_ctx->psoc, &tsf_gpio_pin);
+	if (QDF_IS_STATUS_ERROR(status))
+		return QDF_STATUS_E_INVAL;
+
+	if (tsf_gpio_pin == TSF_GPIO_PIN_INVALID)
+		return QDF_STATUS_E_INVAL;
+
+	status = sme_set_tsf_gpio(hdd_ctx->mac_handle,
+				  tsf_gpio_pin);
+
+	return status;
+}
+#endif
+
+#ifdef WLAN_FEATURE_TSF_PLUS
 bool hdd_tsf_is_ptp_enabled(struct hdd_context *hdd)
 {
 	uint32_t tsf_ptp_options;
@@ -200,51 +261,6 @@
 	else
 		return false;
 }
-
-#else
-static int hdd_tsf_reset_gpio(struct hdd_adapter *adapter)
-{
-	int ret;
-
-	ret = wma_cli_set_command((int)adapter->vdev_id,
-			(int)GEN_PARAM_RESET_TSF_GPIO, adapter->vdev_id,
-			GEN_CMD);
-
-	if (ret != 0) {
-		hdd_err("tsf reset GPIO fail ");
-		ret = TSF_RESET_GPIO_FAIL;
-	} else {
-		ret = TSF_RETURN;
-	}
-	return ret;
-}
-
-/**
- * hdd_tsf_set_gpio() - Set TSF GPIO used for host timer sync
- * @hdd_ctx: pointer to hdd context
- *
- * This function check GPIO and set GPIO as IRQ to FW side on
- * none Adrastea arch
- *
- * Return: QDF_STATUS_SUCCESS on Success, others on Failure.
- */
-static QDF_STATUS hdd_tsf_set_gpio(struct hdd_context *hdd_ctx)
-{
-	QDF_STATUS status;
-	uint32_t tsf_gpio_pin = TSF_GPIO_PIN_INVALID;
-
-	status = ucfg_fwol_get_tsf_gpio_pin(hdd_ctx->psoc, &tsf_gpio_pin);
-	if (QDF_IS_STATUS_ERROR(status))
-		return QDF_STATUS_E_INVAL;
-
-	if (tsf_gpio_pin == TSF_GPIO_PIN_INVALID)
-		return QDF_STATUS_E_INVAL;
-
-	status = sme_set_tsf_gpio(hdd_ctx->mac_handle,
-				  tsf_gpio_pin);
-
-	return status;
-}
 #endif
 
 static enum hdd_tsf_op_result hdd_capture_tsf_internal(
@@ -387,7 +403,11 @@
 /* to distinguish 32-bit overflow case, this inverval should:
  * equal or less than (1/2 * OVERFLOW_INDICATOR32 us)
  */
+#ifdef WLAN_FEATURE_TSF_PLUS_EXT_GPIO_IRQ
+#define WLAN_HDD_CAPTURE_TSF_INTERVAL_SEC 2
+#else
 #define WLAN_HDD_CAPTURE_TSF_INTERVAL_SEC 10
+#endif
 #define OVERFLOW_INDICATOR32 (((int64_t)0x1) << 32)
 #define CAP_TSF_TIMER_FIX_SEC 1
 
@@ -674,6 +694,9 @@
 	if (!arg)
 		return IRQ_NONE;
 
+	if (irq != tsf_gpio_irq_num)
+		return IRQ_NONE;
+
 	hdd_ctx = (struct hdd_context *)arg;
 	host_time = hdd_get_monotonic_host_time(hdd_ctx);
 
@@ -1344,6 +1367,99 @@
 	return HDD_TSF_OP_SUCC;
 }
 #else
+#ifdef WLAN_FEATURE_TSF_PLUS_EXT_GPIO_IRQ
+static
+enum hdd_tsf_op_result wlan_hdd_tsf_plus_init(struct hdd_context *hdd_ctx)
+{
+	int ret;
+	QDF_STATUS status;
+	uint32_t tsf_irq_gpio_pin = TSF_GPIO_PIN_INVALID;
+
+	if (!hdd_tsf_is_ptp_enabled(hdd_ctx)) {
+		hdd_info("To enable TSF_PLUS, set gtsf_ptp_options in ini");
+		goto fail;
+	}
+
+	status = ucfg_fwol_get_tsf_irq_host_gpio_pin(hdd_ctx->psoc,
+						     &tsf_irq_gpio_pin);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		hdd_err("tsf gpio irq host pin error");
+		goto fail;
+	}
+
+	if (tsf_irq_gpio_pin == TSF_GPIO_PIN_INVALID) {
+		hdd_err("gpio host pin is invalid");
+		goto fail;
+	}
+
+	ret = gpio_request(tsf_irq_gpio_pin, "wlan_tsf");
+	if (ret) {
+		hdd_err("gpio host pin is invalid");
+		goto fail;
+	}
+
+	ret = gpio_direction_input(tsf_irq_gpio_pin);
+	if (ret) {
+		hdd_err("gpio host pin is invalid");
+		goto fail_free_gpio;
+	}
+
+	tsf_gpio_irq_num = gpio_to_irq(tsf_irq_gpio_pin);
+	if (tsf_gpio_irq_num < 0) {
+		hdd_err("fail to get irq: %d", tsf_gpio_irq_num);
+		goto fail_free_gpio;
+	}
+
+	ret = request_irq(tsf_gpio_irq_num, hdd_tsf_captured_irq_handler,
+			  IRQF_SHARED | IRQF_TRIGGER_RISING, "wlan_tsf",
+			  hdd_ctx);
+
+	if (ret) {
+		hdd_err("Failed to register irq handler: %d", ret);
+		goto fail_free_gpio;
+	}
+
+	if (hdd_tsf_is_tx_set(hdd_ctx))
+		ol_register_timestamp_callback(hdd_tx_timestamp);
+
+	return HDD_TSF_OP_SUCC;
+
+fail_free_gpio:
+	gpio_free(tsf_irq_gpio_pin);
+fail:
+	tsf_gpio_irq_num = -1;
+	return HDD_TSF_OP_FAIL;
+}
+
+static
+enum hdd_tsf_op_result wlan_hdd_tsf_plus_deinit(struct hdd_context *hdd_ctx)
+{
+	QDF_STATUS status;
+	uint32_t tsf_irq_gpio_pin = TSF_GPIO_PIN_INVALID;
+
+	if (!hdd_tsf_is_ptp_enabled(hdd_ctx))
+		return HDD_TSF_OP_SUCC;
+
+	status = ucfg_fwol_get_tsf_irq_host_gpio_pin(hdd_ctx->psoc,
+						     &tsf_irq_gpio_pin);
+	if (QDF_IS_STATUS_ERROR(status))
+		return QDF_STATUS_E_INVAL;
+
+	if (tsf_irq_gpio_pin == TSF_GPIO_PIN_INVALID)
+		return QDF_STATUS_E_INVAL;
+
+	if (hdd_tsf_is_tx_set(hdd_ctx))
+		ol_deregister_timestamp_callback();
+
+	if (tsf_gpio_irq_num >= 0) {
+		free_irq(tsf_gpio_irq_num, hdd_ctx);
+		tsf_gpio_irq_num = -1;
+		gpio_free(tsf_irq_gpio_pin);
+	}
+
+	return HDD_TSF_OP_SUCC;
+}
+#else
 static inline
 enum hdd_tsf_op_result wlan_hdd_tsf_plus_init(struct hdd_context *hdd_ctx)
 {
@@ -1392,6 +1508,7 @@
 }
 #endif
 
+#endif
 void hdd_tsf_notify_wlan_state_change(struct hdd_adapter *adapter,
 				      eConnectionState old_state,
 				      eConnectionState new_state)
@@ -1448,6 +1565,197 @@
 	return __hdd_indicate_tsf(adapter, buf, len);
 }
 
+#ifdef WLAN_FEATURE_TSF_PTP
+int wlan_get_ts_info(struct net_device *dev, struct ethtool_ts_info *info)
+
+{
+	struct hdd_adapter *adapter = netdev_priv(dev);
+	struct osif_vdev_sync *vdev_sync;
+	struct hdd_context *hdd_ctx;
+	int errno;
+
+	hdd_ctx = WLAN_HDD_GET_CTX(adapter);
+	errno = wlan_hdd_validate_context(hdd_ctx);
+	if (errno)
+		return -EINVAL;
+
+	errno = osif_vdev_sync_op_start(dev, &vdev_sync);
+	if (errno)
+		return -EAGAIN;
+
+	info->so_timestamping = SOF_TIMESTAMPING_TX_HARDWARE |
+				 SOF_TIMESTAMPING_RX_HARDWARE |
+				 SOF_TIMESTAMPING_RAW_HARDWARE;
+	if (hdd_ctx->ptp_clock)
+		info->phc_index = ptp_clock_index(hdd_ctx->ptp_clock);
+	else
+		info->phc_index = -1;
+
+	osif_vdev_sync_op_stop(vdev_sync);
+	return 0;
+}
+
+#if (KERNEL_VERSION(4, 1, 0) > LINUX_VERSION_CODE)
+/**
+ * wlan_ptp_gettime() - return fw ts info to uplayer
+ * @ptp: pointer to ptp_clock_info.
+ * @ts: pointer to timespec.
+ *
+ * Return: Describe the execute result of this routine
+ */
+static int wlan_ptp_gettime(struct ptp_clock_info *ptp, struct timespec *ts)
+{
+	uint64_t host_time, target_time = 0;
+	struct hdd_context *hdd_ctx;
+	struct hdd_adapter *adapter;
+	uint32_t tsf_reg_read_enabled;
+	struct osif_psoc_sync *psoc_sync;
+	int errno, status = 0;
+
+	hdd_ctx = qdf_container_of(ptp, struct hdd_context, ptp_cinfo);
+	errno = wlan_hdd_validate_context(hdd_ctx);
+	if (errno)
+		return -EINVAL;
+
+	errno = osif_psoc_sync_op_start(hdd_ctx->parent_dev, &psoc_sync);
+	if (errno)
+		return -EAGAIN;
+
+	adapter = hdd_get_adapter(hdd_ctx, QDF_P2P_GO_MODE);
+	if (!adapter) {
+		adapter = hdd_get_adapter(hdd_ctx, QDF_P2P_CLIENT_MODE);
+		if (!adapter) {
+			adapter = hdd_get_adapter(hdd_ctx, QDF_SAP_MODE);
+			if (!adapter)
+				adapter = hdd_get_adapter(hdd_ctx,
+							  QDF_STA_MODE);
+				if (!adapter) {
+					status = -EOPNOTSUPP;
+					goto end;
+				}
+		}
+	}
+
+	host_time = hdd_get_monotonic_host_time(hdd_ctx);
+	if (hdd_get_targettime_from_hosttime(adapter, host_time,
+					     &target_time)) {
+		hdd_err("get invalid target timestamp");
+		status = -EINVAL;
+		goto end;
+	}
+	*ts = ns_to_timespec(target_time * NSEC_PER_USEC);
+
+end:
+	osif_psoc_sync_op_stop(psoc_sync);
+	return status;
+}
+
+/**
+ * wlan_hdd_phc_init() - phc init
+ * @hdd_ctx: pointer to the hdd_contex.
+ *
+ * Return: NULL
+ */
+static void wlan_hdd_phc_init(struct hdd_context *hdd_ctx)
+{
+	hdd_ctx->ptp_cinfo.gettime = wlan_ptp_gettime;
+
+	hdd_ctx->ptp_clock = ptp_clock_register(&hdd_ctx->ptp_cinfo,
+						hdd_ctx->parent_dev);
+}
+
+/**
+ * wlan_hdd_phc_deinit() - phc deinit
+ * @hdd_ctx: pointer to the hdd_contex.
+ *
+ * Return: NULL
+ */
+static void wlan_hdd_phc_deinit(struct hdd_context *hdd_ctx)
+{
+	hdd_ctx->ptp_cinfo.gettime = NULL;
+
+	if (hdd_ctx->ptp_clock) {
+		ptp_clock_unregister(hdd_ctx->ptp_clock);
+		hdd_ctx->ptp_clock = NULL;
+	}
+}
+
+#else
+static int wlan_ptp_gettime(struct ptp_clock_info *ptp, struct timespec64 *ts)
+{
+	uint64_t host_time, target_time = 0;
+	struct hdd_context *hdd_ctx;
+	struct hdd_adapter *adapter;
+	struct osif_psoc_sync *psoc_sync;
+	int errno, status = 0;
+
+	hdd_ctx = qdf_container_of(ptp, struct hdd_context, ptp_cinfo);
+	errno = wlan_hdd_validate_context(hdd_ctx);
+	if (errno)
+		return -EINVAL;
+
+	errno = osif_psoc_sync_op_start(hdd_ctx->parent_dev, &psoc_sync);
+	if (errno)
+		return -EAGAIN;
+
+	adapter = hdd_get_adapter(hdd_ctx, QDF_P2P_GO_MODE);
+	if (!adapter) {
+		adapter = hdd_get_adapter(hdd_ctx, QDF_P2P_CLIENT_MODE);
+		if (!adapter) {
+			adapter = hdd_get_adapter(hdd_ctx, QDF_SAP_MODE);
+			if (!adapter)
+				adapter = hdd_get_adapter(hdd_ctx,
+							  QDF_STA_MODE);
+				if (!adapter) {
+					status = -EOPNOTSUPP;
+					goto end;
+				}
+		}
+	}
+
+	host_time = hdd_get_monotonic_host_time(hdd_ctx);
+	if (hdd_get_targettime_from_hosttime(adapter, host_time,
+					     &target_time)) {
+		hdd_err("get invalid target timestamp");
+		status = -EINVAL;
+		goto end;
+	}
+	*ts = ns_to_timespec64(target_time * NSEC_PER_USEC);
+
+end:
+	osif_psoc_sync_op_stop(psoc_sync);
+	return status;
+}
+
+static void wlan_hdd_phc_init(struct hdd_context *hdd_ctx)
+{
+	hdd_ctx->ptp_cinfo.gettime64 = wlan_ptp_gettime;
+	hdd_ctx->ptp_clock = ptp_clock_register(&hdd_ctx->ptp_cinfo,
+						hdd_ctx->parent_dev);
+}
+
+static void wlan_hdd_phc_deinit(struct hdd_context *hdd_ctx)
+{
+	hdd_ctx->ptp_cinfo.gettime64 = NULL;
+
+	if (hdd_ctx->ptp_clock) {
+		ptp_clock_unregister(hdd_ctx->ptp_clock);
+		hdd_ctx->ptp_clock = NULL;
+	}
+}
+
+#endif
+#else
+
+static void wlan_hdd_phc_init(struct hdd_context *hdd_ctx)
+{
+}
+
+static void wlan_hdd_phc_deinit(struct hdd_context *hdd_ctx)
+{
+}
+#endif /* WLAN_FEATURE_TSF_PTP */
+
 /**
  * hdd_get_tsf_cb() - handle tsf callback
  * @pcb_cxt: pointer to the hdd_contex
@@ -1516,6 +1824,7 @@
 
 	adapter->cur_tsf_sync_soc_time =
 		qdf_log_timestamp_to_usecs(tsf_sync_soc_time) * NSEC_PER_USEC;
+
 	complete(&tsf_sync_get_completion_evt);
 	hdd_update_tsf(adapter, adapter->cur_target_time);
 	hdd_info("Vdev=%u, tsf_low=%u, tsf_high=%u ptsf->soc_timer_low=%u ptsf->soc_timer_high=%u",
@@ -1550,7 +1859,7 @@
 	struct nlattr *tb_vendor[QCA_WLAN_VENDOR_ATTR_TSF_MAX + 1];
 	int status, ret;
 	struct sk_buff *reply_skb;
-	uint32_t tsf_op_resp[3], tsf_cmd;
+	uint32_t tsf_op_resp[3] = {0}, tsf_cmd;
 
 	hdd_enter_dev(wdev->netdev);
 
@@ -1699,6 +2008,8 @@
 	if (wlan_hdd_tsf_plus_init(hdd_ctx) != HDD_TSF_OP_SUCC)
 		goto fail;
 
+	wlan_hdd_phc_init(hdd_ctx);
+
 	return;
 
 fail:
@@ -1713,6 +2024,7 @@
 	if (!qdf_atomic_read(&hdd_ctx->tsf_ready_flag))
 		return;
 
+	wlan_hdd_phc_deinit(hdd_ctx);
 	wlan_hdd_tsf_plus_deinit(hdd_ctx);
 	qdf_atomic_set(&hdd_ctx->tsf_ready_flag, 0);
 	qdf_atomic_set(&hdd_ctx->cap_tsf_flag, 0);