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

Commit 67a94f94 authored by Venkata Narendra Kumar Gutta's avatar Venkata Narendra Kumar Gutta
Browse files

ASoC: msm8952: add support for dynamic wsa881x detection



Add support in machine driver to be able to parse device
tree for all possible wsa881x that are supported in the
target, find out from ALSA core about how many wsa881x out
of the list of devices passed from device tree are present
in the target and already registered with ALSA as codec,
and eventually register those wsa881x devices (which are
present) as AUX codec to be used with the sound card.

Change-Id: I31b628f295fac68c05043951f3f5cd4a8f8f6510
Signed-off-by: default avatarVenkata Narendra Kumar Gutta <vgutta@codeaurora.org>
parent 3b74bf1e
Loading
Loading
Loading
Loading
+174 −87
Original line number Diff line number Diff line
@@ -20,6 +20,8 @@
#include "qdsp6v2/msm-pcm-routing-v2.h"
#include "../codecs/wcd9335.h"

#define DEV_NAME_STR_LEN            32

static struct snd_soc_card snd_soc_card_msm[MAX_CODECS];
static struct snd_soc_card snd_soc_card_msm_card;

@@ -1233,29 +1235,13 @@ static struct snd_soc_dai_link msm8952_common_be_dai[] = {
	},
};

static struct snd_soc_aux_dev msm895x_aux_dev[] = {
	{
		.name = "wsa881x.0",
		.codec_name =  NULL,
		.init = msm895x_wsa881x_init,
	},
	{
		.name = "wsa881x.1",
		.codec_name = NULL,
		.init = msm895x_wsa881x_init,
	},
struct msm895x_wsa881x_dev_info {
	struct device_node *of_node;
	u32 index;
};

static struct snd_soc_codec_conf msm895x_codec_conf[] = {
	{
		.dev_name = NULL,
		.name_prefix = NULL,
	},
	{
		.dev_name = NULL,
		.name_prefix = NULL,
	},
};
static struct snd_soc_aux_dev *msm895x_aux_dev;
static struct snd_soc_codec_conf *msm895x_codec_conf;

static struct snd_soc_dai_link msm8952_tomtom_dai_links[
ARRAY_SIZE(msm8952_common_fe_dai) +
@@ -1269,17 +1255,174 @@ ARRAY_SIZE(msm8952_tasha_fe_dai) +
ARRAY_SIZE(msm8952_common_be_dai) +
ARRAY_SIZE(msm8952_tasha_be_dai)];

int msm8952_init_wsa_dev(struct platform_device *pdev,
			struct snd_soc_card *card)
{
	struct device_node *wsa_of_node;
	u32 wsa_max_devs;
	u32 wsa_dev_cnt;
	char *dev_name_str = NULL;
	struct msm895x_wsa881x_dev_info *wsa881x_dev_info;
	const char *wsa_auxdev_name_prefix[1];
	int found = 0;
	int i;
	int ret;

	/* Get maximum WSA device count for this platform */
	ret = of_property_read_u32(pdev->dev.of_node,
					"qcom,wsa-max-devs", &wsa_max_devs);
	if (ret) {
		dev_dbg(&pdev->dev,
			"%s: wsa-max-devs property missing in DT %s, ret = %d\n",
			__func__, pdev->dev.of_node->full_name, ret);
		return 0;
	}
	if (wsa_max_devs == 0) {
		dev_warn(&pdev->dev,
			"%s: Max WSA devices is 0 for this target?\n",
			__func__);
		return 0;
				}

	/* Get count of WSA device phandles for this platform */
	wsa_dev_cnt = of_count_phandle_with_args(pdev->dev.of_node,
						"qcom,wsa-devs", NULL);
	if (wsa_dev_cnt == -ENOENT) {
		dev_warn(&pdev->dev, "%s: No wsa device defined in DT.\n",
			__func__);
		return 0;
	} else if (wsa_dev_cnt <= 0) {
		dev_err(&pdev->dev,
			"%s: Error reading wsa device from DT. wsa_dev_cnt = %d\n",
			__func__, wsa_dev_cnt);
		return -EINVAL;
	}

	/*
	 * Expect total phandles count to be NOT less than maximum possible
	 * WSA count. However, if it is less, then assign same value to
	 * max count as well.
	 */

