#include "debug.h"
 #include "hif.h"
 #include <linux/remoteproc.h>
+#include "pcic.h"
 
 static const struct of_device_id ath11k_ahb_of_match[] = {
        /* TODO: Should we change the compatible string to something similar
        { .compatible = "qcom,ipq6018-wifi",
          .data = (void *)ATH11K_HW_IPQ6018_HW10,
        },
+       { .compatible = "qcom,wcn6750-wifi",
+         .data = (void *)ATH11K_HW_WCN6750_HW10,
+       },
        { }
 };
 
        tcl2host_status_ring,
 };
 
+static int
+ath11k_ahb_get_msi_irq_wcn6750(struct ath11k_base *ab, unsigned int vector)
+{
+       return ab->pci.msi.irqs[vector];
+}
+
+static const struct ath11k_pci_ops ath11k_ahb_pci_ops_wcn6750 = {
+       .get_msi_irq = ath11k_ahb_get_msi_irq_wcn6750,
+};
+
 static inline u32 ath11k_ahb_read32(struct ath11k_base *ab, u32 offset)
 {
        return ioread32(ab->mem + offset);
        int irq_idx;
        int i;
 
+       if (ab->hw_params.hybrid_bus_type)
+               return ath11k_pcic_free_irq(ab);
+
        for (i = 0; i < ab->hw_params.ce_count; i++) {
                if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
                        continue;
        int irq, irq_idx, i;
        int ret;
 
+       if (ab->hw_params.hybrid_bus_type)
+               return ath11k_pcic_config_irq(ab);
+
        /* Configure CE irqs */
        for (i = 0; i < ab->hw_params.ce_count; i++) {
                struct ath11k_ce_pipe *ce_pipe = &ab->ce.ce_pipe[i];
        return 0;
 }
 
-static const struct ath11k_hif_ops ath11k_ahb_hif_ops = {
+static const struct ath11k_hif_ops ath11k_ahb_hif_ops_ipq8074 = {
        .start = ath11k_ahb_start,
        .stop = ath11k_ahb_stop,
        .read32 = ath11k_ahb_read32,
        .power_up = ath11k_ahb_power_up,
 };
 
+static const struct ath11k_hif_ops ath11k_ahb_hif_ops_wcn6750 = {
+       .start = ath11k_pcic_start,
+       .stop = ath11k_pcic_stop,
+       .read32 = ath11k_pcic_read32,
+       .write32 = ath11k_pcic_write32,
+       .irq_enable = ath11k_pcic_ext_irq_enable,
+       .irq_disable = ath11k_pcic_ext_irq_disable,
+       .get_msi_address =  ath11k_pcic_get_msi_address,
+       .get_user_msi_vector = ath11k_pcic_get_user_msi_assignment,
+       .map_service_to_pipe = ath11k_pcic_map_service_to_pipe,
+       .power_down = ath11k_ahb_power_down,
+       .power_up = ath11k_ahb_power_up,
+};
+
 static int ath11k_core_get_rproc(struct ath11k_base *ab)
 {
        struct ath11k_ahb *ab_ahb = ath11k_ahb_priv(ab);
        return 0;
 }
 
+static int ath11k_ahb_setup_msi_resources(struct ath11k_base *ab)
+{
+       struct platform_device *pdev = ab->pdev;
+       phys_addr_t msi_addr_pa;
+       dma_addr_t msi_addr_iova;
+       struct resource *res;
+       int int_prop;
+       int ret;
+       int i;
+
+       ret = ath11k_pcic_init_msi_config(ab);
+       if (ret) {
+               ath11k_err(ab, "failed to init msi config: %d\n", ret);
+               return ret;
+       }
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res) {
+               ath11k_err(ab, "failed to fetch msi_addr\n");
+               return -ENOENT;
+       }
+
+       msi_addr_pa = res->start;
+       msi_addr_iova = dma_map_resource(ab->dev, msi_addr_pa, PAGE_SIZE,
+                                        DMA_FROM_DEVICE, 0);
+       if (dma_mapping_error(ab->dev, msi_addr_iova))
+               return -ENOMEM;
+
+       ab->pci.msi.addr_lo = lower_32_bits(msi_addr_iova);
+       ab->pci.msi.addr_hi = upper_32_bits(msi_addr_iova);
+
+       ret = of_property_read_u32_index(ab->dev->of_node, "interrupts", 1, &int_prop);
+       if (ret)
+               return ret;
+
+       ab->pci.msi.ep_base_data = int_prop + 32;
+
+       for (i = 0; i < ab->pci.msi.config->total_vectors; i++) {
+               res = platform_get_resource(pdev, IORESOURCE_IRQ, i);
+               if (!res)
+                       return -ENODEV;
+
+               ab->pci.msi.irqs[i] = res->start;
+       }
+
+       set_bit(ATH11K_FLAG_MULTI_MSI_VECTORS, &ab->dev_flags);
+
+       return 0;
+}
+
+static int ath11k_ahb_setup_resources(struct ath11k_base *ab)
+{
+       struct platform_device *pdev = ab->pdev;
+       struct resource *mem_res;
+       void __iomem *mem;
+
+       if (ab->hw_params.hybrid_bus_type)
+               return ath11k_ahb_setup_msi_resources(ab);
+
+       mem = devm_platform_get_and_ioremap_resource(pdev, 0, &mem_res);
+       if (IS_ERR(mem)) {
+               dev_err(&pdev->dev, "ioremap error\n");
+               return PTR_ERR(mem);
+       }
+
+       ab->mem = mem;
+       ab->mem_len = resource_size(mem_res);
+
+       return 0;
+}
+
 static int ath11k_ahb_probe(struct platform_device *pdev)
 {
        struct ath11k_base *ab;
        const struct of_device_id *of_id;
-       struct resource *mem_res;
-       void __iomem *mem;
+       const struct ath11k_hif_ops *hif_ops;
+       const struct ath11k_pci_ops *pci_ops;
+       enum ath11k_hw_rev hw_rev;
        int ret;
 
        of_id = of_match_device(ath11k_ahb_of_match, &pdev->dev);
                return -EINVAL;
        }
 
-       mem = devm_platform_get_and_ioremap_resource(pdev, 0, &mem_res);
-       if (IS_ERR(mem)) {
-               dev_err(&pdev->dev, "ioremap error\n");
-               return PTR_ERR(mem);
+       hw_rev = (enum ath11k_hw_rev)of_id->data;
+
+       switch (hw_rev) {
+       case ATH11K_HW_IPQ8074:
+       case ATH11K_HW_IPQ6018_HW10:
+               hif_ops = &ath11k_ahb_hif_ops_ipq8074;
+               pci_ops = NULL;
+               break;
+       case ATH11K_HW_WCN6750_HW10:
+               hif_ops = &ath11k_ahb_hif_ops_wcn6750;
+               pci_ops = &ath11k_ahb_pci_ops_wcn6750;
+               break;
+       default:
+               dev_err(&pdev->dev, "unsupported device type %d\n", hw_rev);
+               return -EOPNOTSUPP;
        }
 
        ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
                return -ENOMEM;
        }
 
-       ab->hif.ops = &ath11k_ahb_hif_ops;
+       ab->hif.ops = hif_ops;
+       ab->pci.ops = pci_ops;
        ab->pdev = pdev;
-       ab->hw_rev = (enum ath11k_hw_rev)of_id->data;
-       ab->mem = mem;
-       ab->mem_len = resource_size(mem_res);
+       ab->hw_rev = hw_rev;
        platform_set_drvdata(pdev, ab);
 
+       ret = ath11k_ahb_setup_resources(ab);
+       if (ret)
+               goto err_core_free;
+
        ret = ath11k_core_pre_init(ab);
        if (ret)
                goto err_core_free;
 
                },
                .hw_rev = ATH11K_HW_WCN6855_HW21,
        },
