qcacmn: Support IPQ4019 driver probe and detach

Add AHB bus type support.

Change-Id: I968f3ae06bb63a2116a9d24d75957f397a0e8c50
Acked-by: Balamurugan Mahalingam <bmahalin@codeaurora.org>
CRs-Fixed: 1009050
diff --git a/hif/inc/regtable_pcie.h b/hif/inc/regtable_pcie.h
index 753271b..c3ebb64 100644
--- a/hif/inc/regtable_pcie.h
+++ b/hif/inc/regtable_pcie.h
@@ -364,7 +364,7 @@
 /* PLL end */
 
 #define FW_CPU_PLL_CONFIG \
-	(sc->targetdef->d_FW_CPU_PLL_CONFIG)
+	(scn->targetdef->d_FW_CPU_PLL_CONFIG)
 
 #define WIFICMN_PCIE_BAR_REG_ADDRESS \
 	(sc->targetdef->d_WIFICMN_PCIE_BAR_REG_ADDRESS)
diff --git a/hif/src/dispatcher/ahb_api.h b/hif/src/dispatcher/ahb_api.h
new file mode 100644
index 0000000..e53c175
--- /dev/null
+++ b/hif/src/dispatcher/ahb_api.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2013-2016 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
+ * above copyright notice and this permission notice appear in all
+ * copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+ * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef __AHB_API_H
+#define __AHB_API_H
+
+QDF_STATUS hif_ahb_open(struct hif_softc *hif_ctx,
+			 enum qdf_bus_type bus_type);
+void hif_ahb_close(struct hif_softc *hif_ctx);
+
+
+void hif_ahb_disable_isr(struct hif_softc *hif_ctx);
+void hif_ahb_nointrs(struct hif_softc *scn);
+QDF_STATUS hif_ahb_enable_bus(struct hif_softc *ol_sc,
+			  struct device *dev, void *bdev,
+			  const hif_bus_id *bid,
+			  enum hif_enable_type type);
+void hif_ahb_disable_bus(struct hif_softc *scn);
+int hif_ahb_bus_configure(struct hif_softc *scn);
+void hif_ahb_irq_disable(struct hif_softc *scn, int ce_id);
+void hif_ahb_irq_enable(struct hif_softc *scn, int ce_id);
+int hif_ahb_dump_registers(struct hif_softc *scn);
+
+#endif
diff --git a/hif/src/dispatcher/multibus.c b/hif/src/dispatcher/multibus.c
index 4c2def6..d26de42 100644
--- a/hif/src/dispatcher/multibus.c
+++ b/hif/src/dispatcher/multibus.c
@@ -86,6 +86,8 @@
 	switch (bus_type) {
 	case QDF_BUS_TYPE_PCI:
 		return hif_pci_get_context_size();
+	case QDF_BUS_TYPE_AHB:
+		return hif_ahb_get_context_size();
 	case QDF_BUS_TYPE_SNOC:
 		return hif_snoc_get_context_size();
 	default:
@@ -114,6 +116,9 @@
 	case QDF_BUS_TYPE_SNOC:
 		status = hif_initialize_snoc_ops(&hif_sc->bus_ops);
 		break;
+	case QDF_BUS_TYPE_AHB:
+		status = hif_initialize_ahb_ops(&hif_sc->bus_ops);
+		break;
 	default:
 		status = QDF_STATUS_E_NOSUPPORT;
 		break;
diff --git a/hif/src/dispatcher/multibus.h b/hif/src/dispatcher/multibus.h
index afa36f9..a331206 100644
--- a/hif/src/dispatcher/multibus.h
+++ b/hif/src/dispatcher/multibus.h
@@ -100,4 +100,31 @@
 }
 #endif /* HIF_PCI */
 
+#ifdef HIF_AHB
+QDF_STATUS hif_initialize_ahb_ops(struct hif_bus_ops *bus_ops);
+int hif_ahb_get_context_size(void);
+#else
+/**
+ * hif_initialize_ahb_ops() - dummy for when ahb not supported
+ *
+ * Return: QDF_STATUS_E_NOSUPPORT
+ */
+static inline QDF_STATUS hif_initialize_ahb_ops(struct hif_bus_ops *bus_ops)
+{
+	HIF_ERROR("%s: not supported", __func__);
+	return QDF_STATUS_E_NOSUPPORT;
+}
+
+/**
+ * hif_ahb_get_context_size() - dummy for when ahb not supported
+ *
+ * Return: 0 as an invalid size to indicate no support
+ */
+static inline int hif_ahb_get_context_size(void)
+{
+	return 0;
+}
+#endif
+
+
 #endif /* _MULTIBUS_H_ */