	if (wsa_dev_cnt < wsa_max_devs) {
		dev_dbg(&pdev->dev,
			"%s: wsa_max_devs = %d cannot exceed wsa_dev_cnt = %d\n",
			__func__, wsa_max_devs, wsa_dev_cnt);
		wsa_max_devs = wsa_dev_cnt;
	}

	/* Make sure prefix string passed for each WSA device */
	ret = of_property_count_strings(pdev->dev.of_node,
			"qcom,wsa-aux-dev-prefix");
	if (ret != wsa_dev_cnt) {
		dev_err(&pdev->dev,
				"%s: expecting %d wsa prefix. Defined only %d in DT\n",
				__func__, wsa_dev_cnt, ret);
		return -EINVAL;
	}

	/*
	 * Alloc mem to store phandle and index info of WSA device, if already
	 * registered with ALSA core
	 */
	wsa881x_dev_info = devm_kcalloc(&pdev->dev, wsa_max_devs,
			sizeof(struct msm895x_wsa881x_dev_info),
			GFP_KERNEL);
	if (!wsa881x_dev_info)
		return -ENOMEM;

	/*
	 * search and check whether all WSA devices are already
	 * registered with ALSA core or not. If found a node, store
	 * the node and the index in a local array of struct for later
	 * use.
	 */
	for (i = 0; i < wsa_dev_cnt; i++) {
		wsa_of_node = of_parse_phandle(pdev->dev.of_node,
				"qcom,wsa-devs", i);
		if (unlikely(!wsa_of_node)) {
			/* we should not be here */
			dev_err(&pdev->dev,
					"%s: wsa dev node is not present\n",
					__func__);
			return -EINVAL;
		}
		if (soc_find_component(wsa_of_node, NULL)) {
			/* WSA device registered with ALSA core */
			wsa881x_dev_info[found].of_node = wsa_of_node;
			wsa881x_dev_info[found].index = i;
			found++;
			if (found == wsa_max_devs)
				break;
		}
	}

	if (found < wsa_max_devs) {
		dev_dbg(&pdev->dev,
				"%s: failed to find %d components. Found only %d\n",
				__func__, wsa_max_devs, found);
		return -EPROBE_DEFER;
	}
	dev_info(&pdev->dev,
			"%s: found %d wsa881x devices registered with ALSA core\n",
			__func__, found);

	card->num_aux_devs = wsa_max_devs;
	card->num_configs = wsa_max_devs;

	/* Alloc array of AUX devs struct */
	msm895x_aux_dev = devm_kcalloc(&pdev->dev, card->num_aux_devs,
			sizeof(struct snd_soc_aux_dev),
			GFP_KERNEL);
	if (!msm895x_aux_dev)
		return -ENOMEM;

	/* Alloc array of codec conf struct */
	msm895x_codec_conf = devm_kcalloc(&pdev->dev, card->num_aux_devs,
			sizeof(struct snd_soc_codec_conf),
			GFP_KERNEL);
	if (!msm895x_codec_conf)
		return -ENOMEM;

	for (i = 0; i < card->num_aux_devs; i++) {
		dev_name_str = devm_kzalloc(&pdev->dev, DEV_NAME_STR_LEN,
				GFP_KERNEL);
		if (!dev_name_str)
			return -ENOMEM;

		ret = of_property_read_string_index(pdev->dev.of_node,
				"qcom,wsa-aux-dev-prefix",
				wsa881x_dev_info[i].index,
				wsa_auxdev_name_prefix);
		if (ret) {
			dev_err(&pdev->dev,
					"%s: failed to read wsa aux dev prefix, ret = %d\n",
					__func__, ret);
			return -EINVAL;
		}

		snprintf(dev_name_str, strlen("wsa881x.%d"), "wsa881x.%d", i);
		msm895x_aux_dev[i].name = dev_name_str;
		msm895x_aux_dev[i].codec_name = NULL;
		msm895x_aux_dev[i].codec_of_node =
			wsa881x_dev_info[i].of_node;
		msm895x_aux_dev[i].init = msm895x_wsa881x_init;
		msm895x_codec_conf[i].dev_name = NULL;
		msm895x_codec_conf[i].name_prefix = wsa_auxdev_name_prefix[0];
		msm895x_codec_conf[i].of_node =
			wsa881x_dev_info[i].of_node;
	}
	card->codec_conf = msm895x_codec_conf;
	card->aux_dev = msm895x_aux_dev;