+       {
+               .total_vectors = 28,
+               .total_users = 2,
+               .users = (struct ath11k_msi_user[]) {
+                       { .name = "CE", .num_vectors = 10, .base_vector = 0 },
+                       { .name = "DP", .num_vectors = 18, .base_vector = 10 },
+               },
+               .hw_rev = ATH11K_HW_WCN6750_HW10,
+       },
 };
 
 int ath11k_pcic_init_msi_config(struct ath11k_base *ab)
            !ret)
                ab->pci.ops->release(ab);
 }
+EXPORT_SYMBOL(ath11k_pcic_write32);
 
 u32 ath11k_pcic_read32(struct ath11k_base *ab, u32 offset)
 {
 
        return val;
 }
+EXPORT_SYMBOL(ath11k_pcic_read32);
 
 void ath11k_pcic_get_msi_address(struct ath11k_base *ab, u32 *msi_addr_lo,
                                 u32 *msi_addr_hi)
        *msi_addr_lo = ab->pci.msi.addr_lo;
        *msi_addr_hi = ab->pci.msi.addr_hi;
 }
+EXPORT_SYMBOL(ath11k_pcic_get_msi_address);
 
 int ath11k_pcic_get_user_msi_assignment(struct ath11k_base *ab, char *user_name,
                                        int *num_vectors, u32 *user_base_data,
 
        return -EINVAL;
 }
