#include "debug.h"
#include "hif.h"
-static const struct of_device_id ath12k_ahb_of_match[] = {
- { .compatible = "qcom,ipq5332-wifi",
- .data = (void *)ATH12K_HW_IPQ5332_HW10,
- },
- { }
-};
-
-MODULE_DEVICE_TABLE(of, ath12k_ahb_of_match);
-
#define ATH12K_IRQ_CE0_OFFSET 4
#define ATH12K_MAX_UPDS 1
#define ATH12K_UPD_IRQ_WRD_LEN 18
+
+static struct ath12k_ahb_driver *ath12k_ahb_family_drivers[ATH12K_DEVICE_FAMILY_MAX];
static const char ath12k_userpd_irq[][9] = {"spawn",
"ready",
"stop-ack"};
ab_ahb->xo_clk = NULL;
}
+static enum ath12k_device_family
+ath12k_ahb_get_device_family(const struct platform_device *pdev)
+{
+ enum ath12k_device_family device_family_id;
+ struct ath12k_ahb_driver *driver;
+ const struct of_device_id *of_id;
+
+ for (device_family_id = ATH12K_DEVICE_FAMILY_START;
+ device_family_id < ATH12K_DEVICE_FAMILY_MAX; device_family_id++) {
+ driver = ath12k_ahb_family_drivers[device_family_id];
+ if (driver) {
+ of_id = of_match_device(driver->id_table, &pdev->dev);
+ if (of_id) {
+ /* Found the driver */
+ return device_family_id;
+ }
+ }
+ }
+
+ return ATH12K_DEVICE_FAMILY_MAX;
+}
+
static int ath12k_ahb_probe(struct platform_device *pdev)
{
- struct ath12k_base *ab;
- const struct ath12k_hif_ops *hif_ops;
+ enum ath12k_device_family device_id;
struct ath12k_ahb *ab_ahb;
- enum ath12k_hw_rev hw_rev;
- u32 addr, userpd_id;
+ struct ath12k_base *ab;
+ u32 addr;
int ret;
ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
if (!ab)
return -ENOMEM;
- hw_rev = (enum ath12k_hw_rev)(kernel_ulong_t)of_device_get_match_data(&pdev->dev);
- switch (hw_rev) {
- case ATH12K_HW_IPQ5332_HW10:
- hif_ops = &ath12k_ahb_hif_ops;
- userpd_id = ATH12K_IPQ5332_USERPD_ID;
- break;
- default:
- ret = -EOPNOTSUPP;
+ ab_ahb = ath12k_ab_to_ahb(ab);
+ ab_ahb->ab = ab;
+ ab->hif.ops = &ath12k_ahb_hif_ops;
+ ab->pdev = pdev;
+ platform_set_drvdata(pdev, ab);
+
+ device_id = ath12k_ahb_get_device_family(pdev);
+ if (device_id >= ATH12K_DEVICE_FAMILY_MAX) {
+ ath12k_err(ab, "failed to get device family: %d\n", device_id);
+ ret = -EINVAL;
goto err_core_free;
}
- ab->hif.ops = hif_ops;
- ab->pdev = pdev;
- ab->hw_rev = hw_rev;
- ab->target_mem_mode = ATH12K_QMI_MEMORY_MODE_DEFAULT;
- platform_set_drvdata(pdev, ab);
- ab_ahb = ath12k_ab_to_ahb(ab);
- ab_ahb->ab = ab;
- ab_ahb->userpd_id = userpd_id;
+ ath12k_dbg(ab, ATH12K_DBG_AHB, "AHB device family id: %d\n", device_id);
+
+ ab_ahb->device_family_ops = &ath12k_ahb_family_drivers[device_id]->ops;
+
+ /* Call device specific probe. This is the callback that can
+ * be used to override any ops in future
+ * probe is validated for NULL during registration.
+ */
+ ret = ab_ahb->device_family_ops->probe(pdev);
+ if (ret) {
+ ath12k_err(ab, "failed to probe device: %d\n", ret);
+ goto err_core_free;
+ }
/* Set fixed_mem_region to true for platforms that support fixed memory
* reservation from DT. If memory is reserved from DT for FW, ath12k driver
ath12k_ahb_free_resources(ab);
}
-static struct platform_driver ath12k_ahb_driver = {
- .driver = {
- .name = "ath12k_ahb",
- .of_match_table = ath12k_ahb_of_match,
- },
- .probe = ath12k_ahb_probe,
- .remove = ath12k_ahb_remove,
-};
-
-int ath12k_ahb_init(void)
+int ath12k_ahb_register_driver(const enum ath12k_device_family device_id,
+ struct ath12k_ahb_driver *driver)
{
- return platform_driver_register(&ath12k_ahb_driver);
+ struct platform_driver *ahb_driver;
+
+ if (device_id >= ATH12K_DEVICE_FAMILY_MAX)
+ return -EINVAL;
+
+ if (!driver || !driver->ops.probe)
+ return -EINVAL;
+
+ if (ath12k_ahb_family_drivers[device_id]) {
+ pr_err("Driver already registered for id %d\n", device_id);
+ return -EALREADY;
+ }
+
+ ath12k_ahb_family_drivers[device_id] = driver;
+
+ ahb_driver = &ath12k_ahb_family_drivers[device_id]->driver;
+ ahb_driver->driver.name = driver->name;
+ ahb_driver->driver.of_match_table = driver->id_table;
+ ahb_driver->probe = ath12k_ahb_probe;
+ ahb_driver->remove = ath12k_ahb_remove;
+
+ return platform_driver_register(ahb_driver);
}
-void ath12k_ahb_exit(void)
+void ath12k_ahb_unregister_driver(const enum ath12k_device_family device_id)
{
- platform_driver_unregister(&ath12k_ahb_driver);
+ struct platform_driver *ahb_driver;
+
+ if (device_id >= ATH12K_DEVICE_FAMILY_MAX)
+ return;
+
+ if (!ath12k_ahb_family_drivers[device_id])
+ return;
+
+ ahb_driver = &ath12k_ahb_family_drivers[device_id]->driver;
+ platform_driver_unregister(ahb_driver);
+ ath12k_ahb_family_drivers[device_id] = NULL;
}
#include <linux/clk.h>
#include <linux/remoteproc/qcom_rproc.h>
+#include <linux/platform_device.h>
#include "core.h"
#define ATH12K_AHB_RECOVERY_TIMEOUT (3 * HZ)
struct ath12k_base;
+struct ath12k_ahb_device_family_ops {
+ int (*probe)(struct platform_device *pdev);
+};
+
struct ath12k_ahb {
struct ath12k_base *ab;
struct rproc *tgt_rproc;
u32 spawn_bit;
u32 stop_bit;
int userpd_irq_num[ATH12K_USERPD_MAX_IRQ];
+ const struct ath12k_ahb_ops *ahb_ops;
+ const struct ath12k_ahb_device_family_ops *device_family_ops;
+};
+
+struct ath12k_ahb_driver {
+ const char *name;
+ const struct of_device_id *id_table;
+ struct ath12k_ahb_device_family_ops ops;
+ struct platform_driver driver;
};
static inline struct ath12k_ahb *ath12k_ab_to_ahb(struct ath12k_base *ab)
return (struct ath12k_ahb *)ab->drv_priv;
}
-#ifdef CONFIG_ATH12K_AHB
-int ath12k_ahb_init(void);
-void ath12k_ahb_exit(void);
-#else
-static inline int ath12k_ahb_init(void)
-{
- return 0;
-}
+int ath12k_ahb_register_driver(const enum ath12k_device_family device_id,
+ struct ath12k_ahb_driver *driver);
+void ath12k_ahb_unregister_driver(const enum ath12k_device_family device_id);
-static inline void ath12k_ahb_exit(void) {};
-#endif
#endif
--- /dev/null
+// SPDX-License-Identifier: BSD-3-Clause-Clear
+/*
+ * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ */
+
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/soc/qcom/mdt_loader.h>
+#include "ahb.h"
+#include "ahb_wifi7.h"
+#include "debug.h"
+#include "hif.h"
+
+static const struct of_device_id ath12k_wifi7_ahb_of_match[] = {
+ { .compatible = "qcom,ipq5332-wifi",
+ .data = (void *)ATH12K_HW_IPQ5332_HW10,
+ },
+ { }
+};
+
+MODULE_DEVICE_TABLE(of, ath12k_wifi7_ahb_of_match);
+
+static int ath12k_wifi7_ahb_probe(struct platform_device *pdev)
+{
+ struct ath12k_ahb *ab_ahb;
+ enum ath12k_hw_rev hw_rev;
+ struct ath12k_base *ab;
+
+ ab = platform_get_drvdata(pdev);
+ ab_ahb = ath12k_ab_to_ahb(ab);
+
+ hw_rev = (enum ath12k_hw_rev)(kernel_ulong_t)of_device_get_match_data(&pdev->dev);
+ switch (hw_rev) {
+ case ATH12K_HW_IPQ5332_HW10:
+ ab_ahb->userpd_id = ATH12K_IPQ5332_USERPD_ID;
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ ab->target_mem_mode = ATH12K_QMI_MEMORY_MODE_DEFAULT;
+ ab->hw_rev = hw_rev;
+
+ return 0;
+}
+
+static struct ath12k_ahb_driver ath12k_wifi7_ahb_driver = {
+ .name = "ath12k_wifi7_ahb",
+ .id_table = ath12k_wifi7_ahb_of_match,
+ .ops.probe = ath12k_wifi7_ahb_probe,
+};
+
+int ath12k_wifi7_ahb_init(void)
+{
+ return ath12k_ahb_register_driver(ATH12K_DEVICE_FAMILY_WIFI7,
+ &ath12k_wifi7_ahb_driver);
+}
+
+void ath12k_wifi7_ahb_exit(void)
+{
+ ath12k_ahb_unregister_driver(ATH12K_DEVICE_FAMILY_WIFI7);
+}