Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d683f683 authored by Laxminath Kasam's avatar Laxminath Kasam
Browse files

ASoC: Add test device to fix defer probe issue



After ADSP loading is done, add audio test module
device which will invoke deferred probe drivers.
Use PCM hostless driver inorder to add this
test module by monitoring ADSP state in workqueue.

CRs-Fixed: 2163828
Change-Id: I958717ffef289c48ba17e3a419026ee0de1410a9
Signed-off-by: default avatarLaxminath Kasam <lkasam@codeaurora.org>
parent 0cdce1ee
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -289,6 +289,13 @@ Required properties:

 - compatible : "qcom,msm-pcm-hostless"

Optional properties

 - compatible : "qcom,audio-test-mod"
		Add this compatible as child device to hostless device.
		This child device is added after lpass is up to invoke
		deferred probe devices.

* msm-ocmem-audio

Required properties:
@@ -631,6 +638,9 @@ Example:

        qcom,msm-pcm-hostless {
                compatible = "qcom,msm-pcm-hostless";
		audio-test-mod {
			compatible = "qcom,audio-test-mod";
		};
        };

	qcom,msm-ocmem-audio {
+1 −1
Original line number Diff line number Diff line
# MSM Machine Support

snd-soc-hostless-pcm-objs := msm-pcm-hostless.o
snd-soc-hostless-pcm-objs := msm-pcm-hostless.o audio_test_mod.o
obj-$(CONFIG_SND_SOC_MSM_HOSTLESS_PCM) += snd-soc-hostless-pcm.o

obj-$(CONFIG_SND_SOC_MSM_QDSP6V2_INTF) += qdsp6v2/
+61 −0
Original line number Diff line number Diff line
/*
 * Copyright (c) 2017, 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>

static int audio_test_mod_probe(struct platform_device *pdev)
{
	pr_debug("%s: dev name %s\n", __func__, dev_name(&pdev->dev));
	return 0;
}

static int audio_test_mod_remove(struct platform_device *pdev)
{
	return 0;
}

static const struct of_device_id audio_test_mod_dt_match[] = {
	{.compatible = "qcom,audio-test-mod"},
	{}
};

static struct platform_driver audio_test_mod_driver = {
	.driver = {
		.name = "audio-test-mod",
		.owner = THIS_MODULE,
		.of_match_table = audio_test_mod_dt_match,
	},
	.probe = audio_test_mod_probe,
	.remove = audio_test_mod_remove,
};

static int __init audio_test_mod_init(void)
{
	platform_driver_register(&audio_test_mod_driver);
	return 0;
}

static void __exit audio_test_mod_exit(void)
{
	platform_driver_unregister(&audio_test_mod_driver);
}

module_init(audio_test_mod_init);
module_exit(audio_test_mod_exit);

MODULE_DESCRIPTION("Audio test module driver");
MODULE_LICENSE("GPL v2");
+83 −0
Original line number Diff line number Diff line
@@ -14,10 +14,85 @@
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/of_device.h>
#include <linux/workqueue.h>
#include <linux/delay.h>
#include <sound/core.h>
#include <sound/soc.h>
#include <sound/pcm.h>
#include <linux/qdsp6v2/apr.h>

struct hostless_pdata {
	struct work_struct msm_test_add_child_dev_work;
	struct device *dev;
};

#define AUDIO_TEST_MOD_STRING_LEN 30

static void msm_test_add_child_dev(struct work_struct *work)
{
	struct hostless_pdata *pdata;
	struct platform_device *pdev;
	struct device_node *node;
	int ret;
	char plat_dev_name[AUDIO_TEST_MOD_STRING_LEN];
	int adsp_state;

	pdata = container_of(work, struct hostless_pdata,
			     msm_test_add_child_dev_work);
	if (!pdata) {
		pr_err("%s: Memory for pdata does not exist\n",
			__func__);
		return;
	}
	if (!pdata->dev) {
		pr_err("%s: pdata dev is not initialized\n", __func__);
		return;
	}
	if (!pdata->dev->of_node) {
		dev_err(pdata->dev,
			"%s: DT node for pdata does not exist\n", __func__);
		return;
	}

	adsp_state = apr_get_subsys_state();
	while (adsp_state != APR_SUBSYS_LOADED) {
		dev_dbg(pdata->dev, "Adsp is not loaded yet %d\n",
			adsp_state);
		msleep(500);
		adsp_state = apr_get_subsys_state();
	}
	msleep(1000);
	for_each_child_of_node(pdata->dev->of_node, node) {
		if (!strcmp(node->name, "audio_test_mod"))
			strlcpy(plat_dev_name, "audio_test_mod",
				(AUDIO_TEST_MOD_STRING_LEN - 1));
		else
			continue;

		pdev = platform_device_alloc(plat_dev_name, -1);
		if (!pdev) {
			dev_err(pdata->dev, "%s: pdev memory alloc failed\n",
				__func__);
			ret = -ENOMEM;
			goto err;
		}
		pdev->dev.parent = pdata->dev;
		pdev->dev.of_node = node;

		ret = platform_device_add(pdev);
		if (ret) {
			dev_err(&pdev->dev,
				"%s: Cannot add platform device\n",
				__func__);
			goto fail_pdev_add;
		}
	}
	return;
fail_pdev_add:
	platform_device_put(pdev);
err:
	return;
}

static int msm_pcm_hostless_prepare(struct snd_pcm_substream *substream)
{
@@ -41,8 +116,16 @@ static struct snd_soc_platform_driver msm_soc_hostless_platform = {

static int msm_pcm_hostless_probe(struct platform_device *pdev)
{
	struct hostless_pdata *pdata;

	pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
	if (!pdata)
		return -ENOMEM;
	pr_debug("%s: dev name %s\n", __func__, dev_name(&pdev->dev));
	pdata->dev = &pdev->dev;
	INIT_WORK(&pdata->msm_test_add_child_dev_work,
		  msm_test_add_child_dev);
	schedule_work(&pdata->msm_test_add_child_dev_work);
	return snd_soc_register_platform(&pdev->dev,
				   &msm_soc_hostless_platform);
}