+EXPORT_SYMBOL(ath11k_pcic_get_user_msi_assignment);
 
 void ath11k_pcic_get_ce_msi_idx(struct ath11k_base *ab, u32 ce_id, u32 *msi_idx)
 {
        }
        *msi_idx = msi_data_idx;
 }
+EXPORT_SYMBOL(ath11k_pcic_get_ce_msi_idx);
 
 static void ath11k_pcic_free_ext_irq(struct ath11k_base *ab)
 {
 
        ath11k_pcic_free_ext_irq(ab);
 }
+EXPORT_SYMBOL(ath11k_pcic_free_irq);
 
 static void ath11k_pcic_ce_irq_enable(struct ath11k_base *ab, u16 ce_id)
 {
                ath11k_pcic_ext_grp_enable(irq_grp);
        }
 }
+EXPORT_SYMBOL(ath11k_pcic_ext_irq_enable);
 
 static void ath11k_pcic_sync_ext_irqs(struct ath11k_base *ab)
 {
        __ath11k_pcic_ext_irq_disable(ab);
        ath11k_pcic_sync_ext_irqs(ab);
 }
+EXPORT_SYMBOL(ath11k_pcic_ext_irq_disable);
 
 static int ath11k_pcic_ext_grp_napi_poll(struct napi_struct *napi, int budget)
 {
 
        return 0;
 }
+EXPORT_SYMBOL(ath11k_pcic_config_irq);
 
 void ath11k_pcic_ce_irqs_enable(struct ath11k_base *ab)
 {
                ath11k_pcic_ce_irq_enable(ab, i);
        }
 }
+EXPORT_SYMBOL(ath11k_pcic_ce_irqs_enable);
 
 static void ath11k_pcic_kill_tasklets(struct ath11k_base *ab)
 {
        ath11k_pcic_sync_ce_irqs(ab);
        ath11k_pcic_kill_tasklets(ab);
 }
+EXPORT_SYMBOL(ath11k_pcic_ce_irq_disable_sync);
 
 void ath11k_pcic_stop(struct ath11k_base *ab)
 {
        ath11k_pcic_ce_irq_disable_sync(ab);
        ath11k_ce_cleanup_pipes(ab);
 }
+EXPORT_SYMBOL(ath11k_pcic_stop);
 
 int ath11k_pcic_start(struct ath11k_base *ab)
 {
 
        return 0;
 }
+EXPORT_SYMBOL(ath11k_pcic_start);
 
 int ath11k_pcic_map_service_to_pipe(struct ath11k_base *ab, u16 service_id,
                                    u8 *ul_pipe, u8 *dl_pipe)
 
        return 0;
 }
+EXPORT_SYMBOL(ath11k_pcic_map_service_to_pipe);