Beispiel #1
0
static int simple_parse_aux_devs(struct device_node *node,
				 struct simple_priv *priv)
{
	struct device *dev = simple_priv_to_dev(priv);
	struct device_node *aux_node;
	struct snd_soc_card *card = simple_priv_to_card(priv);
	int i, n, len;

	if (!of_find_property(node, PREFIX "aux-devs", &len))
		return 0;		/* Ok to have no aux-devs */

	n = len / sizeof(__be32);
	if (n <= 0)
		return -EINVAL;

	card->aux_dev = devm_kcalloc(dev,
			n, sizeof(*card->aux_dev), GFP_KERNEL);
	if (!card->aux_dev)
		return -ENOMEM;

	for (i = 0; i < n; i++) {
		aux_node = of_parse_phandle(node, PREFIX "aux-devs", i);
		if (!aux_node)
			return -EINVAL;
		card->aux_dev[i].codec_of_node = aux_node;
	}

	card->num_aux_devs = n;
	return 0;
}
Beispiel #2
0
static int simple_parse_of(struct simple_priv *priv)
{
	struct device *dev = simple_priv_to_dev(priv);
	struct device_node *top = dev->of_node;
	struct snd_soc_card *card = simple_priv_to_card(priv);
	struct link_info li;
	int ret;

	if (!top)
		return -EINVAL;

	ret = asoc_simple_card_of_parse_widgets(card, PREFIX);
	if (ret < 0)
		return ret;

	ret = asoc_simple_card_of_parse_routing(card, PREFIX);
	if (ret < 0)
		return ret;

	/* Single/Muti DAI link(s) & New style of DT node */
	memset(&li, 0, sizeof(li));
	for (li.cpu = 1; li.cpu >= 0; li.cpu--) {
		/*
		 * Detect all CPU first, and Detect all Codec 2nd.
		 *
		 * In Normal sound case, all DAIs are detected
		 * as "CPU-Codec".
		 *
		 * In DPCM sound case,
		 * all CPUs   are detected as "CPU-dummy", and
		 * all Codecs are detected as "dummy-Codec".
		 * To avoid random sub-device numbering,
		 * detect "dummy-Codec" in last;
		 */
		ret = simple_for_each_link(priv, &li,
					   simple_dai_link_of,
					   simple_dai_link_of_dpcm);
		if (ret < 0)
			return ret;
	}

	ret = asoc_simple_card_parse_card_name(card, PREFIX);
	if (ret < 0)
		return ret;

	ret = simple_parse_aux_devs(top, priv);

	return ret;
}
Beispiel #3
0
static int asoc_simple_card_parse_of(struct simple_card_data *priv)