	return 0;
}

struct snd_soc_card *populate_snd_card_dailinks(struct device *dev)
{
	struct snd_soc_card *card = &snd_soc_card_msm_card;
	struct snd_soc_dai_link *msm8952_dai_links = NULL;
	int num_links, ret, len1, len2, len3, i;
	const char *wsa = "asoc-wsa-codec-names";
	const char *wsa_prefix = "asoc-wsa-codec-prefixes";
	int num_strings;
	char *temp_str = NULL;
	const char *wsa_str = NULL;
	const char *wsa_prefix_str = NULL;
	int num_links, ret, len1, len2, len3;

	card->dev = dev;
	ret = snd_soc_of_parse_card_name(card, "qcom,model");
@@ -1306,7 +1449,9 @@ struct snd_soc_card *populate_snd_card_dailinks(struct device *dev)
			msm8952_tomtom_be_dai, sizeof(msm8952_tomtom_be_dai));
		msm8952_dai_links = msm8952_tomtom_dai_links;
	} else if (!strcmp(card->name, "msm8976-tasha-snd-card") ||
			!strcmp(card->name, "msm8976-tasha-skun-snd-card")) {
			!strcmp(card->name, "msm8976-tasha-skun-snd-card") ||
			!strcmp(card->name, "msm8952-tasha-snd-card") ||
			!strcmp(card->name, "msm8952-tasha-skun-snd-card")) {

		len1 = ARRAY_SIZE(msm8952_common_fe_dai);
		len2 = len1 + ARRAY_SIZE(msm8952_tasha_fe_dai);
@@ -1323,70 +1468,12 @@ struct snd_soc_card *populate_snd_card_dailinks(struct device *dev)
		memcpy(msm8952_tasha_dai_links + len3,
			msm8952_tasha_be_dai, sizeof(msm8952_tasha_be_dai));
		msm8952_dai_links = msm8952_tasha_dai_links;

		num_strings = of_property_count_strings(dev->of_node,
				wsa);
		card->aux_dev = msm895x_aux_dev;
		card->num_aux_devs	= num_strings;
		card->codec_conf	= msm895x_codec_conf;
		card->num_configs	= num_strings;

		for (i = 0; i < num_strings; i++) {
			ret = of_property_read_string_index(
					dev->of_node, wsa,
					i, &wsa_str);
			if (ret) {
				dev_err(dev,
					"%s:of read string %s i %d error %d\n",
					__func__, wsa, i, ret);
				goto err;
	}

			temp_str = kstrdup(wsa_str, GFP_KERNEL);
			if (!temp_str)
				goto err;
			msm895x_aux_dev[i].codec_name = temp_str;
			temp_str = NULL;

			temp_str = kstrdup(wsa_str, GFP_KERNEL);
			if (!temp_str)
				goto err;
			msm895x_codec_conf[i].dev_name = temp_str;
			temp_str = NULL;

			ret = of_property_read_string_index(
					dev->of_node, wsa_prefix,
					i, &wsa_prefix_str);
			if (ret) {
				dev_err(dev,
					"%s:of read string %s i %d error %d\n",
					__func__, wsa_prefix, i, ret);
				goto err;
			}

			temp_str = kstrdup(wsa_prefix_str, GFP_KERNEL);
			if (!temp_str)
				goto err;
			msm895x_codec_conf[i].name_prefix = temp_str;

			temp_str = NULL;
		}
	}

	card->dai_link = msm8952_dai_links;
	card->num_links = num_links;
	card->dev = dev;

	return card;
err:
	if (card->num_aux_devs > 0) {
		for (i = 0; i < card->num_aux_devs; i++) {
			kfree(msm895x_aux_dev[i].codec_name);
			kfree(msm895x_codec_conf[i].dev_name);
			kfree(msm895x_codec_conf[i].name_prefix);
		}
	}
	return NULL;
}

