-obj-$(CONFIG_MSM_QDSP6_APRV2) += apr.o apr_v2.o apr_tal.o voice_svc.o
-obj-$(CONFIG_MSM_QDSP6_APRV3) += apr.o apr_v3.o apr_tal.o voice_svc.o
-obj-$(CONFIG_MSM_QDSP6_APRV2_GLINK) += apr.o apr_v2.o apr_tal_glink.o voice_svc.o
-obj-$(CONFIG_MSM_QDSP6_APRV3_GLINK) += apr.o apr_v3.o apr_tal_glink.o voice_svc.o
+obj-$(CONFIG_MSM_QDSP6_APRV2) += apr.o apr_v2.o apr_tal.o voice_svc.o apr_dummy.o
+obj-$(CONFIG_MSM_QDSP6_APRV3) += apr.o apr_v3.o apr_tal.o voice_svc.o apr_dummy.o
+obj-$(CONFIG_MSM_QDSP6_APRV2_GLINK) += apr.o apr_v2.o apr_tal_glink.o voice_svc.o apr_dummy.o
+obj-$(CONFIG_MSM_QDSP6_APRV3_GLINK) += apr.o apr_v3.o apr_tal_glink.o voice_svc.o apr_dummy.o
obj-$(CONFIG_MSM_QDSP6_APRV2_VM) += apr_vm.o apr_v2.o voice_svc.o
obj-$(CONFIG_SND_SOC_MSM_QDSP6V2_INTF) += msm_audio_ion.o
obj-$(CONFIG_SND_SOC_QDSP6V2_VM) += msm_audio_ion_vm.o
obj-$(CONFIG_MSM_QDSP6_NOTIFIER) += audio_notifier.o
obj-$(CONFIG_MSM_CDSP_LOADER) += cdsp-loader.o
obj-$(CONFIG_EXT_ANC) += sdsp-anc.o audio_anc.o audio-anc-dev-mgr.o
-obj-$(CONFIG_MSM_LPASS_RESOURCE_MANAGER) += lpass_resource_mgr.o
\ No newline at end of file
+obj-$(CONFIG_MSM_LPASS_RESOURCE_MANAGER) += lpass_resource_mgr.o
#include <linux/platform_device.h>
#include <linux/sysfs.h>
#include <linux/device.h>
+#include <linux/of.h>
#include <linux/slab.h>
#include <soc/qcom/subsystem_restart.h>
#include <soc/qcom/scm.h>
#include <linux/qdsp6v2/dsp_debug.h>
#include <linux/qdsp6v2/audio_notifier.h>
#include <linux/ipc_logging.h>
+#include <linux/of_device.h>
#define APR_PKT_IPC_LOG_PAGE_CNT 2
+static struct device *apr_dev_ptr;
static struct apr_q6 q6;
static struct apr_client client[APR_DEST_MAX][APR_CLIENT_MAX];
static void *apr_pkt_ctx;
static bool is_modem_up;
static bool is_initial_modem_boot;
static bool is_initial_adsp_boot;
+static bool is_child_devices_loaded;
/* Subsystem restart: QDSP6 data, functions */
static struct workqueue_struct *apr_reset_workqueue;
static void apr_reset_deregister(struct work_struct *work);
};
static bool apr_cf_debug;
+static struct delayed_work add_chld_dev_work;
#ifdef CONFIG_DEBUG_FS
static struct dentry *debugfs_apr_debug;
if (state < APR_SUBSYS_DOWN || state > APR_SUBSYS_LOADED)
return -EINVAL;
atomic_set(&q6.q6_state, state);
+ if (state == APR_SUBSYS_LOADED && !is_child_devices_loaded) {
+ schedule_delayed_work(&add_chld_dev_work,
+ msecs_to_jiffies(100));
+ is_child_devices_loaded = true;
+ }
return 0;
}
EXPORT_SYMBOL_GPL(apr_set_q6_state);
dispatch_event(opcode, APR_DEST_QDSP6);
}
+static void apr_add_child_devices(struct work_struct *work)
+{
+ int ret;
+
+ ret = of_platform_populate(apr_dev_ptr->of_node,
+ NULL, NULL, apr_dev_ptr);
+ if (ret)
+ dev_err(apr_dev_ptr, "%s: failed to add child nodes, ret=%d\n",
+ __func__, ret);
+}
+
static void apr_adsp_up(void)
{
if (apr_cmpxchg_q6_state(APR_SUBSYS_DOWN, APR_SUBSYS_LOADED) ==
APR_SUBSYS_DOWN)
wake_up(&dsp_wait);
+ if (!is_child_devices_loaded) {
+ schedule_delayed_work(&add_chld_dev_work,
+ msecs_to_jiffies(100));
+ is_child_devices_loaded = true;
+ }
}
int apr_wait_for_device_up(int dest_id)
.priority = 0,
};
-static int __init apr_init(void)
+static void apr_cleanup(void)
+{
+ int i, j, k;
+
+ if (apr_reset_workqueue)
+ destroy_workqueue(apr_reset_workqueue);
+ mutex_destroy(&q6.lock);
+ for (i = 0; i < APR_DEST_MAX; i++) {
+ for (j = 0; j < APR_CLIENT_MAX; j++) {
+ mutex_destroy(&client[i][j].m_lock);
+ for (k = 0; k < APR_SVC_MAX; k++)
+ mutex_destroy(&client[i][j].svc[k].m_lock);
+ }
+ }
+}
+
+static int apr_probe(struct platform_device *pdev)
{
int i, j, k;
subsys_notif_register("apr_modem", AUDIO_NOTIFIER_MODEM_DOMAIN,
&modem_service_nb);
+ apr_dev_ptr = &pdev->dev;
+ INIT_DELAYED_WORK(&add_chld_dev_work, apr_add_child_devices);
+ return 0;
+}
+
+static int apr_remove(struct platform_device *pdev)
+{
+ apr_cleanup();
+ return 0;
+}
+
+static const struct of_device_id apr_machine_of_match[] = {
+ { .compatible = "qcom,msm-audio-apr", },
+ {},
+};
+
+static struct platform_driver apr_driver = {
+ .probe = apr_probe,
+ .remove = apr_remove,
+ .driver = {
+ .name = "audio_apr",
+ .owner = THIS_MODULE,
+ .of_match_table = apr_machine_of_match,
+ }
+};
+
+static int __init apr_init(void)
+{
+ platform_driver_register(&apr_driver);
+ apr_dummy_init();
return 0;
}
device_initcall(apr_init);
+static void __exit apr_exit(void)
+{
+ apr_dummy_exit();
+ platform_driver_unregister(&apr_driver);
+}
+__exitcall(apr_exit);
+
+MODULE_DESCRIPTION("APR DRIVER");
+MODULE_DEVICE_TABLE(of, apr_machine_of_match);
+
static int __init apr_late_init(void)
{
int ret = 0;
--- /dev/null
+/* Copyright (c) 2019, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only 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.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/of_device.h>
+#include <linux/qdsp6v2/apr.h>
+
+static int apr_dummy_probe(struct platform_device *pdev)
+{
+ return 0;
+}
+
+static int apr_dummy_remove(struct platform_device *pdev)
+{
+ return 0;
+}
+
+static const struct of_device_id apr_dummy_dt_match[] = {
+ {.compatible = "qcom,msm-audio-apr-dummy"},
+ {}
+};
+
+static struct platform_driver apr_dummy_driver = {
+ .driver = {
+ .name = "apr_dummy",
+ .owner = THIS_MODULE,
+ .of_match_table = apr_dummy_dt_match,
+ },
+ .probe = apr_dummy_probe,
+ .remove = apr_dummy_remove,
+};
+
+int __init apr_dummy_init(void)
+{
+ platform_driver_register(&apr_dummy_driver);
+ return 0;
+}
+
+void apr_dummy_exit(void)
+{
+ platform_driver_unregister(&apr_dummy_driver);
+}
+
+MODULE_DESCRIPTION("APR dummy module driver");
+MODULE_LICENSE("GPL v2");
+MODULE_DEVICE_TABLE(of, apr_dummy_dt_match);