All of lore.kernel.org
 help / color / mirror / Atom feed
From: Kuninori Morimoto <kuninori.morimoto.gx-zM6kxYcvzFBBDgjK7y7TUQ@public.gmane.org>
To: Mark Brown <broonie-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>,
	Rob Herring <robh+dt-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
Cc: Linux-ALSA <alsa-devel-K7yf7f+aM1XWsZ/bQMPhNw@public.gmane.org>,
	Simon <horms-/R6kz+dDXgpPR4JQBCEnsQ@public.gmane.org>,
	Linux-DT <devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org>
Subject: [PATCH v2 7/7] ASoC: add simple-graph-card support
Date: Mon, 13 Feb 2017 04:23:16 +0000	[thread overview]
Message-ID: <87poim7md3.wl%kuninori.morimoto.gx@renesas.com> (raw)
In-Reply-To: <87zihq7mja.wl%kuninori.morimoto.gx-zM6kxYcvzFBBDgjK7y7TUQ@public.gmane.org>


From: Kuninori Morimoto <kuninori.morimoto.gx-zM6kxYcvzFBBDgjK7y7TUQ@public.gmane.org>

OF-graph base DT binding are used on V4L2, and ALSA SoC is using
different style of DT today. Now ALSA SoC supports simple-card driver
for generic/simple sound card.
In the future, V4L2 / ALSA will support HDMI, and then, DT bindings
between V4L2 / ALSA should be merged.
This patch adds OF-graph base DT binding with simple-card style

Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx-zM6kxYcvzFBBDgjK7y7TUQ@public.gmane.org>
---
v1 -> v2

 - no change

 sound/soc/generic/Kconfig             |   7 +
 sound/soc/generic/Makefile            |   2 +
 sound/soc/generic/simple-graph-card.c | 303 ++++++++++++++++++++++++++++++++++
 3 files changed, 312 insertions(+)
 create mode 100644 sound/soc/generic/simple-graph-card.c

diff --git a/sound/soc/generic/Kconfig b/sound/soc/generic/Kconfig
index d023959..efefabd 100644
--- a/sound/soc/generic/Kconfig
+++ b/sound/soc/generic/Kconfig
@@ -14,3 +14,10 @@ config SND_SIMPLE_SCU_CARD
 	help
 	  This option enables generic simple SCU sound card support.
 	  It supports DPCM of multi CPU single Codec system.
+
+config SND_SIMPLE_GRAPH_CARD
+	tristate "ASoC Simple Graph sound card support"
+	depends on OF
+	select SND_SIMPLE_CARD_UTILS
+	help
+	  This option enables generic simple Graph sound card support
diff --git a/sound/soc/generic/Makefile b/sound/soc/generic/Makefile
index ee750f3..94eb6f1 100644
--- a/sound/soc/generic/Makefile
+++ b/sound/soc/generic/Makefile
@@ -1,7 +1,9 @@
 snd-soc-simple-card-utils-objs	:= simple-card-utils.o
 snd-soc-simple-card-objs	:= simple-card.o
 snd-soc-simple-scu-card-objs	:= simple-scu-card.o
+snd-soc-simple-graph-card-objs	:= simple-graph-card.o
 
 obj-$(CONFIG_SND_SIMPLE_CARD_UTILS)	+= snd-soc-simple-card-utils.o
 obj-$(CONFIG_SND_SIMPLE_CARD)		+= snd-soc-simple-card.o
 obj-$(CONFIG_SND_SIMPLE_SCU_CARD)	+= snd-soc-simple-scu-card.o
