OSDN Git Service

Asoc: apr: Fix sound card failure at stability runs
authorSoumya Managoli <smanag@codeaurora.org>
Fri, 2 Aug 2019 05:31:33 +0000 (11:01 +0530)
committerSoumya Managoli <smanag@codeaurora.org>
Wed, 28 Aug 2019 05:43:40 +0000 (11:13 +0530)
In stability reboot tests, deferred audio drivers
are not invoked after lpass loading sometimes and
results in sound card failure. Change APR to platform
device and after APR status changes to loaded state,
add dummy module child device under APR which invokes
deferred audio drivers and sound card registers successfully.

In analog codec driver defers until Q6 core ready.

Change-Id: I1c82d9da55e771299df356a2771de2b2e62348cf
Signed-off-by: Soumya Managoli <smanag@codeaurora.org>
drivers/soc/qcom/qdsp6v2/Makefile
drivers/soc/qcom/qdsp6v2/apr.c
drivers/soc/qcom/qdsp6v2/apr_dummy.c [new file with mode: 0644]
include/linux/qdsp6v2/apr.h

index 250cc88..7d19932 100644 (file)
@@ -1,7 +1,7 @@
-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
@@ -11,4 +11,4 @@ obj-$(CONFIG_MSM_QDSP6_PDR) += audio_pdr.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
index 4bc1999..8215674 100644 (file)
@@ -26,6 +26,7 @@
 #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;
@@ -47,6 +50,7 @@ static wait_queue_head_t modem_wait;
 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);
@@ -57,6 +61,7 @@ struct apr_reset_work {
 };
 
 static bool apr_cf_debug;
+static struct delayed_work add_chld_dev_work;
 
 #ifdef CONFIG_DEBUG_FS
 static struct dentry *debugfs_apr_debug;
@@ -263,6 +268,11 @@ int apr_set_q6_state(enum apr_subsys_state state)
        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);
@@ -279,11 +289,27 @@ static void apr_adsp_down(unsigned long opcode)
        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)
@@ -1057,7 +1083,23 @@ static struct notifier_block modem_service_nb = {
        .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;
 
@@ -1087,10 +1129,50 @@ static int __init apr_init(void)
        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;
diff --git a/drivers/soc/qcom/qdsp6v2/apr_dummy.c b/drivers/soc/qcom/qdsp6v2/apr_dummy.c
new file mode 100644 (file)
index 0000000..517a49d
--- /dev/null
@@ -0,0 +1,58 @@
+/* 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);
index e7e2a53..d80320e 100644 (file)
@@ -210,4 +210,6 @@ static inline int apr_end_rx_rt(void *handle)
 int apr_start_rx_rt(void *handle);
 int apr_end_rx_rt(void *handle);
 #endif
+int apr_dummy_init(void);
+void apr_dummy_exit(void);
 #endif