void msm895x_free_auxdev_mem(struct platform_device *pdev)
+23 −28
Original line number Diff line number Diff line
@@ -320,54 +320,45 @@ int msm895x_wsa881x_init(struct snd_soc_component *component)
	unsigned int ch_rate[WSA881X_MAX_SWR_PORTS] = {2400, 600, 300, 1200};
	unsigned int ch_mask[WSA881X_MAX_SWR_PORTS] = {0x1, 0xF, 0x3, 0x3};
	struct snd_soc_codec *codec = snd_soc_component_to_codec(component);
	struct snd_soc_card *card = codec->component.card;
	struct msm8952_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card);
	struct msm8952_asoc_mach_data *pdata;
	struct snd_soc_dapm_context *dapm = &codec->dapm;
	struct msm895x_auxcodec_prefix_map codec_prefix_map[MAX_AUX_CODECS] = {
	{ "wsa881x.20170211", "SpkrRight" },
	{ "wsa881x.20170212", "SpkrLeft" },
	{ "wsa881x.21170213", "SpkrRight" },
	{ "wsa881x.21170214", "SpkrLeft" } };
	u8 i;

	if (!codec) {
		pr_err("%s codec is NULL\n", __func__);
		return -EINVAL;
	}

	for (i = 0; i < MAX_AUX_CODECS; i++) {
		if (!strcmp(component->name, codec_prefix_map[i].codec_name))
			break;
	}
	if (i >= MAX_AUX_CODECS) {
		pr_err("%s: could not find prefix map\n" , __func__);
		return -EINVAL;
	}
	if (!strcmp(codec_prefix_map[i].codec_prefix, "SpkrLeft")) {
	if (!strcmp(component->name_prefix, "SpkrLeft")) {
		dev_dbg(codec->dev, "%s: setting left ch map to codec %s\n",
				__func__, codec->component.name);
		wsa881x_set_channel_map(codec, &spkleft_ports[0],
				WSA881X_MAX_SWR_PORTS, &ch_mask[0],
				&ch_rate[0]);
	} else if (!strcmp(codec_prefix_map[i].codec_prefix, "SpkrRight")) {
		if (dapm->component) {
			snd_soc_dapm_ignore_suspend(dapm, "SpkrLeft IN");
			snd_soc_dapm_ignore_suspend(dapm, "SpkrLeft SPKR");
		}
	} else if (!strcmp(component->name_prefix, "SpkrRight")) {
		dev_dbg(codec->dev, "%s: setting right ch map to codec %s\n",
				__func__, codec->component.name);
		wsa881x_set_channel_map(codec, &spkright_ports[0],
				WSA881X_MAX_SWR_PORTS, &ch_mask[0],
				&ch_rate[0]);
		if (dapm->component) {
			snd_soc_dapm_ignore_suspend(dapm, "SpkrRight IN");
			snd_soc_dapm_ignore_suspend(dapm, "SpkrRight SPKR");
		}
	} else {
		dev_err(codec->dev, "%s: wrong codec name %s\n", __func__,
				codec->component.name);
		return -EINVAL;
	}
	pdata = snd_soc_card_get_drvdata(card);


	pdata = snd_soc_card_get_drvdata(component->card);
	if (pdata && pdata->codec_root)
		wsa881x_codec_info_create_codec_entry(pdata->codec_root,
						      codec);
	if (!strcmp(codec_prefix_map[i].codec_prefix, "SpkrLeft")) {
		snd_soc_dapm_ignore_suspend(dapm, "SpkrLeft IN");
		snd_soc_dapm_ignore_suspend(dapm, "SpkrLeft SPKR");
	} else if (!strcmp(codec_prefix_map[i].codec_prefix, "SpkrRight")) {
		snd_soc_dapm_ignore_suspend(dapm, "SpkrRight IN");
		snd_soc_dapm_ignore_suspend(dapm, "SpkrRight SPKR");
	}

	return 0;
}

@@ -2345,6 +2336,10 @@ static int msm8952_asoc_machine_probe(struct platform_device *pdev)
		goto err;
	}

	ret = msm8952_init_wsa_dev(pdev, card);
	if (ret)
		goto err;

	ret = snd_soc_register_card(card);
	if (ret) {
		if (codec_reg_done)
+2 −0
Original line number Diff line number Diff line
@@ -71,5 +71,7 @@ struct snd_soc_card *populate_snd_card_dailinks(struct device *dev);
int msm_slim_4_tx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
					    struct snd_pcm_hw_params *params);
int msm895x_wsa881x_init(struct snd_soc_component *component);
int msm8952_init_wsa_dev(struct platform_device *pdev,
		struct snd_soc_card *card);
void msm895x_free_auxdev_mem(struct platform_device *pdev);
#endif