diff --git a/hif/src/dispatcher/multibus_ahb.c b/hif/src/dispatcher/multibus_ahb.c
new file mode 100644
index 0000000..dc8966a
--- /dev/null
+++ b/hif/src/dispatcher/multibus_ahb.c
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2016 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
+ * above copyright notice and this permission notice appear in all
+ * copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+ * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "hif.h"
+#include "hif_main.h"
+#include "multibus.h"
+#include "ce_main.h"
+#include "ahb_api.h"
+#include "dummy.h"
+
+/**
+ * hif_initialize_ahb_ops() - initialize the ahb ops
+ * @bus_ops: hif_bus_ops table pointer to initialize
+ *
+ * This function will assign the set of callbacks that needs
+ * to be called for ipq4019 platform
+ *
+ * Return: QDF_STATUS_SUCCESS
+ */
+QDF_STATUS hif_initialize_ahb_ops(struct hif_bus_ops *bus_ops)
+{
+	bus_ops->hif_bus_open = &hif_ahb_open;
+	bus_ops->hif_bus_close = &hif_ahb_close;
+	bus_ops->hif_bus_prevent_linkdown = &hif_dummy_bus_prevent_linkdown;
+	bus_ops->hif_reset_soc = &hif_dummy_reset_soc;
+	bus_ops->hif_bus_suspend = &hif_dummy_bus_suspend;
+	bus_ops->hif_bus_resume = &hif_dummy_bus_resume;
+	bus_ops->hif_target_sleep_state_adjust =
+		&hif_dummy_target_sleep_state_adjust;
+
+	bus_ops->hif_disable_isr = &hif_ahb_disable_isr;
+	bus_ops->hif_nointrs = &hif_ahb_nointrs;
+	bus_ops->hif_enable_bus = &hif_ahb_enable_bus;
+	bus_ops->hif_disable_bus = &hif_ahb_disable_bus;
+	bus_ops->hif_bus_configure = &hif_ahb_bus_configure;
+	bus_ops->hif_irq_disable = &hif_ahb_irq_disable;
+	bus_ops->hif_irq_enable = &hif_ahb_irq_enable;
+	bus_ops->hif_dump_registers = &hif_ahb_dump_registers;
+	bus_ops->hif_enable_power_management =
+		&hif_dummy_enable_power_management;
+	bus_ops->hif_disable_power_management =
+		&hif_dummy_disable_power_management;
+
+	return QDF_STATUS_SUCCESS;
+}
+
+/**
+ * hif_ahb_get_context_size() - return the size of the snoc context
+ *
+ * Return the size of the context.  (0 for invalid bus)
+ */
+int hif_ahb_get_context_size(void)
+{
+	return sizeof(struct HIF_CE_state);
+}
diff --git a/hif/src/hif_main.c b/hif/src/hif_main.c
index 8510537..2dac2f4 100644
--- a/hif/src/hif_main.c
+++ b/hif/src/hif_main.c
@@ -487,7 +487,7 @@
 	qdf_atomic_init(&scn->link_suspended);
 	qdf_atomic_init(&scn->tasklet_from_intr);
 	qdf_mem_copy(&scn->callbacks, cbk, sizeof(struct hif_driver_state_callbacks));
-
+	scn->bus_type  = bus_type;
 	status = hif_bus_open(scn, bus_type);
 	if (status != QDF_STATUS_SUCCESS) {
 		HIF_ERROR("%s: hif_bus_open error = %d, bus_type = %d",
@@ -804,6 +804,12 @@
 		HIF_INFO(" *********** AR900B *************\n");
 		break;
 
+	case IPQ4019_DEVICE_ID:
+		*hif_type = HIF_TYPE_IPQ4019;
+		*target_type = TARGET_TYPE_IPQ4019;
+		HIF_INFO(" *********** IPQ4019  *************\n");
+		break;
+
 	default:
 		HIF_ERROR("%s: Unsupported device ID!", __func__);
 		ret = -ENODEV;
diff --git a/hif/src/hif_main.h b/hif/src/hif_main.h
index db6fd77..66f7b29 100644
--- a/hif/src/hif_main.h
+++ b/hif/src/hif_main.h
@@ -90,6 +90,7 @@
 #define AR900B_DEVICE_ID    (0x0040)
 #define QCA9984_DEVICE_ID   (0x0046)
 #define QCA9888_DEVICE_ID   (0x0056)
+#define IPQ4019_DEVICE_ID   (0x12ef)
 
 #define HIF_GET_PCI_SOFTC(scn) ((struct hif_pci_softc *)scn)
 #define HIF_GET_CE_STATE(scn) ((struct HIF_CE_state *)scn)
diff --git a/hif/src/pcie/if_pci.c b/hif/src/pcie/if_pci.c
index 63ae29e..3130891 100644
--- a/hif/src/pcie/if_pci.c
+++ b/hif/src/pcie/if_pci.c
@@ -176,7 +176,7 @@
 	}
 }
 