{
	struct device *dev = simple_priv_to_dev(priv);
	struct device_node *np;
	struct snd_soc_card *card = simple_priv_to_card(priv);
	struct device_node *node = dev->of_node;
	unsigned int daifmt = 0;
	bool is_fe;
	int ret, i;

	if (!node)
		return -EINVAL;

	ret = asoc_simple_card_of_parse_widgets(card, PREFIX);
	if (ret < 0)
		return ret;

	ret = asoc_simple_card_of_parse_routing(card, PREFIX, 0);
	if (ret < 0)
		return ret;

	asoc_simple_card_parse_convert(dev, PREFIX, &priv->adata);

	/* find 1st codec */
	np = of_get_child_by_name(node, PREFIX "codec");
	if (!np)
		return -ENODEV;

	ret = asoc_simple_card_parse_daifmt(dev, node, np, PREFIX, &daifmt);
	if (ret < 0)
		return ret;

	i = 0;
	for_each_child_of_node(node, np) {
		is_fe = false;
		if (strcmp(np->name, PREFIX "cpu") == 0)
			is_fe = true;

		ret = asoc_simple_card_dai_link_of(np, priv, daifmt, i, is_fe);
		if (ret < 0)
			return ret;
		i++;
	}
Beispiel #4
0
static int asoc_simple_card_parse_of(struct simple_card_data *priv)
{
	struct device *dev = simple_priv_to_dev(priv);
	struct snd_soc_card *card = simple_priv_to_card(priv);
	struct device_node *dai_link;
	struct device_node *node = dev->of_node;
	int ret;

	if (!node)
		return -EINVAL;

	dai_link = of_get_child_by_name(node, PREFIX "dai-link");

	ret = asoc_simple_card_of_parse_widgets(card, PREFIX);
	if (ret < 0)
		goto card_parse_end;

	ret = asoc_simple_card_of_parse_routing(card, PREFIX, 1);
	if (ret < 0)
		goto card_parse_end;

	/* Factor to mclk, used in hw_params() */
	of_property_read_u32(node, PREFIX "mclk-fs", &priv->mclk_fs);

	/* Single/Muti DAI link(s) & New style of DT node */
	if (dai_link) {
		struct device_node *np = NULL;
		int i = 0;

		for_each_child_of_node(node, np) {
			dev_dbg(dev, "\tlink %d:\n", i);
			ret = asoc_simple_card_dai_link_of(np, priv,
							   i, false);
			if (ret < 0) {
				of_node_put(np);
				goto card_parse_end;
			}
			i++;
		}
	} else {
Beispiel #5
0
static int asoc_simple_card_dai_link_of(struct device_node *np,
					struct simple_card_data *priv,
					unsigned int daifmt,
					int idx, bool is_fe)
{
	struct device *dev = simple_priv_to_dev(priv);
	struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, idx);
	struct asoc_simple_dai *dai_props = simple_priv_to_props(priv, idx);
	struct snd_soc_card *card = simple_priv_to_card(priv);
	int ret;

	if (is_fe) {
		int is_single_links = 0;

		/* BE is dummy */
		dai_link->codec_of_node		= NULL;
		dai_link->codec_dai_name	= "snd-soc-dummy-dai";
		dai_link->codec_name		= "snd-soc-dummy";

		/* FE settings */
		dai_link->dynamic		= 1;
		dai_link->dpcm_merged_format	= 1;

		ret = asoc_simple_card_parse_cpu(np, dai_link, DAI, CELL,
						 &is_single_links);
		if (ret)
			return ret;

		ret = asoc_simple_card_parse_clk_cpu(dev, np, dai_link, dai_props);
		if (ret < 0)
			return ret;

		ret = asoc_simple_card_set_dailink_name(dev, dai_link,
							"fe.%s",
							dai_link->cpu_dai_name);
		if (ret < 0)
			return ret;

		asoc_simple_card_canonicalize_cpu(dai_link, is_single_links);
	} else {
		/* FE is dummy */
		dai_link->cpu_of_node		= NULL;
		dai_link->cpu_dai_name		= "snd-soc-dummy-dai";
		dai_link->cpu_name		= "snd-soc-dummy";

		/* BE settings */
		dai_link->no_pcm		= 1;
		dai_link->be_hw_params_fixup	= asoc_simple_card_be_hw_params_fixup;

		ret = asoc_simple_card_parse_codec(np, dai_link, DAI, CELL);
		if (ret < 0)
			return ret;

		ret = asoc_simple_card_parse_clk_codec(dev, np, dai_link, dai_props);
		if (ret < 0)
			return ret;

		ret = asoc_simple_card_set_dailink_name(dev, dai_link,
							"be.%s",
							dai_link->codec_dai_name);
		if (ret < 0)
			return ret;

		snd_soc_of_parse_audio_prefix(card,
					      &priv->codec_conf,
					      dai_link->codec_of_node,
					      PREFIX "prefix");
	}

	ret = asoc_simple_card_of_parse_tdm(np, dai_props);
	if (ret)
		return ret;

	ret = asoc_simple_card_canonicalize_dailink(dai_link);
	if (ret < 0)
		return ret;

	dai_link->dai_fmt		= daifmt;
	dai_link->dpcm_playback		= 1;
	dai_link->dpcm_capture		= 1;
	dai_link->ops			= &asoc_simple_card_ops;
	dai_link->init			= asoc_simple_card_dai_init;

	return 0;
}
Beispiel #6
0
static int simple_probe(struct platform_device *pdev)
{
	struct simple_priv *priv;
	struct snd_soc_dai_link *dai_link;
	struct simple_dai_props *dai_props;
	struct asoc_simple_dai *dais;
	struct device *dev = &pdev->dev;
	struct device_node *np = dev->of_node;
	struct snd_soc_card *card;
	struct snd_soc_codec_conf *cconf;
	struct link_info li;
	int ret, i;

	/* Allocate the private data and the DAI link array */
	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
	if (!priv)
		return -ENOMEM;

	card = simple_priv_to_card(priv);
	card->owner		= THIS_MODULE;
	card->dev		= dev;
	card->probe		= simple_soc_probe;

	memset(&li, 0, sizeof(li));
	simple_get_dais_count(priv, &li);
	if (!li.link || !li.dais)
		return -EINVAL;

	dai_props = devm_kcalloc(dev, li.link, sizeof(*dai_props), GFP_KERNEL);
	dai_link  = devm_kcalloc(dev, li.link, sizeof(*dai_link),  GFP_KERNEL);
	dais      = devm_kcalloc(dev, li.dais, sizeof(*dais),      GFP_KERNEL);
	cconf     = devm_kcalloc(dev, li.conf, sizeof(*cconf),     GFP_KERNEL);
	if (!dai_props || !dai_link || !dais)
		return -ENOMEM;

	/*
	 * Use snd_soc_dai_link_component instead of legacy style
	 * It is codec only. but cpu/platform will be supported in the future.
	 * see
	 *	soc-core.c :: snd_soc_init_multicodec()
	 */
	for (i = 0; i < li.link; i++) {
		dai_link[i].codecs	= &dai_props[i].codecs;
		dai_link[i].num_codecs	= 1;
		dai_link[i].platforms	= &dai_props[i].platforms;
		dai_link[i].num_platforms = 1;
	}

	priv->dai_props		= dai_props;
	priv->dai_link		= dai_link;
	priv->dais		= dais;
	priv->codec_conf	= cconf;

	card->dai_link		= priv->dai_link;
	card->num_links		= li.link;
	card->codec_conf	= cconf;
	card->num_configs	= li.conf;

	if (np && of_device_is_available(np)) {

		ret = simple_parse_of(priv);
		if (ret < 0) {
			if (ret != -EPROBE_DEFER)
				dev_err(dev, "parse error %d\n", ret);
			goto err;
		}

	} else {
		struct asoc_simple_card_info *cinfo;
		struct snd_soc_dai_link_component *codecs;
		struct snd_soc_dai_link_component *platform;
		int dai_idx = 0;

		cinfo = dev->platform_data;
		if (!cinfo) {
			dev_err(dev, "no info for asoc-simple-card\n");
			return -EINVAL;
		}

		if (!cinfo->name ||
		    !cinfo->codec_dai.name ||
		    !cinfo->codec ||
		    !cinfo->platform ||
		    !cinfo->cpu_dai.name) {
			dev_err(dev, "insufficient asoc_simple_card_info settings\n");
			return -EINVAL;
		}

		dai_props->cpu_dai	= &priv->dais[dai_idx++];
		dai_props->codec_dai	= &priv->dais[dai_idx++];

		codecs			= dai_link->codecs;
		codecs->name		= cinfo->codec;
		codecs->dai_name	= cinfo->codec_dai.name;

		platform		= dai_link->platforms;
		platform->name		= cinfo->platform;

		card->name		= (cinfo->card) ? cinfo->card : cinfo->name;
		dai_link->name		= cinfo->name;
		dai_link->stream_name	= cinfo->name;
		dai_link->cpu_dai_name	= cinfo->cpu_dai.name;
		dai_link->dai_fmt	= cinfo->daifmt;
		dai_link->init		= simple_dai_init;
		memcpy(priv->dai_props->cpu_dai, &cinfo->cpu_dai,
					sizeof(*priv->dai_props->cpu_dai));
		memcpy(priv->dai_props->codec_dai, &cinfo->codec_dai,
					sizeof(*priv->dai_props->codec_dai));
	}

	snd_soc_card_set_drvdata(card, priv);

	ret = devm_snd_soc_register_card(dev, card);
	if (ret < 0)
		goto err;

	return 0;
err:
	asoc_simple_card_clean_reference(card);

	return ret;
}