+obj-$(CONFIG_SND_SIMPLE_GRAPH_CARD)	+= snd-soc-simple-graph-card.o
diff --git a/sound/soc/generic/simple-graph-card.c b/sound/soc/generic/simple-graph-card.c
new file mode 100644
index 0000000..700717b
--- /dev/null
+++ b/sound/soc/generic/simple-graph-card.c
@@ -0,0 +1,303 @@
+/*
+ * ASoC simple graph sound card support
+ *
+ * Copyright (C) 2016 Renesas Solutions Corp.
+ * Kuninori Morimoto <kuninori.morimoto.gx-zM6kxYcvzFBBDgjK7y7TUQ@public.gmane.org>
+ *
+ * based on ${LINUX}/sound/soc/generic/simple-card.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/gpio.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
+#include <linux/of_graph.h>
+#include <linux/platform_device.h>
+#include <linux/string.h>
+#include <sound/jack.h>
+#include <sound/simple_card_utils.h>
+
+struct simple_card_data {
+	struct snd_soc_card snd_card;
+	struct simple_dai_props {
+		struct asoc_simple_dai cpu_dai;
+		struct asoc_simple_dai codec_dai;
+	} *dai_props;
+	struct snd_soc_dai_link *dai_link;
+};
+
+#define simple_priv_to_dev(priv) ((priv)->snd_card.dev)
+#define simple_priv_to_link(priv, i) ((priv)->snd_card.dai_link + (i))
+#define simple_priv_to_props(priv, i) ((priv)->dai_props + (i))
+
+#define PREFIX	"simple-audio-card,"
+
+static int asoc_simple_card_startup(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct simple_card_data *priv =	snd_soc_card_get_drvdata(rtd->card);
+	struct simple_dai_props *dai_props =
+		simple_priv_to_props(priv, rtd->num);
+	int ret;
+
+	ret = clk_prepare_enable(dai_props->cpu_dai.clk);
+	if (ret)
+		return ret;
+
+	ret = clk_prepare_enable(dai_props->codec_dai.clk);
+	if (ret)
+		clk_disable_unprepare(dai_props->cpu_dai.clk);
+
+	return ret;
+}
+
+static void asoc_simple_card_shutdown(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct simple_card_data *priv =	snd_soc_card_get_drvdata(rtd->card);
+	struct simple_dai_props *dai_props =
+		simple_priv_to_props(priv, rtd->num);
+
+	clk_disable_unprepare(dai_props->cpu_dai.clk);
+
+	clk_disable_unprepare(dai_props->codec_dai.clk);
+}
+
+static struct snd_soc_ops asoc_simple_card_ops = {
+	.startup = asoc_simple_card_startup,
+	.shutdown = asoc_simple_card_shutdown,
+};
+
+static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd)
+{
+	struct simple_card_data *priv =	snd_soc_card_get_drvdata(rtd->card);
+	struct snd_soc_dai *codec = rtd->codec_dai;
+	struct snd_soc_dai *cpu = rtd->cpu_dai;
+	struct simple_dai_props *dai_props =
+		simple_priv_to_props(priv, rtd->num);
+	int ret;
+
+	ret = asoc_simple_card_init_dai(codec, &dai_props->codec_dai);
+	if (ret < 0)
+		return ret;
+
+	ret = asoc_simple_card_init_dai(cpu, &dai_props->cpu_dai);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static int asoc_simple_card_dai_link_of(struct device_node *cpu_port,
+					struct simple_card_data *priv,
+					int idx)
+{
+	struct device *dev = simple_priv_to_dev(priv);
+	struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, idx);
+	struct simple_dai_props *dai_props = simple_priv_to_props(priv, idx);
+	struct asoc_simple_dai *cpu_dai = &dai_props->cpu_dai;
+	struct asoc_simple_dai *codec_dai = &dai_props->codec_dai;
+	struct device_node *cpu_ep    = of_get_next_child(cpu_port, NULL);
+	struct device_node *codec_ep = of_graph_get_remote_endpoint(cpu_ep);
+	struct device_node *rcpu_ep = of_graph_get_remote_endpoint(codec_ep);
+	int ret;
+
+	if (rcpu_ep != cpu_ep) {
+		dev_err(dev, "remote-endpoint missmatch (%s/%s/%s)\n",
+			cpu_ep->name, codec_ep->name, rcpu_ep->name);
+		return -EINVAL;
+	}
+
+	ret = asoc_simple_card_parse_daifmt(dev, cpu_ep, codec_ep,
+					    PREFIX, &dai_link->dai_fmt);
+	if (ret < 0)
+		goto dai_link_of_err;
+
+	/*
+	 * we need to consider "mclk-fs" around here
+	 * see simple-card
+	 */
+
+	ret = asoc_simple_card_parse_graph_cpu(cpu_ep, dai_link);
+	if (ret < 0)
+		goto dai_link_of_err;
+
+	ret = asoc_simple_card_parse_graph_codec(codec_ep, dai_link);
+	if (ret < 0)
+		goto dai_link_of_err;
+
+	ret = snd_soc_of_parse_tdm_slot(cpu_ep,
+					&cpu_dai->tx_slot_mask,
+					&cpu_dai->rx_slot_mask,
+					&cpu_dai->slots,
+					&cpu_dai->slot_width);
+	if (ret < 0)
+		goto dai_link_of_err;
+
+	ret = snd_soc_of_parse_tdm_slot(codec_ep,
+					&codec_dai->tx_slot_mask,
+					&codec_dai->rx_slot_mask,
+					&codec_dai->slots,
+					&codec_dai->slot_width);
+	if (ret < 0)
+		goto dai_link_of_err;
+
+	ret = asoc_simple_card_parse_clk_cpu(dev, cpu_ep, dai_link, cpu_dai);
+	if (ret < 0)
+		goto dai_link_of_err;
+
+	ret = asoc_simple_card_parse_clk_codec(dev, codec_ep, dai_link, codec_dai);
+	if (ret < 0)
+		goto dai_link_of_err;
+
+	ret = asoc_simple_card_canonicalize_dailink(dai_link);
+	if (ret < 0)
+		goto dai_link_of_err;
+
+	ret = asoc_simple_card_set_dailink_name(dev, dai_link,
+						"%s-%s",
+						dai_link->cpu_dai_name,
+						dai_link->codec_dai_name);
+	if (ret < 0)
+		goto dai_link_of_err;
+
+	dai_link->ops = &asoc_simple_card_ops;
+	dai_link->init = asoc_simple_card_dai_init;
+
+	dev_dbg(dev, "\tname : %s\n", dai_link->stream_name);
+	dev_dbg(dev, "\tformat : %04x\n", dai_link->dai_fmt);
+	dev_dbg(dev, "\tcpu : %s / %d\n",
+		dai_link->cpu_dai_name,
+		dai_props->cpu_dai.sysclk);
+	dev_dbg(dev, "\tcodec : %s / %d\n",
+		dai_link->codec_dai_name,
+		dai_props->codec_dai.sysclk);
+
+	asoc_simple_card_canonicalize_cpu(dai_link,
+					  priv->snd_card.num_links == 1);
+
+dai_link_of_err:
+	of_node_put(codec_ep);
+
+	return ret;
+}
+
+static int asoc_simple_card_parse_of(struct device *dev,
+				     struct simple_card_data *priv)
+{
+	struct device_node *node = dev->of_node;
+	struct snd_soc_card *card = &priv->snd_card;
+	struct device_node *np;
+	int idx = 0;
+	int ret;
+
+	/*
+	 * we need to consider "widgets", "routing", "mclk-fs" around here
+	 * see simple-card
+	 */
+
+	while ((np = of_parse_phandle(node, "dais", idx))) {
+		ret = asoc_simple_card_dai_link_of(np, priv, idx++);
+		if (ret < 0)
+			return ret;
+	}
+
+	return asoc_simple_card_parse_card_name(card, PREFIX);
+}
+
+static int asoc_simple_get_dais_count(struct device *dev)
+{
+	struct device_node *node = dev->of_node;
+	int count = 0;
+
+	if (of_get_property(node, "dais", NULL)) {
+		while (of_parse_phandle(node, "dais", count))
+			count++;
+	} else {
+		count = 1;
+	}
+
+	return count;
+}
+
+static int asoc_simple_card_probe(struct platform_device *pdev)
+{
+	struct simple_card_data *priv;
+	struct snd_soc_dai_link *dai_link;
+	struct simple_dai_props *dai_props;
+	struct device *dev = &pdev->dev;
+	int num, ret;
+
+	/* Allocate the private data and the DAI link array */
+	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	num = asoc_simple_get_dais_count(dev);
+
+	dai_props = devm_kzalloc(dev, sizeof(*dai_props) * num, GFP_KERNEL);
+	dai_link  = devm_kzalloc(dev, sizeof(*dai_link)  * num, GFP_KERNEL);
+	if (!dai_props || !dai_link)
+		return -ENOMEM;
+
+	priv->dai_props			= dai_props;
+	priv->dai_link			= dai_link;
+
+	/* Init snd_soc_card */
+	priv->snd_card.owner		= THIS_MODULE;
+	priv->snd_card.dev		= dev;
+	priv->snd_card.dai_link		= dai_link;
+	priv->snd_card.num_links	= num;
+
+	ret = asoc_simple_card_parse_of(dev, priv);
+	if (ret < 0) {
+		if (ret != -EPROBE_DEFER)
+			dev_err(dev, "parse error %d\n", ret);
+		goto err;
+	}
+
+	snd_soc_card_set_drvdata(&priv->snd_card, priv);
+
+	ret = devm_snd_soc_register_card(dev, &priv->snd_card);
+	if (ret >= 0)
+		return ret;
+err:
+	asoc_simple_card_clean_reference(&priv->snd_card);
+
+	return ret;
+}
+
+static int asoc_simple_card_remove(struct platform_device *pdev)
+{
+	struct snd_soc_card *card = platform_get_drvdata(pdev);
+	struct simple_card_data *priv = snd_soc_card_get_drvdata(card);
+
+	return asoc_simple_card_clean_reference(&priv->snd_card);
+}
+
+static const struct of_device_id asoc_simple_of_match[] = {
+	{ .compatible = "asoc-simple-graph-card", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, asoc_simple_of_match);
+
+static struct platform_driver asoc_simple_card = {
+	.driver = {
+		.name = "asoc-simple-graph-card",
+		.of_match_table = asoc_simple_of_match,
+	},
+	.probe = asoc_simple_card_probe,
+	.remove = asoc_simple_card_remove,
+};
+module_platform_driver(asoc_simple_card);
+
+MODULE_ALIAS("platform:asoc-simple-graph-card");
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("ASoC Simple Graph Sound Card");
+MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx-zM6kxYcvzFBBDgjK7y7TUQ@public.gmane.org>");
-- 
1.9.1

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

  parent reply	other threads:[~2017-02-13  4:23 UTC|newest]

Thread overview: 11+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-02-13  4:19 [PATCH v2 0/7][resend] ASoC: add OF-graph base simple-card Kuninori Morimoto
     [not found] ` <87zihq7mja.wl%kuninori.morimoto.gx-zM6kxYcvzFBBDgjK7y7TUQ@public.gmane.org>
2017-02-13  4:20   ` [PATCH v2 1/7] of_graph: add of_graph_get_remote_endpoint() Kuninori Morimoto
2017-02-13  4:21   ` [PATCH v2 2/7] of_graph: add of_graph_get_port_parent() Kuninori Morimoto
2017-02-13  4:21   ` [PATCH v2 3/7] of_graph: add of_graph_get_endpoint_count() Kuninori Morimoto
2017-02-13  4:22   ` [PATCH v2 4/7] ASoC: add snd_soc_get_dai_id() Kuninori Morimoto
2017-02-13  4:22   ` [PATCH v2 5/7] ASoC: simple-card-utils: add asoc_simple_card_parse_graph_dai() Kuninori Morimoto
2017-02-13  4:22   ` [PATCH v2 6/7] ASoC: add simple-graph-card document Kuninori Morimoto
     [not found]     ` <87r3327mdo.wl%kuninori.morimoto.gx-zM6kxYcvzFBBDgjK7y7TUQ@public.gmane.org>
2017-02-22 15:07       ` Rob Herring
2017-02-27  3:05         ` Kuninori Morimoto
2017-02-13  4:23   ` Kuninori Morimoto [this message]
2017-02-24 14:45     ` [PATCH v2 7/7] ASoC: add simple-graph-card support Rob Herring

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=87poim7md3.wl%kuninori.morimoto.gx@renesas.com \
    --to=kuninori.morimoto.gx-zm6kxycvzfbbdgjk7y7tuq@public.gmane.org \
    --cc=alsa-devel-K7yf7f+aM1XWsZ/bQMPhNw@public.gmane.org \
    --cc=broonie-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org \
    --cc=devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org \
    --cc=horms-/R6kz+dDXgpPR4JQBCEnsQ@public.gmane.org \
    --cc=robh+dt-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.