-static irqreturn_t hif_pci_interrupt_handler(int irq, void *arg)
+irqreturn_t hif_pci_interrupt_handler(int irq, void *arg)
 {
 	struct hif_pci_softc *sc = (struct hif_pci_softc *)arg;
 	struct hif_softc *scn = HIF_GET_SOFTC(sc);
@@ -891,7 +891,7 @@
 static void hif_init_reschedule_tasklet_work(struct hif_pci_softc *sc) { }
 #endif /* CONFIG_SLUB_DEBUG_ON */
 
-static void wlan_tasklet(unsigned long data)
+void wlan_tasklet(unsigned long data)
 {
 	struct hif_pci_softc *sc = (struct hif_pci_softc *)data;
 	struct hif_softc *scn = HIF_GET_SOFTC(sc);
@@ -2170,7 +2170,7 @@
 	return ret;
 }
 
-static void wlan_tasklet_msi(unsigned long data)
+void wlan_tasklet_msi(unsigned long data)
 {
 	struct hif_tasklet_entry *entry = (struct hif_tasklet_entry *)data;
 	struct hif_pci_softc *sc = (struct hif_pci_softc *) entry->hif_handler;
@@ -2338,6 +2338,9 @@
 		HIF_ERROR("%s: request_irq failed, ret = %d", __func__, ret);
 		goto end;
 	}
+	/* Use sc->irq instead of sc->pdev-irq
+	platform_device pdev doesn't have an irq field */
+	sc->irq = sc->pdev->irq;
 	/* Use Legacy PCI Interrupts */
 	hif_write32_mb(sc->mem+(SOC_CORE_BASE_ADDRESS |
 		  PCIE_INTR_ENABLE_ADDRESS),
@@ -2372,12 +2375,14 @@
 	if (sc->num_msi_intrs > 0) {
 		/* MSI interrupt(s) */
 		for (i = 0; i < sc->num_msi_intrs; i++) {
-			free_irq(sc->pdev->irq + i, sc);
+			free_irq(sc->irq + i, sc);
 		}
 		sc->num_msi_intrs = 0;
 	} else {
-		/* Legacy PCI line interrupt */
-		free_irq(sc->pdev->irq, sc);
+		/* Legacy PCI line interrupt
+		Use sc->irq instead of sc->pdev-irq
+		platform_device pdev doesn't have an irq field */
+		free_irq(sc->irq, sc);
 	}
 	ce_unregister_irq(hif_state, 0xfff);
 	scn->request_irq_done = false;
@@ -3262,8 +3267,16 @@
 }
 #endif
 
+#ifndef HIF_AHB
+int hif_ahb_configure_legacy_irq(struct hif_pci_softc *sc)
+{
+	QDF_BUG(0);
+	return -EINVAL;
+}
+#endif
+
 /**
- * hif_configure_irq(): configure interrupt
+ * hif_configure_irq() - configure interrupt
  *
  * This function configures interrupt(s)
  *
@@ -3287,7 +3300,14 @@
 			goto end;
 	}
 	/* MSI failed. Try legacy irq */
-	ret = hif_pci_configure_legacy_irq(sc);
+	switch (scn->target_info.target_type) {
+	case TARGET_TYPE_IPQ4019:
+		ret = hif_ahb_configure_legacy_irq(sc);
+		break;
+	default:
+		ret = hif_pci_configure_legacy_irq(sc);
+		break;
+	}
 	if (ret < 0) {
 		HIF_ERROR("%s: hif_pci_configure_legacy_irq error = %d",
 			__func__, ret);
diff --git a/hif/src/pcie/if_pci.h b/hif/src/pcie/if_pci.h
index 617086a..9b59153 100644
--- a/hif/src/pcie/if_pci.h
+++ b/hif/src/pcie/if_pci.h
@@ -147,6 +147,8 @@
 bool hif_pci_targ_is_present(struct hif_softc *scn, void *__iomem *mem);
 int hif_configure_irq(struct hif_softc *sc);
 void hif_pci_cancel_deferred_target_sleep(struct hif_softc *scn);
+void wlan_tasklet(unsigned long data);
+irqreturn_t hif_pci_interrupt_handler(int irq, void *arg);
 
 /*
  * A firmware interrupt to the Host is indicated by the
diff --git a/hif/src/snoc/if_ahb.c b/hif/src/snoc/if_ahb.c
new file mode 100644
index 0000000..d8bf1fb
--- /dev/null
+++ b/hif/src/snoc/if_ahb.c
@@ -0,0 +1,401 @@
+/*
+ * Copyright (c) 2013-2016 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
+ * above copyright notice and this permission notice appear in all
+ * copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+ * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/**
+ * DOC: if_ahb.c
+ *
+ * c file for ahb specific implementations.
+ */
+
+#include "hif.h"
+#include "hif_main.h"
+#include "hif_debug.h"
+#include "hif_io32.h"
+#include "ce_main.h"
+#include "ce_tasklet.h"
+#include "if_ahb.h"
+#include "if_pci.h"
+#include "ahb_api.h"
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)
+#define IRQF_DISABLED 0x00000020
+#endif
+/**
+ * hif_disable_isr() - disable isr
+ *
+ * This function disables isr and kills tasklets
+ *
+ * @hif_ctx: struct hif_softc
+ *
+ * Return: void
+ */
+void hif_ahb_disable_isr(struct hif_softc *scn)
+{
+	struct hif_pci_softc *sc = HIF_GET_PCI_SOFTC(scn);
+
+	hif_nointrs(scn);
+	ce_tasklet_kill(scn);
+	tasklet_kill(&sc->intr_tq);
+	qdf_atomic_set(&scn->active_tasklet_cnt, 0);
+}
+
+/**
+ * hif_dump_registers() - dump bus debug registers
+ * @scn: struct hif_opaque_softc
+ *
+ * This function dumps hif bus debug registers
+ *
+ * Return: 0 for success or error code
+ */
+int hif_ahb_dump_registers(struct hif_softc *hif_ctx)
+{
+	int status;
+	struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx);
+
+	status = hif_dump_ce_registers(scn);
+	if (status)
+		HIF_ERROR("%s: Dump CE Registers Failed status %d", __func__,
+							status);
+
+	return 0;
+}
+
+/**
+ * hif_ahb_close() - hif_bus_close
+ * @scn: pointer to the hif context.
+ *
+ * This is a callback function for hif_bus_close.
+ *
+ *
+ * Return: n/a
+ */
+void hif_ahb_close(struct hif_softc *scn)
+{
+	hif_ce_close(scn);
+}
+
+/**
+ * hif_bus_open() - hif_ahb open
+ * @hif_ctx: hif context
+ * @bus_type: bus type
+ *
+ * This is a callback function for hif_bus_open.
+ *
+ * Return: n/a
+ */
+QDF_STATUS hif_ahb_open(struct hif_softc *hif_ctx, enum qdf_bus_type bus_type)
+{
+
+	struct hif_pci_softc *sc = HIF_GET_PCI_SOFTC(hif_ctx);
+
+	qdf_spinlock_create(&sc->irq_lock);
+	return hif_ce_open(hif_ctx);
+}
+
+/**
+ * hif_bus_configure() - Configure the bus
+ * @scn: pointer to the hif context.
+ *
+ * This function configure the ahb bus
+ *
+ * return: 0 for success. nonzero for failure.
+ */
+int hif_ahb_bus_configure(struct hif_softc *scn)
+{
+	return hif_pci_bus_configure(scn);
+}
+
+/**
+ * hif_configure_msi_ahb - Configure MSI interrupts
+ * @sc : pointer to the hif context
+ *
+ * return: 0 for success. nonzero for failure.
+ */
+
+int hif_configure_msi_ahb(struct hif_pci_softc *sc)
+{
+	return 0;
+}
+
+/**
+ * hif_ahb_configure_legacy_irq() - Configure Legacy IRQ
+ * @sc: pointer to the hif context.
+ *
+ * This function registers the irq handler and enables legacy interrupts
+ *
+ * return: 0 for success. nonzero for failure.
+ */
+int hif_ahb_configure_legacy_irq(struct hif_pci_softc *sc)
+{
+	int ret = 0;
+	struct hif_softc *scn = HIF_GET_SOFTC(sc);
+	struct platform_device *pdev = (struct platform_device *)sc->pdev;
+	int irq = 0;
+
+	/* do not support MSI or MSI IRQ failed */
+	tasklet_init(&sc->intr_tq, wlan_tasklet, (unsigned long)sc);
+	irq = platform_get_irq_byname(pdev, "legacy");
+	if (irq < 0) {
+		dev_err(&pdev->dev, "Unable to get irq\n");
+		ret = -1;
+		goto end;
+	}
+	ret = request_irq(irq, hif_pci_interrupt_handler,
+				IRQF_DISABLED, "wlan_ahb", sc);
+	if (ret) {
+		dev_err(&pdev->dev, "ath_request_irq failed\n");
+		ret = -1;
+		goto end;
+	}
+	sc->irq = irq;
+
+	/* Use Legacy PCI Interrupts */
+	hif_write32_mb(sc->mem+(SOC_CORE_BASE_ADDRESS |
+				PCIE_INTR_ENABLE_ADDRESS),
+			PCIE_INTR_FIRMWARE_MASK | PCIE_INTR_CE_MASK_ALL);
+	/* read once to flush */
+	hif_read32_mb(sc->mem+(SOC_CORE_BASE_ADDRESS |
+				PCIE_INTR_ENABLE_ADDRESS)
+		     );
+
+end:
+	return ret;
+}
+
+/**
+ * hif_target_sync() : ensure the target is ready
+ * @scn: hif control structure
+ *
+ * Informs fw that we plan to use legacy interupts so that
+ * it can begin booting. Ensures that the fw finishes booting
+ * before continuing. Should be called before trying to write
+ * to the targets other registers for the first time.
+ *
+ * Return: none
+ */
+int hif_target_sync_ahb(struct hif_softc *scn)
+{
+	hif_write32_mb(scn->mem + FW_INDICATOR_ADDRESS, FW_IND_HOST_READY);
+	if (HAS_FW_INDICATOR) {
+		int wait_limit = 500;
+		int fw_ind = 0;
+
+		while (1) {
+			fw_ind = hif_read32_mb(scn->mem +
+					FW_INDICATOR_ADDRESS);
+			if (fw_ind & FW_IND_INITIALIZED)
+				break;
+			if (wait_limit-- < 0)
+				break;
+			hif_write32_mb(scn->mem+(SOC_CORE_BASE_ADDRESS |
+				PCIE_INTR_ENABLE_ADDRESS),
+				PCIE_INTR_FIRMWARE_MASK);
+			qdf_mdelay(10);
+		}
+		if (wait_limit < 0) {
+			HIF_TRACE("%s: FW signal timed out", __func__);
+			return -EIO;
+		} else {
+			HIF_TRACE("%s: Got FW signal, retries = %x", __func__,
+							500-wait_limit);
+		}
+	}
+
+	return 0;
+}
+
+/**
+ * hif_disable_bus() - Disable the bus
+ * @scn : pointer to the hif context
+ *
+ * This function disables the bus and helds the target in reset state
+ *
+ * Return: none
+ */
+void hif_ahb_disable_bus(struct hif_softc *scn)
+{
+	struct hif_pci_softc *sc = HIF_GET_PCI_SOFTC(scn);
+	void __iomem *mem;
+	struct platform_device *pdev = (struct platform_device *)sc->pdev;
+
+	/*Disable WIFI clock input*/
+	hif_ahb_clk_enable_disable(&pdev->dev, 0);
+
+	hif_ahb_device_reset(scn);
+	mem = (void __iomem *)sc->mem;
+	if (mem) {
+		devm_iounmap(&pdev->dev, mem);
+		sc->mem = NULL;
+	}
+	scn->mem = NULL;
+}
+
+/**
+ * hif_enable_bus() - Enable the bus
+ * @dev: dev
+ * @bdev: bus dev
+ * @bid: bus id
+ * @type: bus type
+ *
+ * This function enables the radio bus by enabling necessary
+ * clocks and waits for the target to get ready to proceed futher
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS hif_ahb_enable_bus(struct hif_softc *ol_sc,
+		struct device *dev, void *bdev,
+		const hif_bus_id *bid,
+		enum hif_enable_type type)
+{
+	int ret = 0;
+	int hif_type;
+	int target_type;
+	const struct platform_device_id *id = (struct platform_device_id *)bid;
+	struct platform_device *pdev = bdev;
+	struct hif_target_info *tgt_info = NULL;
+	struct resource *memres = NULL;
+	void __iomem *mem = NULL;
+	uint32_t revision_id = 0;
+	struct hif_pci_softc *sc = HIF_GET_PCI_SOFTC(ol_sc);
+
+	sc->pdev = (struct pci_dev *)pdev;
+	sc->dev = &pdev->dev;
+	sc->devid = id->driver_data;
+
+	ret = hif_get_device_type(id->driver_data, revision_id,
+			&hif_type, &target_type);
+	if (ret < 0) {
+		HIF_ERROR("%s: invalid device  ret %d id %d revision_id %d",
+			__func__, ret, (int)id->driver_data, revision_id);
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	memres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!memres) {
+		HIF_INFO("%s: Failed to get IORESOURCE_MEM\n", __func__);
+		return -EIO;
+	}
+
+	ret = dma_set_mask(dev, DMA_BIT_MASK(32));
+	if (ret) {
+		HIF_INFO("ath: 32-bit DMA not available\n");
+		goto err_cleanup1;
+	}
+
+	ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32));
+	if (ret) {
+		HIF_ERROR("%s: failed to set dma mask error = %d",
+				__func__, ret);
+		return ret;
+	}
+
+	/* Arrange for access to Target SoC registers. */
+	mem = devm_ioremap_resource(&pdev->dev, memres);
+	if (IS_ERR(mem)) {
+		HIF_INFO("ath: ioremap error\n");
+		ret = PTR_ERR(mem);
+		goto err_cleanup1;
+	}
+
+	sc->mem = mem;
+	ol_sc->mem = mem;
+	ol_sc->mem_pa = memres->start;
+	tgt_info = hif_get_target_info_handle((struct hif_opaque_softc *)ol_sc);
+
+	tgt_info->target_type = target_type;
+	hif_register_tbl_attach(ol_sc, hif_type);
+	target_register_tbl_attach(ol_sc, target_type);
+
+	if (hif_ahb_enable_radio(sc, pdev, id) != 0) {
+		HIF_INFO("error in enabling soc\n");
+		return -EIO;
+	}
+
+	if (hif_target_sync_ahb(ol_sc) < 0) {
+		ret = -EIO;
+		goto err_target_sync;
+	}
+	HIF_TRACE("%s: X - hif_type = 0x%x, target_type = 0x%x",
+			__func__, hif_type, target_type);
+
+	return QDF_STATUS_SUCCESS;
+err_target_sync:
+	HIF_INFO("Error: Disabling target\n");
+	hif_ahb_disable_bus(ol_sc);
+err_cleanup1:
+	return ret;
+}
+
+
+/**
+ * hif_reset_soc() - reset soc
+ *
+ * @hif_ctx: HIF context
+ *
+ * This function resets soc and helds the
+ * target in reset state
+ *
+ * Return: void
+ */
+/* Function to reset SoC */
+void hif_ahb_reset_soc(struct hif_opaque_softc *hif_ctx)
+{
+	struct hif_pci_softc *sc = HIF_GET_PCI_SOFTC(hif_ctx);
+	hif_ahb_device_reset((struct hif_softc *)sc);
+}
+
+
+/**
+ * hif_nointrs() - disable IRQ
+ *
+ * @scn: struct hif_softc
+ *
+ * This function stops interrupt(s)
+ *
+ * Return: none
+ */
+void hif_ahb_nointrs(struct hif_softc *scn)
+{
+	hif_pci_nointrs(scn);
+}
+
+/**
+ * ce_irq_enable() - enable copy engine IRQ
+ * @scn: struct hif_softc
+ * @ce_id: ce_id
+ *
+ * This function enables the interrupt for the radio.
+ *
+ * Return: N/A
+ */
+void hif_ahb_irq_enable(struct hif_softc *scn, int ce_id)
+{
+	hif_pci_irq_enable(scn, ce_id);
+}
+
+/**
+ * ce_irq_disable() - disable copy engine IRQ
+ * @scn: struct hif_softc
+ * @ce_id: ce_id
+ *
+ * Return: N/A
+ */
+void hif_ahb_irq_disable(struct hif_softc *scn, int ce_id)
+{
+
+}
diff --git a/hif/src/snoc/if_ahb.h b/hif/src/snoc/if_ahb.h
new file mode 100644
index 0000000..f5c9081
--- /dev/null
+++ b/hif/src/snoc/if_ahb.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2013-2016 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
+ * above copyright notice and this permission notice appear in all
+ * copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+ * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/**
+ * DOC: if_ahb.h
+ *
+ * h file for ahb specific implementations.
+ */
+
+#ifndef __IF_AHB_H
+#define __IF_AHB_H
+
+#define GCC_BASE 0x1800000
+#define GCC_SIZE 0x60000
+#define GCC_FEPLL_PLL_DIV 0x2f020
+#define GCC_FEPLL_PLL_CLK_WIFI_0_SEL_MASK 0x00000300
+#define GCC_FEPLL_PLL_CLK_WIFI_0_SEL_SHIFT 8
+#define GCC_FEPLL_PLL_CLK_WIFI_1_SEL_MASK 0x00003000
+#define GCC_FEPLL_PLL_CLK_WIFI_1_SEL_SHIFT 12
+
+
+/* These registers are outsize Wifi space. */
+/* TBD: Should we add these offsets as device tree properties? */
+#define TCSR_BASE 0x1900000
+#define TCSR_SIZE 0x80000
+#define TCSR_WIFI0_GLB_CFG 0x49000
+#define TCSR_WIFI1_GLB_CFG 0x49004
+#define TCSR_WCSS0_HALTREQ 0x52000
+#define TCSR_WCSS1_HALTREQ 0x52004
+#define TCSR_WCSS0_HALTACK 0x52010
+#define TCSR_WCSS1_HALTACK 0x52014
+#define ATH_AHB_RESET_WAIT_MAX 10 /* Ms */
+#endif
+
diff --git a/hif/src/snoc/if_ahb_reset.c b/hif/src/snoc/if_ahb_reset.c
new file mode 100644
index 0000000..b65edf4
--- /dev/null
+++ b/hif/src/snoc/if_ahb_reset.c
@@ -0,0 +1,372 @@
+/*
+ * Copyright (c) 2013-2016 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
+ * above copyright notice and this permission notice appear in all
+ * copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+ * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/**
+ * DOC: if_ahb_reset.c
+ *
+ * c file for ahb ipq4019 specific implementations.
+ */
+
+#include "hif.h"
+#include "hif_main.h"
+#include "hif_debug.h"
+#include "hif_io32.h"
+#include "ce_main.h"
+#include "ce_tasklet.h"
+#include "ahb_api.h"
+#include "if_ahb.h"
+
+#include <linux/clk.h>
+#include <linux/reset.h>
+#include <linux/of_address.h>
+#include <linux/platform_device.h>
+#include <linux/device.h>
+#include <linux/of.h>
+
+/**
+ * clk_enable_disable() -  Enable/disable clock
+ * @dev : pointer to device structure
+ * @str : clock name
+ * @enable : should be true, if the clock needs to be enabled
+ *           should be false, if the clock needs to be enabled
+ *
+ * This is a helper function for hif_ahb_clk_enable_disable to enable
+ * disable clocks.
+ * clk_prepare_enable will enable the clock
+ * clk_disable_unprepare will disable the clock
+ *
+ * Return: zero on success, non-zero incase of error.
+ */
+
+static int clk_enable_disable(struct device *dev, const char *str, int enable)
+{
+	struct clk *clk_t = NULL;
+	int ret;
+
+	clk_t = clk_get(dev, str);
+	if (IS_ERR(clk_t)) {
+		HIF_INFO("%s: Failed to get %s clk %ld\n",
+				__func__, str, PTR_ERR(clk_t));
+		return -EFAULT;
+	}
+	if (TRUE == enable) {
+		/* Prepare and Enable clk */
+		ret = clk_prepare_enable(clk_t);
+		if (ret) {
+			HIF_INFO("%s: err enabling clk %s , error:%d\n",
+					__func__, str, ret);
+			return ret;
+		}
+	} else {
+		/* Disable and unprepare clk */
+		clk_disable_unprepare(clk_t);
+	}
+	return 0;
+}
+
+
+/**
+ * hif_ahb_clk_enable_disable() - Enable/disable ahb clock
+ * @dev : pointer to device structure
+ * @enable : should be true, if the clock needs to be enabled
+ *           should be false, if the clock needs to be enabled
+ *
+ * This functions helps to enable/disable all the necesasary clocks
+ * for bus access.
+ *
+ * Return: zero on success, non-zero incase of error
+ */
+int hif_ahb_clk_enable_disable(struct device *dev, int enable)
+{
+	int ret;
+
+	ret = clk_enable_disable(dev, "wifi_wcss_cmd", enable);
+	if (ret)
+		return ret;
+	ret = clk_enable_disable(dev, "wifi_wcss_ref", enable);
+	if (ret)
+		return ret;
+	ret = clk_enable_disable(dev, "wifi_wcss_rtc", enable);
+	if (ret)
+		return ret;
+	return 0;
+}
+
+/**
+ * hif_enable_radio() - Enable the target radio.
+ * @sc : pointer to the hif context
+ *
+ * This function helps to release the target from reset state
+ *
+ * Return : zero on success, non-zero incase of error.
+ */
+int hif_ahb_enable_radio(struct hif_pci_softc *sc,
+		struct platform_device *pdev,
+		const struct platform_device_id *id)
+{
+	struct reset_control *reset_ctl = NULL;
+	uint32_t msi_addr, msi_base, wifi_core_id;
+	struct hif_softc *scn = HIF_GET_SOFTC(sc);
+	struct device_node *dev_node = pdev->dev.of_node;
+	bool msienable = false;
+	int ret = 0;
+
+	ret = of_property_read_u32(dev_node, "qca,msi_addr", &msi_addr);
+	if (ret) {
+		HIF_INFO("%s: Unable to get msi_addr - error:%d\n",
+					__func__, ret);
+		return -EIO;
+	}
+	ret = of_property_read_u32(dev_node, "qca,msi_base", &msi_base);
+	if (ret) {
+		HIF_INFO("%s: Unable to get msi_base - error:%d\n",
+					__func__, ret);
+		return -EIO;
+	}
+	ret = of_property_read_u32(dev_node, "core-id", &wifi_core_id);
+	if (ret) {
+		HIF_INFO("%s: Unable to get core-id - error:%d\n",
+					__func__, ret);
+		return -EIO;
+	}
+
+	/* Program the above values into Wifi scratch regists */
+	if (msienable) {
+		hif_write32_mb(sc->mem + FW_AXI_MSI_ADDR, msi_addr);
+		hif_write32_mb(sc->mem + FW_AXI_MSI_DATA, msi_base);
+	}
+
+	/* TBD: Temporary changes. Frequency should be
+	   retrieved through clk_xxx once kernel GCC driver is available */
+	{
+		void __iomem *mem_gcc;
+		uint32_t clk_sel;
+		uint32_t gcc_fepll_pll_div;
+		uint32_t wifi_cpu_freq[4] = {266700000, 250000000, 222200000,
+								200000000};
+		uint32_t current_freq = 0;
+
+		/* Enable WIFI clock input */
+		if (scn->target_info.target_type == TARGET_TYPE_IPQ4019) {
+			ret = hif_ahb_clk_enable_disable(&pdev->dev, 1);
+			if (ret) {
+				HIF_INFO("%s:Error while enabling clock :%d\n",
+					__func__, ret);
+				return ret;
+			}
+		}
+
+		mem_gcc = ioremap_nocache(GCC_BASE, GCC_SIZE);
+		if (IS_ERR(mem_gcc)) {
+			HIF_INFO("%s: GCC ioremap failed\n", __func__);
+			return PTR_ERR(mem_gcc);
+		}
+		gcc_fepll_pll_div = hif_read32_mb(mem_gcc + GCC_FEPLL_PLL_DIV);
+		clk_sel = (wifi_core_id == 0) ? ((gcc_fepll_pll_div &
+				GCC_FEPLL_PLL_CLK_WIFI_0_SEL_MASK) >>
+					GCC_FEPLL_PLL_CLK_WIFI_0_SEL_SHIFT) :
+		((gcc_fepll_pll_div & GCC_FEPLL_PLL_CLK_WIFI_1_SEL_MASK)
+					>> GCC_FEPLL_PLL_CLK_WIFI_1_SEL_SHIFT);
+		current_freq = wifi_cpu_freq[clk_sel];
+
+		HIF_INFO("Wifi%d CPU frequency %u\n", wifi_core_id,
+							current_freq);
+		hif_write32_mb(sc->mem + FW_CPU_PLL_CONFIG, gcc_fepll_pll_div);
+		iounmap(mem_gcc);
+	}
+
+	/* De-assert radio cold reset */
+	reset_ctl = reset_control_get(&pdev->dev, "wifi_radio_cold");
+	if (IS_ERR(reset_ctl)) {
+		HIF_INFO("%s: Failed to get radio cold reset control\n",
+							__func__);
+		ret = PTR_ERR(reset_ctl);
+		goto err_reset;
+	}
+	reset_control_deassert(reset_ctl);
+	reset_control_put(reset_ctl);
+
+	/* De-assert radio warm reset */
+	reset_ctl = reset_control_get(&pdev->dev, "wifi_radio_warm");
+	if (IS_ERR(reset_ctl)) {
+		HIF_INFO("%s: Failed to get radio warm reset control\n",
+							__func__);
+		ret = PTR_ERR(reset_ctl);
+		goto err_reset;
+	}
+	reset_control_deassert(reset_ctl);
+	reset_control_put(reset_ctl);
+
+	/* De-assert radio srif reset */
+	reset_ctl = reset_control_get(&pdev->dev, "wifi_radio_srif");
+	if (IS_ERR(reset_ctl)) {
+		HIF_INFO("%s: Failed to get radio srif reset control\n",
+							__func__);
+		ret = PTR_ERR(reset_ctl);
+		goto err_reset;
+	}
+	reset_control_deassert(reset_ctl);
+	reset_control_put(reset_ctl);
+
+	/* De-assert target CPU reset */
+	reset_ctl = reset_control_get(&pdev->dev, "wifi_cpu_init");
+	if (IS_ERR(reset_ctl)) {
+		HIF_INFO("%s: Failed to get cpu init reset control", __func__);
+		ret = PTR_ERR(reset_ctl);
+		goto err_reset;
+	}
+	reset_control_deassert(reset_ctl);
+	reset_control_put(reset_ctl);
+
+	return 0;
+
+err_reset:
+	return -EIO;
+
+}
+
+/* "wifi_core_warm" is the other reset type */
+#define AHB_RESET_TYPE "wifi_core_cold"
+
+/**
+ * hif_ahb_device_reset() - Disable the radio and held the radio is reset state.
+ * @scn : pointer to the hif context
+ *
+ * This function will hold the target in reset state.
+ * Will be called while unload the driver or any graceful unload path.
+ *
+ * Return : n/a.
+ */
+void hif_ahb_device_reset(struct hif_softc *scn)
+{
+	struct reset_control *resetctl = NULL;
+	struct reset_control *core_resetctl = NULL;
+	struct hif_pci_softc *sc = HIF_GET_PCI_SOFTC(scn);
+	struct platform_device *pdev = (struct platform_device *)(sc->pdev);
+	uint32_t glb_cfg_offset;
+	uint32_t haltreq_offset;
+	uint32_t haltack_offset;
+	void __iomem *mem_tcsr;
+	uint32_t wifi_core_id;
+	uint32_t reg_value;
+	int wait_limit = ATH_AHB_RESET_WAIT_MAX;
+
+
+	wifi_core_id = hif_read32_mb(sc->mem + WLAN_SUBSYSTEM_CORE_ID_ADDRESS);
+	glb_cfg_offset = (wifi_core_id == 0) ? TCSR_WIFI0_GLB_CFG :
+							TCSR_WIFI1_GLB_CFG;
+	haltreq_offset = (wifi_core_id == 0) ? TCSR_WCSS0_HALTREQ :
+							TCSR_WCSS1_HALTREQ;
+	haltack_offset = (wifi_core_id == 0) ? TCSR_WCSS0_HALTACK :
+							TCSR_WCSS1_HALTACK;
+
+	mem_tcsr = ioremap_nocache(TCSR_BASE, TCSR_SIZE);
+	if (IS_ERR(mem_tcsr)) {
+		HIF_INFO("%s: TCSR ioremap failed\n", __func__);
+		return;
+	}
+	reg_value = hif_read32_mb(mem_tcsr + haltreq_offset);
+	hif_write32_mb(mem_tcsr + haltreq_offset, reg_value | 0x1);
+	/* Wait for halt ack before asserting reset */
+	while (wait_limit) {
+
+		if (hif_read32_mb(mem_tcsr + haltack_offset) & 0x1)
+			break;
+
+		A_MDELAY(1);
+		wait_limit--;
+	}
+
+	reg_value = hif_read32_mb(mem_tcsr + glb_cfg_offset);
+	hif_write32_mb(mem_tcsr + glb_cfg_offset, reg_value | (1 << 25));
+
+	core_resetctl = reset_control_get(&pdev->dev, AHB_RESET_TYPE);
+	if (IS_ERR(core_resetctl)) {
+		HIF_INFO("Failed to get wifi core cold reset control\n");
+		return;
+	}
+
+	/* Reset wifi core */
+	reset_control_assert(core_resetctl);
+
+	/* TBD: Check if we should also assert other bits (radio_cold, radio_
+	warm, radio_srif, cpu_ini) */
+	A_MDELAY(1); /* TBD: Get reqd delay from HW team */
+
+	/* Assert radio cold reset */
+	resetctl = reset_control_get(&pdev->dev, "wifi_radio_cold");
+	if (IS_ERR(resetctl)) {
+		HIF_INFO("%s: Failed to get radio cold reset control\n",
+						__func__);
+		return;
+	}
+	reset_control_assert(resetctl);
+	A_MDELAY(1); /* TBD: Get reqd delay from HW team */
+	reset_control_put(resetctl);
+
+	/* Assert radio warm reset */
+	resetctl = reset_control_get(&pdev->dev, "wifi_radio_warm");
+	if (IS_ERR(resetctl)) {
+		HIF_INFO("%s: Failed to get radio warm reset control\n",
+						__func__);
+		return;
+	}
+	reset_control_assert(resetctl);
+	A_MDELAY(1); /* TBD: Get reqd delay from HW team */
+	reset_control_put(resetctl);
+
+	/* Assert radio srif reset */
+	resetctl = reset_control_get(&pdev->dev, "wifi_radio_srif");
+	if (IS_ERR(resetctl)) {
+		HIF_INFO("%s: Failed to get radio srif reset control\n",
+						__func__);
+		return;
+	}
+	reset_control_assert(resetctl);
+	A_MDELAY(1); /* TBD: Get reqd delay from HW team */
+	reset_control_put(resetctl);
+
+	/* Assert target CPU reset */
+	resetctl = reset_control_get(&pdev->dev, "wifi_cpu_init");
+	if (IS_ERR(resetctl)) {
+		HIF_INFO("%s: Failed to get cpu init reset control", __func__);
+		return;
+	}
+	reset_control_assert(resetctl);
+	A_MDELAY(10); /* TBD: Get reqd delay from HW team */
+	reset_control_put(resetctl);
+
+	/* Clear gbl_cfg and haltreq before clearing Wifi core reset */
+	reg_value = hif_read32_mb(mem_tcsr + haltreq_offset);
+	hif_write32_mb(mem_tcsr + haltreq_offset, reg_value & ~0x1);
+	reg_value = hif_read32_mb(mem_tcsr + glb_cfg_offset);
+	hif_write32_mb(mem_tcsr + glb_cfg_offset, reg_value & ~(1 << 25));
+
+	/* de-assert wifi core reset */
+	reset_control_deassert(core_resetctl);
+
+	A_MDELAY(1); /* TBD: Get reqd delay from HW team */
+
+	/* TBD: Check if we should de-assert other bits here */
+	reset_control_put(core_resetctl);
+	iounmap(mem_tcsr);
+	HIF_INFO("Reset complete for wifi core id : %d\n", wifi_core_id);
+}
+
+
+