All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v4 0/8] ASoC: core: Add support for DAI multicodec
@ 2014-07-01  7:47 Benoit Cousson
  2014-07-01  7:47 ` [PATCH v4 1/8] ASoC: core: Change soc_link_dai_widgets signature for multiple codecs Benoit Cousson
                   ` (7 more replies)
  0 siblings, 8 replies; 43+ messages in thread
From: Benoit Cousson @ 2014-07-01  7:47 UTC (permalink / raw)
  To: broonie, lgirdwood, lars; +Cc: misael.lopez, alsa-devel, Benoit Cousson

Hi Lars, Mark and Liam,

Sorry for the delay. Here is the fourth version of the multicodec series.

I had to split it in smaller chunks since the previous patch was exceeding the 
size limit of the ML :-(

I think (and hope) I did address all the v3 comments from Lars.

I did not address the codec to codec link in multicodec case as suggested
by Lars.

There is still an open point about enforcing the number of channels for the
CPU dai in case the TDM slots are set for the CODEC dais.
I guess this point could be addressed later.

Please note that I have a very simple setup based on BBB to check if the series
is working, so it will be good to test it on various platforms to ensure
this is not generating any regression.

The series is based on asoc/for-next (v3.16-rc1).

Test and comments are welcome.

Thanks,
Benoit


v1: http://comments.gmane.org/gmane.linux.alsa.devel/120532

v2: http://comments.gmane.org/gmane.linux.alsa.devel/121024
- Split the first version in several patches.
- Remove the TDM fixup 

v3: 
- Fixed all the places that were not iterating over all the codecs.
- Change the structure and split it.

v4:
- Improve the TDM management
- Split the orginal patch in smaller chunks
- Ignore the CODEC to CODEC link case for the moment
- Add iteration for multicodecs everywhere


Benoit Cousson (8):
  ASoC: core: Change soc_link_dai_widgets signature for multiple codecs
  ASoC: pcm: Refactor soc_pcm_apply_msb for multicodecs
  ASoC: core: Add initial support for DAI multicodec
  ASoC: pcm: Add support for DAI multicodec
  ASoC: dapm: Add support for DAI multicodec
  ASoC: compress: Add support for DAI multicodec
  ASoC: pcm: Add soc_dai_hw_params helper
  ASoC: core: Add a warning for link_dai_widget in the multicodec case

 include/sound/soc-dai.h  |   4 +
 include/sound/soc.h      |  17 ++
 sound/soc/soc-compress.c |  94 +++++---
 sound/soc/soc-core.c     | 348 +++++++++++++++++++----------
 sound/soc/soc-dapm.c     |  93 ++++----
 sound/soc/soc-pcm.c      | 563 ++++++++++++++++++++++++++++++++---------------
 6 files changed, 751 insertions(+), 368 deletions(-)

-- 
1.9.1

^ permalink raw reply	[flat|nested] 43+ messages in thread

* [PATCH v4 1/8] ASoC: core: Change soc_link_dai_widgets signature for multiple codecs
  2014-07-01  7:47 [PATCH v4 0/8] ASoC: core: Add support for DAI multicodec Benoit Cousson
@ 2014-07-01  7:47 ` Benoit Cousson
  2014-07-01 17:17   ` Mark Brown
  2014-07-01  7:47 ` [PATCH v4 2/8] ASoC: pcm: Refactor soc_pcm_apply_msb for multicodecs Benoit Cousson
                   ` (6 subsequent siblings)
  7 siblings, 1 reply; 43+ messages in thread
From: Benoit Cousson @ 2014-07-01  7:47 UTC (permalink / raw)
  To: broonie, lgirdwood, lars; +Cc: misael.lopez, alsa-devel, Benoit Cousson

Since multiple codecs DAI will be usable in the future, remove
explicit unique codec_dai and cpu_dai parameters.
Replace them with snd_soc_pcm_runtime pointer that will contain
every instances.

No functionale change.

Signed-off-by: Benoit Cousson <bcousson@baylibre.com>
---
 sound/soc/soc-core.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index 19c1e958..37a965c 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -1448,9 +1448,10 @@ static int soc_probe_codec_dai(struct snd_soc_card *card,
 
 static int soc_link_dai_widgets(struct snd_soc_card *card,
 				struct snd_soc_dai_link *dai_link,
-				struct snd_soc_dai *cpu_dai,
-				struct snd_soc_dai *codec_dai)
+				struct snd_soc_pcm_runtime *rtd)
 {
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+	struct snd_soc_dai *codec_dai = rtd->codec_dai;
 	struct snd_soc_dapm_widget *play_w, *capture_w;
 	int ret;
 
@@ -1565,8 +1566,7 @@ static int soc_probe_link_dais(struct snd_soc_card *card, int num, int order)
 						codec2codec_close_delayed_work);
 
 			/* link the DAI widgets */
-			ret = soc_link_dai_widgets(card, dai_link,
-					cpu_dai, codec_dai);
+			ret = soc_link_dai_widgets(card, dai_link, rtd);
 			if (ret)
 				return ret;
 		}
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 43+ messages in thread

* [PATCH v4 2/8] ASoC: pcm: Refactor soc_pcm_apply_msb for multicodecs
  2014-07-01  7:47 [PATCH v4 0/8] ASoC: core: Add support for DAI multicodec Benoit Cousson
  2014-07-01  7:47 ` [PATCH v4 1/8] ASoC: core: Change soc_link_dai_widgets signature for multiple codecs Benoit Cousson
@ 2014-07-01  7:47 ` Benoit Cousson
  2014-07-01 17:20   ` Mark Brown
  2014-07-01  7:47 ` [PATCH v4 3/8] ASoC: core: Add initial support for DAI multicodec Benoit Cousson
                   ` (5 subsequent siblings)
  7 siblings, 1 reply; 43+ messages in thread
From: Benoit Cousson @ 2014-07-01  7:47 UTC (permalink / raw)
  To: broonie, lgirdwood, lars; +Cc: misael.lopez, alsa-devel, Benoit Cousson

Refactor the function to facilitate the migration to
multiple codecs.

Fix a trailing space in the header as well.

No functional change.

Signed-off-by: Benoit Cousson <bcousson@baylibre.com>
---
 sound/soc/soc-pcm.c | 35 ++++++++++++++++++++++++-----------
 1 file changed, 24 insertions(+), 11 deletions(-)

diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c
index 094676a..ab0712e 100644
--- a/sound/soc/soc-pcm.c
+++ b/sound/soc/soc-pcm.c
@@ -7,7 +7,7 @@
  * Copyright (C) 2010 Texas Instruments Inc.
  *
  * Authors: Liam Girdwood <lrg@ti.com>
- *          Mark Brown <broonie@opensource.wolfsonmicro.com>       
+ *          Mark Brown <broonie@opensource.wolfsonmicro.com>
  *
  *  This program is free software; you can redistribute  it and/or modify it
  *  under  the terms of  the GNU General  Public License as published by the
@@ -284,15 +284,10 @@ static int sample_sizes[] = {
 	24, 32,
 };
 
-static void soc_pcm_apply_msb(struct snd_pcm_substream *substream,
-			      struct snd_soc_dai *dai)
+static void soc_pcm_set_msb(struct snd_pcm_substream *substream,
+			    struct snd_soc_dai *dai, int bits)
 {
-	int ret, i, bits;
-
-	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-		bits = dai->driver->playback.sig_bits;
-	else
-		bits = dai->driver->capture.sig_bits;
+	int ret, i;
 
 	if (!bits)
 		return;
@@ -310,6 +305,25 @@ static void soc_pcm_apply_msb(struct snd_pcm_substream *substream,
 	}
 }
 
+static void soc_pcm_apply_msb(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+	struct snd_soc_dai *codec_dai = rtd->codec_dai;
+	unsigned int bits = 0, cpu_bits;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		bits = codec_dai->driver->playback.sig_bits;
+		cpu_bits = cpu_dai->driver->playback.sig_bits;
+	} else {
+		bits = codec_dai->driver->capture.sig_bits;
+		cpu_bits = cpu_dai->driver->capture.sig_bits;
+	}
+
+	soc_pcm_set_msb(substream, codec_dai, bits);
+	soc_pcm_set_msb(substream, cpu_dai, cpu_bits);
+}
+
 static void soc_pcm_init_runtime_hw(struct snd_pcm_runtime *runtime,
 	struct snd_soc_pcm_stream *codec_stream,
 	struct snd_soc_pcm_stream *cpu_stream)
@@ -433,8 +447,7 @@ static int soc_pcm_open(struct snd_pcm_substream *substream)
 		goto config_err;
 	}
 
-	soc_pcm_apply_msb(substream, codec_dai);
-	soc_pcm_apply_msb(substream, cpu_dai);
+	soc_pcm_apply_msb(substream);
 
 	/* Symmetry only applies if we've already got an active stream. */
 	if (cpu_dai->active) {
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 43+ messages in thread

* [PATCH v4 3/8] ASoC: core: Add initial support for DAI multicodec
  2014-07-01  7:47 [PATCH v4 0/8] ASoC: core: Add support for DAI multicodec Benoit Cousson
  2014-07-01  7:47 ` [PATCH v4 1/8] ASoC: core: Change soc_link_dai_widgets signature for multiple codecs Benoit Cousson
  2014-07-01  7:47 ` [PATCH v4 2/8] ASoC: pcm: Refactor soc_pcm_apply_msb for multicodecs Benoit Cousson
@ 2014-07-01  7:47 ` Benoit Cousson
  2014-07-01 13:19   ` Lars-Peter Clausen
  2014-07-01  7:47 ` [PATCH v4 4/8] ASoC: pcm: Add " Benoit Cousson
                   ` (4 subsequent siblings)
  7 siblings, 1 reply; 43+ messages in thread
From: Benoit Cousson @ 2014-07-01  7:47 UTC (permalink / raw)
  To: broonie, lgirdwood, lars
  Cc: Fabien Parent, misael.lopez, alsa-devel, Benoit Cousson

DAI link assumes a one to one mapping between CPU DAI and CODEC. In
some cases, the same CPU DAI can be connected to several codecs.
This is the case for example, if you connect two mono codecs to the
same I2S link in order to have a stereo card.
The current ASoC implementation does not allow such setup.

Add support for DAI links composed of a single CPU DAI and multiple
CODECs. Sound cards have to pass the CODECs array in the corresponding
DAI link through a new 'snd_soc_dai_link_component' struct. Each CODEC in
this array is described in the same manner single CODEC DAIs are
(either DT/OF node or codec_name).

Based on an original code done by Misael.

Signed-off-by: Benoit Cousson <bcousson@baylibre.com>
Signed-off-by: Misael Lopez Cruz <misael.lopez@ti.com>
Signed-off-by: Fabien Parent <fparent@baylibre.com>
---
 include/sound/soc-dai.h |   4 +
 include/sound/soc.h     |  13 ++
 sound/soc/soc-core.c    | 337 ++++++++++++++++++++++++++++++++----------------
 3 files changed, 242 insertions(+), 112 deletions(-)

diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h
index 031be2a..e8b3080 100644
--- a/include/sound/soc-dai.h
+++ b/include/sound/soc-dai.h
@@ -272,6 +272,10 @@ struct snd_soc_dai {
 	struct snd_soc_codec *codec;
 	struct snd_soc_component *component;
 
+	/* CODEC TDM slot masks and params (for fixup) */
+	unsigned int tx_mask;
+	unsigned int rx_mask;
+
 	struct snd_soc_card *card;
 
 	struct list_head list;
diff --git a/include/sound/soc.h b/include/sound/soc.h
index 9a5b4f6..f2142cf 100644
--- a/include/sound/soc.h
+++ b/include/sound/soc.h
@@ -846,6 +846,12 @@ struct snd_soc_platform_driver {
 	int (*bespoke_trigger)(struct snd_pcm_substream *, int);
 };
 
+struct snd_soc_dai_link_component {
+	const char *name;
+	const struct device_node *of_node;
+	const char *dai_name;
+};
+
 struct snd_soc_platform {
 	struct device *dev;
 	const struct snd_soc_platform_driver *driver;
@@ -891,6 +897,10 @@ struct snd_soc_dai_link {
 	const struct device_node *codec_of_node;
 	/* You MUST specify the DAI name within the codec */
 	const char *codec_dai_name;
+
+	struct snd_soc_dai_link_component *codecs;
+	unsigned int num_codecs;
+
 	/*
 	 * You MAY specify the link's platform/PCM/DMA driver, either by
 	 * device name, or by DT/OF node, but not both. Some forms of link
@@ -1089,6 +1099,9 @@ struct snd_soc_pcm_runtime {
 	struct snd_soc_dai *codec_dai;
 	struct snd_soc_dai *cpu_dai;
 
+	struct snd_soc_dai **codec_dais;
+	unsigned int num_codecs;
+
 	struct delayed_work delayed_work;
 #ifdef CONFIG_DEBUG_FS
 	struct dentry *debugfs_dpcm_root;
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index 37a965c..3764150 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -554,7 +554,7 @@ int snd_soc_suspend(struct device *dev)
 {
 	struct snd_soc_card *card = dev_get_drvdata(dev);
 	struct snd_soc_codec *codec;
-	int i;
+	int i, j;
 
 	/* If the initialization of this soc device failed, there is no codec
 	 * associated with it. Just bail out in this case.
@@ -574,14 +574,16 @@ int snd_soc_suspend(struct device *dev)
 
 	/* mute any active DACs */
 	for (i = 0; i < card->num_rtd; i++) {
-		struct snd_soc_dai *dai = card->rtd[i].codec_dai;
-		struct snd_soc_dai_driver *drv = dai->driver;
+		for (j = 0; j < card->rtd[i].num_codecs; j++) {
+			struct snd_soc_dai *dai = card->rtd[i].codec_dais[j];
+			struct snd_soc_dai_driver *drv = dai->driver;
 
-		if (card->rtd[i].dai_link->ignore_suspend)
-			continue;
+			if (card->rtd[i].dai_link->ignore_suspend)
+				continue;
 
-		if (drv->ops->digital_mute && dai->playback_active)
-			drv->ops->digital_mute(dai, 1);
+			if (drv->ops->digital_mute && dai->playback_active)
+				drv->ops->digital_mute(dai, 1);
+		}
 	}
 
 	/* suspend all pcms */
@@ -612,8 +614,12 @@ int snd_soc_suspend(struct device *dev)
 
 	/* close any waiting streams and save state */
 	for (i = 0; i < card->num_rtd; i++) {
+		struct snd_soc_dai **codec_dais = card->rtd[i].codec_dais;
 		flush_delayed_work(&card->rtd[i].delayed_work);
-		card->rtd[i].codec->dapm.suspend_bias_level = card->rtd[i].codec->dapm.bias_level;
+		for (j = 0; j < card->rtd[i].num_codecs; j++) {
+			codec_dais[j]->codec->dapm.suspend_bias_level =
+					codec_dais[j]->codec->dapm.bias_level;
+		}
 	}
 
 	for (i = 0; i < card->num_rtd; i++) {
@@ -697,7 +703,7 @@ static void soc_resume_deferred(struct work_struct *work)
 	struct snd_soc_card *card =
 			container_of(work, struct snd_soc_card, deferred_resume_work);
 	struct snd_soc_codec *codec;
-	int i;
+	int i, j;
 
 	/* our power state is still SNDRV_CTL_POWER_D3hot from suspend time,
 	 * so userspace apps are blocked from touching us
@@ -758,14 +764,17 @@ static void soc_resume_deferred(struct work_struct *work)
 
 	/* unmute any active DACs */
 	for (i = 0; i < card->num_rtd; i++) {
-		struct snd_soc_dai *dai = card->rtd[i].codec_dai;
-		struct snd_soc_dai_driver *drv = dai->driver;
 
-		if (card->rtd[i].dai_link->ignore_suspend)
-			continue;
+		for (j = 0; j < card->rtd[i].num_codecs; j++) {
+			struct snd_soc_dai *dai = card->rtd[i].codec_dais[j];
+			struct snd_soc_dai_driver *drv = dai->driver;
+
+			if (card->rtd[i].dai_link->ignore_suspend)
+				continue;
 
-		if (drv->ops->digital_mute && dai->playback_active)
-			drv->ops->digital_mute(dai, 0);
+			if (drv->ops->digital_mute && dai->playback_active)
+				drv->ops->digital_mute(dai, 0);
+		}
 	}
 
 	for (i = 0; i < card->num_rtd; i++) {
@@ -810,12 +819,19 @@ int snd_soc_resume(struct device *dev)
 
 	/* activate pins from sleep state */
 	for (i = 0; i < card->num_rtd; i++) {
-		struct snd_soc_dai *cpu_dai = card->rtd[i].cpu_dai;
-		struct snd_soc_dai *codec_dai = card->rtd[i].codec_dai;
+		struct snd_soc_pcm_runtime *rtd = &card->rtd[i];
+		struct snd_soc_dai **codec_dais = rtd->codec_dais;
+		struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+		int j;
+
 		if (cpu_dai->active)
 			pinctrl_pm_select_default_state(cpu_dai->dev);
-		if (codec_dai->active)
-			pinctrl_pm_select_default_state(codec_dai->dev);
+
+		for (j = 0; j < rtd->num_codecs; j++) {
+			struct snd_soc_dai *codec_dai = codec_dais[j];
+			if (codec_dai->active)
+				pinctrl_pm_select_default_state(codec_dai->dev);
+		}
 	}
 
 	/* AC97 devices might have other drivers hanging off them so
@@ -847,8 +863,9 @@ EXPORT_SYMBOL_GPL(snd_soc_resume);
 static const struct snd_soc_dai_ops null_dai_ops = {
 };
 
-static struct snd_soc_codec *soc_find_codec(const struct device_node *codec_of_node,
-					    const char *codec_name)
+static struct snd_soc_codec *soc_find_codec(
+					const struct device_node *codec_of_node,
+					const char *codec_name)
 {
 	struct snd_soc_codec *codec;
 
@@ -886,9 +903,12 @@ static int soc_bind_dai_link(struct snd_soc_card *card, int num)
 	struct snd_soc_dai_link *dai_link = &card->dai_link[num];
 	struct snd_soc_pcm_runtime *rtd = &card->rtd[num];
 	struct snd_soc_component *component;
+	struct snd_soc_dai_link_component *codecs = dai_link->codecs;
+	struct snd_soc_dai **codec_dais = rtd->codec_dais;
 	struct snd_soc_platform *platform;
 	struct snd_soc_dai *cpu_dai;
 	const char *platform_name;
+	int i;
 
 	dev_dbg(card->dev, "ASoC: binding %s at idx %d\n", dai_link->name, num);
 
@@ -915,24 +935,30 @@ static int soc_bind_dai_link(struct snd_soc_card *card, int num)
 		return -EPROBE_DEFER;
 	}
 
-	/* Find CODEC from registered list */
-	rtd->codec = soc_find_codec(dai_link->codec_of_node,
-				    dai_link->codec_name);
-	if (!rtd->codec) {
-		dev_err(card->dev, "ASoC: CODEC %s not registered\n",
-			dai_link->codec_name);
-		return -EPROBE_DEFER;
-	}
+	rtd->num_codecs = dai_link->num_codecs;
 
-	/* Find CODEC DAI from registered list */
-	rtd->codec_dai = soc_find_codec_dai(rtd->codec,
-					    dai_link->codec_dai_name);
-	if (!rtd->codec_dai) {
-		dev_err(card->dev, "ASoC: CODEC DAI %s not registered\n",
-			dai_link->codec_dai_name);
-		return -EPROBE_DEFER;
+	/* Find CODEC from registered CODECs */
+	for (i = 0; i < rtd->num_codecs; i++) {
+		struct snd_soc_codec *codec;
+		codec = soc_find_codec(codecs[i].of_node, codecs[i].name);
+		if (!codec) {
+			dev_err(card->dev, "ASoC: CODEC %s not registered\n",
+				codecs[i].name);
+			return -EPROBE_DEFER;
+		}
+
+		codec_dais[i] = soc_find_codec_dai(codec, codecs[i].dai_name);
+		if (!codec_dais[i]) {
+			dev_err(card->dev, "ASoC: CODEC DAI %s not registered\n",
+				codecs[i].dai_name);
+			return -EPROBE_DEFER;
+		}
 	}
 
+	/* Single codec links expect codec and codec_dai in runtime data */
+	rtd->codec_dai = codec_dais[0];
+	rtd->codec = rtd->codec_dai->codec;
+
 	/* if there's no platform we match on the empty platform */
 	platform_name = dai_link->platform_name;
 	if (!platform_name && !dai_link->platform_of_node)
@@ -1023,8 +1049,8 @@ static void soc_remove_codec_dai(struct snd_soc_dai *codec_dai, int order)
 static void soc_remove_link_dais(struct snd_soc_card *card, int num, int order)
 {
 	struct snd_soc_pcm_runtime *rtd = &card->rtd[num];
-	struct snd_soc_dai *codec_dai = rtd->codec_dai, *cpu_dai = rtd->cpu_dai;
-	int err;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+	int i, err;
 
 	/* unregister the rtd device */
 	if (rtd->dev_registered) {
@@ -1035,7 +1061,8 @@ static void soc_remove_link_dais(struct snd_soc_card *card, int num, int order)
 	}
 
 	/* remove the CODEC DAI */
-	soc_remove_codec_dai(codec_dai, order);
+	for (i = 0; i < rtd->num_codecs; i++)
+		soc_remove_codec_dai(rtd->codec_dais[i], order);
 
 	/* remove the cpu_dai */
 	if (cpu_dai && cpu_dai->probed &&
@@ -1058,9 +1085,9 @@ static void soc_remove_link_components(struct snd_soc_card *card, int num,
 {
 	struct snd_soc_pcm_runtime *rtd = &card->rtd[num];
 	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-	struct snd_soc_dai *codec_dai = rtd->codec_dai;
 	struct snd_soc_platform *platform = rtd->platform;
 	struct snd_soc_codec *codec;
+	int i;
 
 	/* remove the platform */
 	if (platform && platform->probed &&
@@ -1069,8 +1096,8 @@ static void soc_remove_link_components(struct snd_soc_card *card, int num,
 	}
 
 	/* remove the CODEC-side CODEC */
-	if (codec_dai) {
-		codec = codec_dai->codec;
+	for (i = 0; i < rtd->num_codecs; i++) {
+		codec = rtd->codec_dais[i]->codec;
 		if (codec && codec->probed &&
 		    codec->driver->remove_order == order)
 			soc_remove_codec(codec);
@@ -1264,16 +1291,19 @@ static void rtd_release(struct device *dev)
 	kfree(dev);
 }
 
-static int soc_aux_dev_init(struct snd_soc_card *card,
-			    struct snd_soc_codec *codec,
-			    int num)
+static int soc_aux_dev_init(struct snd_soc_card *card, int num)
 {
 	struct snd_soc_aux_dev *aux_dev = &card->aux_dev[num];
 	struct snd_soc_pcm_runtime *rtd = &card->rtd_aux[num];
+	struct snd_soc_codec *codec;
 	int ret;
 
 	rtd->card = card;
 
+	codec = soc_find_codec(NULL, aux_dev->codec_name);
+	if (!codec)
+		return -EPROBE_DEFER;
+
 	/* do machine specific initialization */
 	if (aux_dev->init) {
 		ret = aux_dev->init(&codec->dapm);
@@ -1286,16 +1316,19 @@ static int soc_aux_dev_init(struct snd_soc_card *card,
 	return 0;
 }
 
-static int soc_dai_link_init(struct snd_soc_card *card,
-			     struct snd_soc_codec *codec,
-			     int num)
+static int soc_dai_link_init(struct snd_soc_card *card, int num)
 {
 	struct snd_soc_dai_link *dai_link =  &card->dai_link[num];
 	struct snd_soc_pcm_runtime *rtd = &card->rtd[num];
-	int ret;
+	int i, ret;
 
 	rtd->card = card;
 
+	for (i = 0; i < rtd->num_codecs; i++) {
+		/* Make sure all DAPM widgets are instantiated */
+		snd_soc_dapm_new_widgets(rtd->codec_dais[i]->codec->dapm.card);
+	}
+
 	/* do machine specific initialization */
 	if (dai_link->init) {
 		ret = dai_link->init(rtd);
@@ -1303,13 +1336,10 @@ static int soc_dai_link_init(struct snd_soc_card *card,
 			return ret;
 	}
 
-	rtd->codec = codec;
-
 	return 0;
 }
 
 static int soc_post_component_init(struct snd_soc_card *card,
-				   struct snd_soc_codec *codec,
 				   int num, int dailess)
 {
 	struct snd_soc_dai_link *dai_link = NULL;
@@ -1322,12 +1352,12 @@ static int soc_post_component_init(struct snd_soc_card *card,
 		dai_link = &card->dai_link[num];
 		rtd = &card->rtd[num];
 		name = dai_link->name;
-		ret = soc_dai_link_init(card, codec, num);
+		ret = soc_dai_link_init(card, num);
 	} else {
 		aux_dev = &card->aux_dev[num];
 		rtd = &card->rtd_aux[num];
 		name = aux_dev->name;
-		ret = soc_aux_dev_init(card, codec, num);
+		ret = soc_aux_dev_init(card, num);
 	}
 
 	if (ret < 0) {
@@ -1353,7 +1383,7 @@ static int soc_post_component_init(struct snd_soc_card *card,
 	if (ret < 0) {
 		/* calling put_device() here to free the rtd->dev */
 		put_device(rtd->dev);
-		dev_err(card->dev,
+		dev_err(rtd->dev,
 			"ASoC: failed to register runtime device: %d\n", ret);
 		return ret;
 	}
@@ -1362,13 +1392,13 @@ static int soc_post_component_init(struct snd_soc_card *card,
 	/* add DAPM sysfs entries for this codec */
 	ret = snd_soc_dapm_sys_add(rtd->dev);
 	if (ret < 0)
-		dev_err(codec->dev,
+		dev_err(rtd->dev,
 			"ASoC: failed to add codec dapm sysfs entries: %d\n", ret);
 
 	/* add codec sysfs entries */
 	ret = device_create_file(rtd->dev, &dev_attr_codec_reg);
 	if (ret < 0)
-		dev_err(codec->dev,
+		dev_err(rtd->dev,
 			"ASoC: failed to add codec sysfs files: %d\n", ret);
 
 #ifdef CONFIG_DEBUG_FS
@@ -1390,9 +1420,8 @@ static int soc_probe_link_components(struct snd_soc_card *card, int num,
 {
 	struct snd_soc_pcm_runtime *rtd = &card->rtd[num];
 	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-	struct snd_soc_dai *codec_dai = rtd->codec_dai;
 	struct snd_soc_platform *platform = rtd->platform;
-	int ret;
+	int i, ret;
 
 	/* probe the CPU-side component, if it is a CODEC */
 	if (cpu_dai->codec &&
@@ -1403,12 +1432,14 @@ static int soc_probe_link_components(struct snd_soc_card *card, int num,
 			return ret;
 	}
 
-	/* probe the CODEC-side component */
-	if (!codec_dai->codec->probed &&
-	    codec_dai->codec->driver->probe_order == order) {
-		ret = soc_probe_codec(card, codec_dai->codec);
-		if (ret < 0)
-			return ret;
+	/* probe the CODEC-side components */
+	for (i = 0; i < rtd->num_codecs; i++) {
+		if (!rtd->codec_dais[i]->codec->probed &&
+		    rtd->codec_dais[i]->codec->driver->probe_order == order) {
+			ret = soc_probe_codec(card, rtd->codec_dais[i]->codec);
+			if (ret < 0)
+				return ret;
+		}
 	}
 
 	/* probe the platform */
@@ -1487,19 +1518,18 @@ static int soc_probe_link_dais(struct snd_soc_card *card, int num, int order)
 {
 	struct snd_soc_dai_link *dai_link = &card->dai_link[num];
 	struct snd_soc_pcm_runtime *rtd = &card->rtd[num];
-	struct snd_soc_codec *codec = rtd->codec;
 	struct snd_soc_platform *platform = rtd->platform;
-	struct snd_soc_dai *codec_dai = rtd->codec_dai;
 	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-	int ret;
+	int i, ret;
 
 	dev_dbg(card->dev, "ASoC: probe %s dai link %d late %d\n",
 			card->name, num, order);
 
 	/* config components */
 	cpu_dai->platform = platform;
-	codec_dai->card = card;
 	cpu_dai->card = card;
+	for (i = 0; i < rtd->num_codecs; i++)
+		rtd->codec_dais[i]->card = card;
 
 	/* set default power off timeout */
 	rtd->pmdown_time = pmdown_time;
@@ -1526,15 +1556,17 @@ static int soc_probe_link_dais(struct snd_soc_card *card, int num, int order)
 	}
 
 	/* probe the CODEC DAI */
-	ret = soc_probe_codec_dai(card, codec_dai, order);
-	if (ret)
-		return ret;
+	for (i = 0; i < rtd->num_codecs; i++) {
+		ret = soc_probe_codec_dai(card, rtd->codec_dais[i], order);
+		if (ret)
+			return ret;
+	}
 
 	/* complete DAI probe during last probe */
 	if (order != SND_SOC_COMP_ORDER_LAST)
 		return 0;
 
-	ret = soc_post_component_init(card, codec, num, 0);
+	ret = soc_post_component_init(card, num, 0);
 	if (ret)
 		return ret;
 
@@ -1573,8 +1605,11 @@ static int soc_probe_link_dais(struct snd_soc_card *card, int num, int order)
 	}
 
 	/* add platform data for AC97 devices */
-	if (rtd->codec_dai->driver->ac97_control)
-		snd_ac97_dev_add_pdata(codec->ac97, rtd->cpu_dai->ac97_pdata);
+	for (i = 0; i < rtd->num_codecs; i++) {
+		if (rtd->codec_dais[i]->driver->ac97_control)
+			snd_ac97_dev_add_pdata(rtd->codec_dais[i]->codec->ac97,
+					       rtd->cpu_dai->ac97_pdata);
+	}
 
 	return 0;
 }
@@ -1612,11 +1647,6 @@ static int soc_register_ac97_codec(struct snd_soc_codec *codec,
 	return 0;
 }
 
-static int soc_register_ac97_dai_link(struct snd_soc_pcm_runtime *rtd)
-{
-	return soc_register_ac97_codec(rtd->codec, rtd->codec_dai);
-}
-
 static void soc_unregister_ac97_codec(struct snd_soc_codec *codec)
 {
 	if (codec->ac97_registered) {
@@ -1625,9 +1655,30 @@ static void soc_unregister_ac97_codec(struct snd_soc_codec *codec)
 	}
 }
 
+static int soc_register_ac97_dai_link(struct snd_soc_pcm_runtime *rtd)
+{
+	int i, ret;
+
+	for (i = 0; i < rtd->num_codecs; i++) {
+		struct snd_soc_dai *codec_dai = rtd->codec_dais[i];
+
+		ret = soc_register_ac97_codec(codec_dai->codec, codec_dai);
+		if (ret) {
+			while (--i >= 0)
+				soc_unregister_ac97_codec(codec_dai->codec);
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
 static void soc_unregister_ac97_dai_link(struct snd_soc_pcm_runtime *rtd)
 {
-	soc_unregister_ac97_codec(rtd->codec);
+	int i;
+
+	for (i = 0; i < rtd->num_codecs; i++)
+		soc_unregister_ac97_codec(rtd->codec_dais[i]->codec);
 }
 #endif
 
@@ -1691,7 +1742,7 @@ static int soc_probe_aux_dev(struct snd_soc_card *card, int num)
 	if (ret < 0)
 		return ret;
 
-	ret = soc_post_component_init(card, codec, num, 1);
+	ret = soc_post_component_init(card, num, 1);
 
 	return ret;
 }
@@ -1845,16 +1896,23 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card)
 					card->num_dapm_routes);
 
 	for (i = 0; i < card->num_links; i++) {
+		struct snd_soc_pcm_runtime *rtd = &card->rtd[i];
 		dai_link = &card->dai_link[i];
 		dai_fmt = dai_link->dai_fmt;
 
 		if (dai_fmt) {
-			ret = snd_soc_dai_set_fmt(card->rtd[i].codec_dai,
-						  dai_fmt);
-			if (ret != 0 && ret != -ENOTSUPP)
-				dev_warn(card->rtd[i].codec_dai->dev,
-					 "ASoC: Failed to set DAI format: %d\n",
-					 ret);
+			struct snd_soc_dai **codec_dais = rtd->codec_dais;
+			int j;
+
+			for (j = 0; j < rtd->num_codecs; j++) {
+				struct snd_soc_dai *codec_dai = codec_dais[j];
+
+				ret = snd_soc_dai_set_fmt(codec_dai, dai_fmt);
+				if (ret != 0 && ret != -ENOTSUPP)
+					dev_warn(codec_dai->dev,
+						 "ASoC: Failed to set DAI format: %d\n",
+						 ret);
+			}
 		}
 
 		/* If this is a regular CPU link there will be a platform */
@@ -2053,10 +2111,15 @@ int snd_soc_poweroff(struct device *dev)
 
 	/* deactivate pins to sleep state */
 	for (i = 0; i < card->num_rtd; i++) {
-		struct snd_soc_dai *cpu_dai = card->rtd[i].cpu_dai;
-		struct snd_soc_dai *codec_dai = card->rtd[i].codec_dai;
-		pinctrl_pm_select_sleep_state(codec_dai->dev);
+		struct snd_soc_pcm_runtime *rtd = &card->rtd[i];
+		struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+		int j;
+
 		pinctrl_pm_select_sleep_state(cpu_dai->dev);
+		for (j = 0; j < rtd->num_codecs; j++) {
+			struct snd_soc_dai *codec_dai = rtd->codec_dais[j];
+			pinctrl_pm_select_sleep_state(codec_dai->dev);
+		}
 	}
 
 	return 0;
@@ -3636,6 +3699,9 @@ int snd_soc_dai_set_tdm_slot(struct snd_soc_dai *dai,
 	else
 		snd_soc_xlate_tdm_slot_mask(slots, &tx_mask, &rx_mask);
 
+	dai->tx_mask = tx_mask;
+	dai->rx_mask = rx_mask;
+
 	if (dai->driver && dai->driver->ops->set_tdm_slot)
 		return dai->driver->ops->set_tdm_slot(dai, tx_mask, rx_mask,
 				slots, slot_width);
@@ -3708,6 +3774,33 @@ int snd_soc_dai_digital_mute(struct snd_soc_dai *dai, int mute,
 }
 EXPORT_SYMBOL_GPL(snd_soc_dai_digital_mute);
 
+static int snd_soc_init_multicodec(struct snd_soc_card *card,
+				   struct snd_soc_dai_link *dai_link)
+{
+	/* Legacy codec/codec_dai link is a single entry in multicodec */
+	if (dai_link->codec_name || dai_link->codec_of_node ||
+	    dai_link->codec_dai_name) {
+		dai_link->num_codecs = 1;
+
+		dai_link->codecs = devm_kzalloc(card->dev,
+				sizeof(struct snd_soc_dai_link_component),
+				GFP_KERNEL);
+		if (!dai_link->codecs)
+			return -ENOMEM;
+
+		dai_link->codecs[0].name = dai_link->codec_name;
+		dai_link->codecs[0].of_node = dai_link->codec_of_node;
+		dai_link->codecs[0].dai_name = dai_link->codec_dai_name;
+	}
+
+	if (!dai_link->codecs) {
+		dev_err(card->dev, "ASoC: DAI link has no CODECs\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
 /**
  * snd_soc_register_card - Register a card with the ASoC core
  *
@@ -3716,7 +3809,7 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_digital_mute);
  */
 int snd_soc_register_card(struct snd_soc_card *card)
 {
-	int i, ret;
+	int i, j, ret;
 
 	if (!card->name || !card->dev)
 		return -EINVAL;
@@ -3724,22 +3817,29 @@ int snd_soc_register_card(struct snd_soc_card *card)
 	for (i = 0; i < card->num_links; i++) {
 		struct snd_soc_dai_link *link = &card->dai_link[i];
 
-		/*
-		 * Codec must be specified by 1 of name or OF node,
-		 * not both or neither.
-		 */
-		if (!!link->codec_name == !!link->codec_of_node) {
-			dev_err(card->dev,
-				"ASoC: Neither/both codec name/of_node are set for %s\n",
-				link->name);
-			return -EINVAL;
+		ret = snd_soc_init_multicodec(card, link);
+		if (ret) {
+			dev_err(card->dev, "ASoC: failed to init multicodec\n");
+			return ret;
 		}
-		/* Codec DAI name must be specified */
-		if (!link->codec_dai_name) {
-			dev_err(card->dev,
-				"ASoC: codec_dai_name not set for %s\n",
-				link->name);
-			return -EINVAL;
+
+		for (j = 0; j < link->num_codecs; j++) {
+			/*
+			 * Codec must be specified by 1 of name or OF node,
+			 * not both or neither.
+			 */
+			if (!!link->codecs[j].name ==
+			    !!link->codecs[j].of_node) {
+				dev_err(card->dev, "ASoC: Neither/both codec name/of_node are set for %s\n",
+					link->name);
+				return -EINVAL;
+			}
+			/* Codec DAI name must be specified */
+			if (!link->codecs[j].dai_name) {
+				dev_err(card->dev, "ASoC: codec_dai_name not set for %s\n",
+					link->name);
+				return -EINVAL;
+			}
 		}
 
 		/*
@@ -3792,8 +3892,15 @@ int snd_soc_register_card(struct snd_soc_card *card)
 	card->num_rtd = 0;
 	card->rtd_aux = &card->rtd[card->num_links];
 
-	for (i = 0; i < card->num_links; i++)
+	for (i = 0; i < card->num_links; i++) {
 		card->rtd[i].dai_link = &card->dai_link[i];
+		card->rtd[i].codec_dais = devm_kzalloc(card->dev,
+					sizeof(struct snd_soc_dai *) *
+					(card->rtd[i].dai_link->num_codecs),
+					GFP_KERNEL);
+		if (card->rtd->codec_dais == NULL)
+			return -ENOMEM;
+	}
 
 	INIT_LIST_HEAD(&card->dapm_dirty);
 	card->instantiated = 0;
@@ -3806,10 +3913,16 @@ int snd_soc_register_card(struct snd_soc_card *card)
 
 	/* deactivate pins to sleep state */
 	for (i = 0; i < card->num_rtd; i++) {
-		struct snd_soc_dai *cpu_dai = card->rtd[i].cpu_dai;
-		struct snd_soc_dai *codec_dai = card->rtd[i].codec_dai;
-		if (!codec_dai->active)
-			pinctrl_pm_select_sleep_state(codec_dai->dev);
+		struct snd_soc_pcm_runtime *rtd = &card->rtd[i];
+		struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+		int j;
+
+		for (j = 0; j < rtd->num_codecs; j++) {
+			struct snd_soc_dai *codec_dai = rtd->codec_dais[j];
+			if (!codec_dai->active)
+				pinctrl_pm_select_sleep_state(codec_dai->dev);
+		}
+
 		if (!cpu_dai->active)
 			pinctrl_pm_select_sleep_state(cpu_dai->dev);
 	}
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 43+ messages in thread

* [PATCH v4 4/8] ASoC: pcm: Add support for DAI multicodec
  2014-07-01  7:47 [PATCH v4 0/8] ASoC: core: Add support for DAI multicodec Benoit Cousson
                   ` (2 preceding siblings ...)
  2014-07-01  7:47 ` [PATCH v4 3/8] ASoC: core: Add initial support for DAI multicodec Benoit Cousson
@ 2014-07-01  7:47 ` Benoit Cousson
  2014-07-01 13:32   ` Lars-Peter Clausen
  2014-07-01  7:47 ` [PATCH v4 5/8] ASoC: dapm: " Benoit Cousson
                   ` (3 subsequent siblings)
  7 siblings, 1 reply; 43+ messages in thread
From: Benoit Cousson @ 2014-07-01  7:47 UTC (permalink / raw)
  To: broonie, lgirdwood, lars
  Cc: Fabien Parent, misael.lopez, alsa-devel, Benoit Cousson

Add multicodec support in soc-pcm.c

Signed-off-by: Benoit Cousson <bcousson@baylibre.com>
Signed-off-by: Misael Lopez Cruz <misael.lopez@ti.com>
Signed-off-by: Fabien Parent <fparent@baylibre.com>
---
 sound/soc/soc-pcm.c | 515 ++++++++++++++++++++++++++++++++++++----------------
 1 file changed, 354 insertions(+), 161 deletions(-)

diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c
index ab0712e..981b99c 100644
--- a/sound/soc/soc-pcm.c
+++ b/sound/soc/soc-pcm.c
@@ -47,22 +47,26 @@
 void snd_soc_runtime_activate(struct snd_soc_pcm_runtime *rtd, int stream)
 {
 	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-	struct snd_soc_dai *codec_dai = rtd->codec_dai;
+	int i;
 
 	lockdep_assert_held(&rtd->pcm_mutex);
 
 	if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
 		cpu_dai->playback_active++;
-		codec_dai->playback_active++;
+		for (i = 0; i < rtd->num_codecs; i++)
+			rtd->codec_dais[i]->playback_active++;
 	} else {
 		cpu_dai->capture_active++;
-		codec_dai->capture_active++;
+		for (i = 0; i < rtd->num_codecs; i++)
+			rtd->codec_dais[i]->capture_active++;
 	}
 
 	cpu_dai->active++;
-	codec_dai->active++;
 	cpu_dai->component->active++;
-	codec_dai->component->active++;
+	for (i = 0; i < rtd->num_codecs; i++) {
+		rtd->codec_dais[i]->active++;
+		rtd->codec_dais[i]->component->active++;
+	}
 }
 
 /**
@@ -78,22 +82,26 @@ void snd_soc_runtime_activate(struct snd_soc_pcm_runtime *rtd, int stream)
 void snd_soc_runtime_deactivate(struct snd_soc_pcm_runtime *rtd, int stream)
 {
 	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-	struct snd_soc_dai *codec_dai = rtd->codec_dai;
+	int i;
 
 	lockdep_assert_held(&rtd->pcm_mutex);
 
 	if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
 		cpu_dai->playback_active--;
-		codec_dai->playback_active--;
+		for (i = 0; i < rtd->num_codecs; i++)
+			rtd->codec_dais[i]->playback_active--;
 	} else {
 		cpu_dai->capture_active--;
-		codec_dai->capture_active--;
+		for (i = 0; i < rtd->num_codecs; i++)
+			rtd->codec_dais[i]->capture_active--;
 	}
 
 	cpu_dai->active--;
-	codec_dai->active--;
 	cpu_dai->component->active--;
-	codec_dai->component->active--;
+	for (i = 0; i < rtd->num_codecs; i++) {
+		rtd->codec_dais[i]->component->active--;
+		rtd->codec_dais[i]->active--;
+	}
 }
 
 /**
@@ -107,11 +115,15 @@ void snd_soc_runtime_deactivate(struct snd_soc_pcm_runtime *rtd, int stream)
  */
 bool snd_soc_runtime_ignore_pmdown_time(struct snd_soc_pcm_runtime *rtd)
 {
+	int i, ignore = 0;
+
 	if (!rtd->pmdown_time || rtd->dai_link->ignore_pmdown_time)
 		return true;
 
-	return rtd->cpu_dai->component->ignore_pmdown_time &&
-			rtd->codec_dai->component->ignore_pmdown_time;
+	for (i = 0; (i < rtd->num_codecs) && !ignore; i++)
+		ignore &= rtd->codec_dais[i]->component->ignore_pmdown_time;
+
+	return rtd->cpu_dai->component->ignore_pmdown_time && ignore;
 }
 
 /**
@@ -222,8 +234,7 @@ static int soc_pcm_params_symmetry(struct snd_pcm_substream *substream,
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-	struct snd_soc_dai *codec_dai = rtd->codec_dai;
-	unsigned int rate, channels, sample_bits, symmetry;
+	unsigned int rate, channels, sample_bits, symmetry, i;
 
 	rate = params_rate(params);
 	channels = params_channels(params);
@@ -231,8 +242,11 @@ static int soc_pcm_params_symmetry(struct snd_pcm_substream *substream,
 
 	/* reject unmatched parameters when applying symmetry */
 	symmetry = cpu_dai->driver->symmetric_rates ||
-		codec_dai->driver->symmetric_rates ||
 		rtd->dai_link->symmetric_rates;
+
+	for (i = 0; i < rtd->num_codecs; i++)
+		symmetry |= rtd->codec_dais[i]->driver->symmetric_rates;
+
 	if (symmetry && cpu_dai->rate && cpu_dai->rate != rate) {
 		dev_err(rtd->dev, "ASoC: unmatched rate symmetry: %d - %d\n",
 				cpu_dai->rate, rate);
@@ -240,8 +254,11 @@ static int soc_pcm_params_symmetry(struct snd_pcm_substream *substream,
 	}
 
 	symmetry = cpu_dai->driver->symmetric_channels ||
-		codec_dai->driver->symmetric_channels ||
 		rtd->dai_link->symmetric_channels;
+
+	for (i = 0; i < rtd->num_codecs; i++)
+		symmetry |= rtd->codec_dais[i]->driver->symmetric_channels;
+
 	if (symmetry && cpu_dai->channels && cpu_dai->channels != channels) {
 		dev_err(rtd->dev, "ASoC: unmatched channel symmetry: %d - %d\n",
 				cpu_dai->channels, channels);
@@ -249,8 +266,11 @@ static int soc_pcm_params_symmetry(struct snd_pcm_substream *substream,
 	}
 
 	symmetry = cpu_dai->driver->symmetric_samplebits ||
-		codec_dai->driver->symmetric_samplebits ||
 		rtd->dai_link->symmetric_samplebits;
+
+	for (i = 0; i < rtd->num_codecs; i++)
+		symmetry |= rtd->codec_dais[i]->driver->symmetric_samplebits;
+
 	if (symmetry && cpu_dai->sample_bits && cpu_dai->sample_bits != sample_bits) {
 		dev_err(rtd->dev, "ASoC: unmatched sample bits symmetry: %d - %d\n",
 				cpu_dai->sample_bits, sample_bits);
@@ -264,15 +284,20 @@ static bool soc_pcm_has_symmetry(struct snd_pcm_substream *substream)
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 	struct snd_soc_dai_driver *cpu_driver = rtd->cpu_dai->driver;
-	struct snd_soc_dai_driver *codec_driver = rtd->codec_dai->driver;
 	struct snd_soc_dai_link *link = rtd->dai_link;
+	unsigned int symmetry, i;
+
+	symmetry = cpu_driver->symmetric_rates || link->symmetric_rates ||
+		cpu_driver->symmetric_channels || link->symmetric_channels ||
+		cpu_driver->symmetric_samplebits || link->symmetric_samplebits;
 
-	return cpu_driver->symmetric_rates || codec_driver->symmetric_rates ||
-		link->symmetric_rates || cpu_driver->symmetric_channels ||
-		codec_driver->symmetric_channels || link->symmetric_channels ||
-		cpu_driver->symmetric_samplebits ||
-		codec_driver->symmetric_samplebits ||
-		link->symmetric_samplebits;
+	for (i = 0; i < rtd->num_codecs; i++)
+		symmetry = symmetry ||
+			rtd->codec_dais[i]->driver->symmetric_rates ||
+			rtd->codec_dais[i]->driver->symmetric_channels ||
+			rtd->codec_dais[i]->driver->symmetric_samplebits;
+
+	return symmetry;
 }
 
 /*
@@ -309,14 +334,21 @@ static void soc_pcm_apply_msb(struct snd_pcm_substream *substream)
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-	struct snd_soc_dai *codec_dai = rtd->codec_dai;
+	struct snd_soc_dai *codec_dai;
+	int i;
 	unsigned int bits = 0, cpu_bits;
 
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-		bits = codec_dai->driver->playback.sig_bits;
+		for (i = 0; i < rtd->num_codecs; i++) {
+			codec_dai = rtd->codec_dais[i];
+			bits = max(codec_dai->driver->playback.sig_bits, bits);
+		}
 		cpu_bits = cpu_dai->driver->playback.sig_bits;
 	} else {
-		bits = codec_dai->driver->capture.sig_bits;
+		for (i = 0; i < rtd->num_codecs; i++) {
+			codec_dai = rtd->codec_dais[i];
+			bits = max(codec_dai->driver->capture.sig_bits, bits);
+		}
 		cpu_bits = cpu_dai->driver->capture.sig_bits;
 	}
 
@@ -324,32 +356,65 @@ static void soc_pcm_apply_msb(struct snd_pcm_substream *substream)
 	soc_pcm_set_msb(substream, cpu_dai, cpu_bits);
 }
 
-static void soc_pcm_init_runtime_hw(struct snd_pcm_runtime *runtime,
-	struct snd_soc_pcm_stream *codec_stream,
-	struct snd_soc_pcm_stream *cpu_stream)
+static void soc_pcm_init_runtime_hw(struct snd_pcm_substream *substream)
 {
+	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct snd_pcm_hardware *hw = &runtime->hw;
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai_driver *cpu_dai_drv = rtd->cpu_dai->driver;
+	struct snd_soc_dai_driver *codec_dai_drv;
+	struct snd_soc_pcm_stream *codec_stream;
+	struct snd_soc_pcm_stream *cpu_stream;
+	unsigned int chan_min = 0, chan_max = UINT_MAX;
+	unsigned int rate_min = 0, rate_max = UINT_MAX;
+	unsigned int rates = UINT_MAX;
+	u64 formats = ULLONG_MAX;
+	int i;
 
-	hw->channels_min = max(codec_stream->channels_min,
-		cpu_stream->channels_min);
-	hw->channels_max = min(codec_stream->channels_max,
-		cpu_stream->channels_max);
-	if (hw->formats)
-		hw->formats &= codec_stream->formats & cpu_stream->formats;
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		cpu_stream = &cpu_dai_drv->playback;
 	else
-		hw->formats = codec_stream->formats & cpu_stream->formats;
-	hw->rates = snd_pcm_rate_mask_intersect(codec_stream->rates,
-		cpu_stream->rates);
+		cpu_stream = &cpu_dai_drv->capture;
 
-	hw->rate_min = 0;
-	hw->rate_max = UINT_MAX;
+	/* first calculate min/max only for CODECs in the DAI link */
+	for (i = 0; i < rtd->num_codecs; i++) {
+		codec_dai_drv = rtd->codec_dais[i]->driver;
+		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+			codec_stream = &codec_dai_drv->playback;
+		else
+			codec_stream = &codec_dai_drv->capture;
+		chan_min = max(chan_min, codec_stream->channels_min);
+		chan_max = min(chan_max, codec_stream->channels_max);
+		rate_min = max(rate_min, codec_stream->rate_min);
+		rate_max = min_not_zero(rate_max, codec_stream->rate_max);
+		formats &= codec_stream->formats;
+		rates = snd_pcm_rate_mask_intersect(codec_stream->rates, rates);
+	}
+
+	/*
+	 * chan min/max cannot be enforced if there are multiple CODEC DAIs
+	 * connected to a single CPU DAI, use CPU DAI's directly and let
+	 * channel allocation be fixed up later
+	 */
+	if (rtd->num_codecs > 1) {
+		chan_min = cpu_stream->channels_min;
+		chan_max = cpu_stream->channels_max;
+	}
+
+	hw->channels_min = max(chan_min, cpu_stream->channels_min);
+	hw->channels_max = min(chan_max, cpu_stream->channels_max);
+	if (hw->formats)
+		hw->formats &= formats & cpu_stream->formats;
+	else
+		hw->formats = formats & cpu_stream->formats;
+	hw->rates = snd_pcm_rate_mask_intersect(rates, cpu_stream->rates);
 
 	snd_pcm_limit_hw_rates(runtime);
 
 	hw->rate_min = max(hw->rate_min, cpu_stream->rate_min);
-	hw->rate_min = max(hw->rate_min, codec_stream->rate_min);
+	hw->rate_min = max(hw->rate_min, rate_min);
 	hw->rate_max = min_not_zero(hw->rate_max, cpu_stream->rate_max);
-	hw->rate_max = min_not_zero(hw->rate_max, codec_stream->rate_max);
+	hw->rate_max = min_not_zero(hw->rate_max, rate_max);
 }
 
 /*
@@ -363,15 +428,16 @@ static int soc_pcm_open(struct snd_pcm_substream *substream)
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct snd_soc_platform *platform = rtd->platform;
 	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-	struct snd_soc_dai *codec_dai = rtd->codec_dai;
-	struct snd_soc_dai_driver *cpu_dai_drv = cpu_dai->driver;
-	struct snd_soc_dai_driver *codec_dai_drv = codec_dai->driver;
-	int ret = 0;
+	struct snd_soc_dai *codec_dai;
+	const char *codec_dai_name = "multicodec";
+	int i, ret = 0;
 
 	pinctrl_pm_select_default_state(cpu_dai->dev);
-	pinctrl_pm_select_default_state(codec_dai->dev);
+	for (i = 0; i < rtd->num_codecs; i++)
+		pinctrl_pm_select_default_state(rtd->codec_dais[i]->dev);
 	pm_runtime_get_sync(cpu_dai->dev);
-	pm_runtime_get_sync(codec_dai->dev);
+	for (i = 0; i < rtd->num_codecs; i++)
+		pm_runtime_get_sync(rtd->codec_dais[i]->dev);
 	pm_runtime_get_sync(platform->dev);
 
 	mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
@@ -395,13 +461,23 @@ static int soc_pcm_open(struct snd_pcm_substream *substream)
 		}
 	}
 
-	if (codec_dai->driver->ops && codec_dai->driver->ops->startup) {
-		ret = codec_dai->driver->ops->startup(substream, codec_dai);
-		if (ret < 0) {
-			dev_err(codec_dai->dev, "ASoC: can't open codec"
-				" %s: %d\n", codec_dai->name, ret);
-			goto codec_dai_err;
+	for (i = 0; i < rtd->num_codecs; i++) {
+		codec_dai = rtd->codec_dais[i];
+		if (codec_dai->driver->ops && codec_dai->driver->ops->startup) {
+			ret = codec_dai->driver->ops->startup(substream,
+							      codec_dai);
+			if (ret < 0) {
+				dev_err(codec_dai->dev,
+					"ASoC: can't open codec %s: %d\n",
+					codec_dai->name, ret);
+				goto codec_dai_err;
+			}
 		}
+
+		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+			codec_dai->tx_mask = 0;
+		else
+			codec_dai->rx_mask = 0;
 	}
 
 	if (rtd->dai_link->ops && rtd->dai_link->ops->startup) {
@@ -418,13 +494,10 @@ static int soc_pcm_open(struct snd_pcm_substream *substream)
 		goto dynamic;
 
 	/* Check that the codec and cpu DAIs are compatible */
-	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-		soc_pcm_init_runtime_hw(runtime, &codec_dai_drv->playback,
-			&cpu_dai_drv->playback);
-	} else {
-		soc_pcm_init_runtime_hw(runtime, &codec_dai_drv->capture,
-			&cpu_dai_drv->capture);
-	}
+	soc_pcm_init_runtime_hw(substream);
+
+	if (rtd->num_codecs == 1)
+		codec_dai_name = rtd->codec_dai->name;
 
 	if (soc_pcm_has_symmetry(substream))
 		runtime->hw.info |= SNDRV_PCM_INFO_JOINT_DUPLEX;
@@ -432,18 +505,18 @@ static int soc_pcm_open(struct snd_pcm_substream *substream)
 	ret = -EINVAL;
 	if (!runtime->hw.rates) {
 		printk(KERN_ERR "ASoC: %s <-> %s No matching rates\n",
-			codec_dai->name, cpu_dai->name);
+			codec_dai_name, cpu_dai->name);
 		goto config_err;
 	}
 	if (!runtime->hw.formats) {
 		printk(KERN_ERR "ASoC: %s <-> %s No matching formats\n",
-			codec_dai->name, cpu_dai->name);
+			codec_dai_name, cpu_dai->name);
 		goto config_err;
 	}
 	if (!runtime->hw.channels_min || !runtime->hw.channels_max ||
 	    runtime->hw.channels_min > runtime->hw.channels_max) {
 		printk(KERN_ERR "ASoC: %s <-> %s No matching channels\n",
-				codec_dai->name, cpu_dai->name);
+				codec_dai_name, cpu_dai->name);
 		goto config_err;
 	}
 
@@ -456,14 +529,17 @@ static int soc_pcm_open(struct snd_pcm_substream *substream)
 			goto config_err;
 	}
 
-	if (codec_dai->active) {
-		ret = soc_pcm_apply_symmetry(substream, codec_dai);
-		if (ret != 0)
-			goto config_err;
+	for (i = 0; i < rtd->num_codecs; i++) {
+		if (rtd->codec_dais[i]->active) {
+			ret = soc_pcm_apply_symmetry(substream,
+						     rtd->codec_dais[i]);
+			if (ret != 0)
+				goto config_err;
+		}
 	}
 
 	pr_debug("ASoC: %s <-> %s info:\n",
-			codec_dai->name, cpu_dai->name);
+			codec_dai_name, cpu_dai->name);
 	pr_debug("ASoC: rate mask 0x%x\n", runtime->hw.rates);
 	pr_debug("ASoC: min ch %d max ch %d\n", runtime->hw.channels_min,
 		 runtime->hw.channels_max);
@@ -482,10 +558,15 @@ config_err:
 		rtd->dai_link->ops->shutdown(substream);
 
 machine_err:
-	if (codec_dai->driver->ops->shutdown)
-		codec_dai->driver->ops->shutdown(substream, codec_dai);
+	i = rtd->num_codecs;
 
 codec_dai_err:
+	while (--i >= 0) {
+		codec_dai = rtd->codec_dais[i];
+		if (codec_dai->driver->ops->shutdown)
+			codec_dai->driver->ops->shutdown(substream, codec_dai);
+	}
+
 	if (platform->driver->ops && platform->driver->ops->close)
 		platform->driver->ops->close(substream);
 
@@ -496,10 +577,13 @@ out:
 	mutex_unlock(&rtd->pcm_mutex);
 
 	pm_runtime_put(platform->dev);
-	pm_runtime_put(codec_dai->dev);
+	for (i = 0; i < rtd->num_codecs; i++)
+		pm_runtime_put(rtd->codec_dais[i]->dev);
 	pm_runtime_put(cpu_dai->dev);
-	if (!codec_dai->active)
-		pinctrl_pm_select_sleep_state(codec_dai->dev);
+	for (i = 0; i < rtd->num_codecs; i++) {
+		if (!rtd->codec_dais[i]->active)
+			pinctrl_pm_select_sleep_state(rtd->codec_dais[i]->dev);
+	}
 	if (!cpu_dai->active)
 		pinctrl_pm_select_sleep_state(cpu_dai->dev);
 
@@ -515,7 +599,7 @@ static void close_delayed_work(struct work_struct *work)
 {
 	struct snd_soc_pcm_runtime *rtd =
 			container_of(work, struct snd_soc_pcm_runtime, delayed_work.work);
-	struct snd_soc_dai *codec_dai = rtd->codec_dai;
+	struct snd_soc_dai *codec_dai = rtd->codec_dais[0];
 
 	mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
 
@@ -544,7 +628,8 @@ static int soc_pcm_close(struct snd_pcm_substream *substream)
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 	struct snd_soc_platform *platform = rtd->platform;
 	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-	struct snd_soc_dai *codec_dai = rtd->codec_dai;
+	struct snd_soc_dai *codec_dai;
+	int i;
 
 	mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
 
@@ -554,14 +639,20 @@ static int soc_pcm_close(struct snd_pcm_substream *substream)
 	if (!cpu_dai->active)
 		cpu_dai->rate = 0;
 
-	if (!codec_dai->active)
-		codec_dai->rate = 0;
+	for (i = 0; i < rtd->num_codecs; i++) {
+		codec_dai = rtd->codec_dais[i];
+		if (!codec_dai->active)
+			codec_dai->rate = 0;
+	}
 
 	if (cpu_dai->driver->ops->shutdown)
 		cpu_dai->driver->ops->shutdown(substream, cpu_dai);
 
-	if (codec_dai->driver->ops->shutdown)
-		codec_dai->driver->ops->shutdown(substream, codec_dai);
+	for (i = 0; i < rtd->num_codecs; i++) {
+		codec_dai = rtd->codec_dais[i];
+		if (codec_dai->driver->ops->shutdown)
+			codec_dai->driver->ops->shutdown(substream, codec_dai);
+	}
 
 	if (rtd->dai_link->ops && rtd->dai_link->ops->shutdown)
 		rtd->dai_link->ops->shutdown(substream);
@@ -591,10 +682,13 @@ static int soc_pcm_close(struct snd_pcm_substream *substream)
 	mutex_unlock(&rtd->pcm_mutex);
 
 	pm_runtime_put(platform->dev);
-	pm_runtime_put(codec_dai->dev);
+	for (i = 0; i < rtd->num_codecs; i++)
+		pm_runtime_put(rtd->codec_dais[i]->dev);
 	pm_runtime_put(cpu_dai->dev);
-	if (!codec_dai->active)
-		pinctrl_pm_select_sleep_state(codec_dai->dev);
+	for (i = 0; i < rtd->num_codecs; i++) {
+		if (!rtd->codec_dais[i]->active)
+			pinctrl_pm_select_sleep_state(rtd->codec_dais[i]->dev);
+	}
 	if (!cpu_dai->active)
 		pinctrl_pm_select_sleep_state(cpu_dai->dev);
 
@@ -611,8 +705,8 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream)
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 	struct snd_soc_platform *platform = rtd->platform;
 	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-	struct snd_soc_dai *codec_dai = rtd->codec_dai;
-	int ret = 0;
+	struct snd_soc_dai *codec_dai;
+	int i, ret = 0;
 
 	mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
 
@@ -634,12 +728,16 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream)
 		}
 	}
 
-	if (codec_dai->driver->ops && codec_dai->driver->ops->prepare) {
-		ret = codec_dai->driver->ops->prepare(substream, codec_dai);
-		if (ret < 0) {
-			dev_err(codec_dai->dev, "ASoC: DAI prepare error: %d\n",
-				ret);
-			goto out;
+	for (i = 0; i < rtd->num_codecs; i++) {
+		codec_dai = rtd->codec_dais[i];
+		if (codec_dai->driver->ops && codec_dai->driver->ops->prepare) {
+			ret = codec_dai->driver->ops->prepare(substream,
+							      codec_dai);
+			if (ret < 0) {
+				dev_err(codec_dai->dev,
+					"ASoC: DAI prepare error: %d\n", ret);
+				goto out;
+			}
 		}
 	}
 
@@ -662,13 +760,26 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream)
 	snd_soc_dapm_stream_event(rtd, substream->stream,
 			SND_SOC_DAPM_STREAM_START);
 
-	snd_soc_dai_digital_mute(codec_dai, 0, substream->stream);
+	for (i = 0; i < rtd->num_codecs; i++)
+		snd_soc_dai_digital_mute(rtd->codec_dais[i], 0,
+					 substream->stream);
 
 out:
 	mutex_unlock(&rtd->pcm_mutex);
 	return ret;
 }
 
+static void soc_pcm_codec_params_fixup(struct snd_pcm_hw_params *params,
+				       unsigned int mask)
+{
+	struct snd_interval *interval;
+	int channels = hweight_long(mask);
+
+	interval = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
+	interval->min = channels;
+	interval->max = channels;
+}
+
 /*
  * Called by ALSA when the hardware params are set by application. This
  * function can also be called multiple times and can allocate buffers
@@ -680,8 +791,7 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream,
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 	struct snd_soc_platform *platform = rtd->platform;
 	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-	struct snd_soc_dai *codec_dai = rtd->codec_dai;
-	int ret = 0;
+	int i, ret = 0;
 
 	mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
 
@@ -698,13 +808,37 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream,
 		}
 	}
 
-	if (codec_dai->driver->ops && codec_dai->driver->ops->hw_params) {
-		ret = codec_dai->driver->ops->hw_params(substream, params, codec_dai);
-		if (ret < 0) {
-			dev_err(codec_dai->dev, "ASoC: can't set %s hw params:"
-				" %d\n", codec_dai->name, ret);
-			goto codec_err;
+	for (i = 0; i < rtd->num_codecs; i++) {
+		struct snd_soc_dai *codec_dai = rtd->codec_dais[i];
+		struct snd_pcm_hw_params codec_params;
+
+		/* copy params for each codec */
+		memcpy(&codec_params, params, sizeof(struct snd_pcm_hw_params));
+
+		/* fixup params based on TDM slot masks */
+		if (codec_dai->tx_mask)
+			soc_pcm_codec_params_fixup(&codec_params,
+						   codec_dai->tx_mask);
+		if (codec_dai->rx_mask)
+			soc_pcm_codec_params_fixup(&codec_params,
+						   codec_dai->rx_mask);
+
+		if (codec_dai->driver->ops &&
+		    codec_dai->driver->ops->hw_params) {
+			ret = codec_dai->driver->ops->hw_params(substream,
+						&codec_params, codec_dai);
+			if (ret < 0) {
+				dev_err(codec_dai->dev,
+					"ASoC: can't set %s hw params: %d\n",
+					codec_dai->name, ret);
+				goto codec_err;
+			}
 		}
+
+		codec_dai->rate = params_rate(&codec_params);
+		codec_dai->channels = params_channels(&codec_params);
+		codec_dai->sample_bits = snd_pcm_format_physical_width(
+						params_format(&codec_params));
 	}
 
 	if (cpu_dai->driver->ops && cpu_dai->driver->ops->hw_params) {
@@ -731,11 +865,6 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream,
 	cpu_dai->sample_bits =
 		snd_pcm_format_physical_width(params_format(params));
 
-	codec_dai->rate = params_rate(params);
-	codec_dai->channels = params_channels(params);
-	codec_dai->sample_bits =
-		snd_pcm_format_physical_width(params_format(params));
-
 out:
 	mutex_unlock(&rtd->pcm_mutex);
 	return ret;
@@ -745,10 +874,16 @@ platform_err:
 		cpu_dai->driver->ops->hw_free(substream, cpu_dai);
 
 interface_err:
-	if (codec_dai->driver->ops && codec_dai->driver->ops->hw_free)
-		codec_dai->driver->ops->hw_free(substream, codec_dai);
+	i = rtd->num_codecs;
 
 codec_err:
+	while (--i >= 0) {
+		struct snd_soc_dai *codec_dai = rtd->codec_dais[i];
+		if (codec_dai->driver->ops && codec_dai->driver->ops->hw_free)
+			codec_dai->driver->ops->hw_free(substream, codec_dai);
+		codec_dai->rate = 0;
+	}
+
 	if (rtd->dai_link->ops && rtd->dai_link->ops->hw_free)
 		rtd->dai_link->ops->hw_free(substream);
 
@@ -764,8 +899,9 @@ static int soc_pcm_hw_free(struct snd_pcm_substream *substream)
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 	struct snd_soc_platform *platform = rtd->platform;
 	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-	struct snd_soc_dai *codec_dai = rtd->codec_dai;
+	struct snd_soc_dai *codec_dai;
 	bool playback = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
+	int i;
 
 	mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
 
@@ -776,16 +912,22 @@ static int soc_pcm_hw_free(struct snd_pcm_substream *substream)
 		cpu_dai->sample_bits = 0;
 	}
 
-	if (codec_dai->active == 1) {
-		codec_dai->rate = 0;
-		codec_dai->channels = 0;
-		codec_dai->sample_bits = 0;
+	for (i = 0; i < rtd->num_codecs; i++) {
+		codec_dai = rtd->codec_dais[i];
+		if (codec_dai->active == 1) {
+			codec_dai->rate = 0;
+			codec_dai->channels = 0;
+			codec_dai->sample_bits = 0;
+		}
 	}
 
 	/* apply codec digital mute */
-	if ((playback && codec_dai->playback_active == 1) ||
-	    (!playback && codec_dai->capture_active == 1))
-		snd_soc_dai_digital_mute(codec_dai, 1, substream->stream);
+	for (i = 0; i < rtd->num_codecs; i++) {
+		if ((playback && rtd->codec_dais[i]->playback_active == 1) ||
+		    (!playback && rtd->codec_dais[i]->capture_active == 1))
+			snd_soc_dai_digital_mute(rtd->codec_dais[i], 1,
+						 substream->stream);
+	}
 
 	/* free any machine hw params */
 	if (rtd->dai_link->ops && rtd->dai_link->ops->hw_free)
@@ -796,8 +938,11 @@ static int soc_pcm_hw_free(struct snd_pcm_substream *substream)
 		platform->driver->ops->hw_free(substream);
 
 	/* now free hw params for the DAIs  */
-	if (codec_dai->driver->ops && codec_dai->driver->ops->hw_free)
-		codec_dai->driver->ops->hw_free(substream, codec_dai);
+	for (i = 0; i < rtd->num_codecs; i++) {
+		codec_dai = rtd->codec_dais[i];
+		if (codec_dai->driver->ops && codec_dai->driver->ops->hw_free)
+			codec_dai->driver->ops->hw_free(substream, codec_dai);
+	}
 
 	if (cpu_dai->driver->ops && cpu_dai->driver->ops->hw_free)
 		cpu_dai->driver->ops->hw_free(substream, cpu_dai);
@@ -811,13 +956,17 @@ static int soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 	struct snd_soc_platform *platform = rtd->platform;
 	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-	struct snd_soc_dai *codec_dai = rtd->codec_dai;
-	int ret;
-
-	if (codec_dai->driver->ops && codec_dai->driver->ops->trigger) {
-		ret = codec_dai->driver->ops->trigger(substream, cmd, codec_dai);
-		if (ret < 0)
-			return ret;
+	struct snd_soc_dai *codec_dai;
+	int i, ret;
+
+	for (i = 0; i < rtd->num_codecs; i++) {
+		codec_dai = rtd->codec_dais[i];
+		if (codec_dai->driver->ops && codec_dai->driver->ops->trigger) {
+			ret = codec_dai->driver->ops->trigger(substream,
+							      cmd, codec_dai);
+			if (ret < 0)
+				return ret;
+		}
 	}
 
 	if (platform->driver->ops && platform->driver->ops->trigger) {
@@ -847,14 +996,18 @@ static int soc_pcm_bespoke_trigger(struct snd_pcm_substream *substream,
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 	struct snd_soc_platform *platform = rtd->platform;
 	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-	struct snd_soc_dai *codec_dai = rtd->codec_dai;
-	int ret;
-
-	if (codec_dai->driver->ops &&
-	    codec_dai->driver->ops->bespoke_trigger) {
-		ret = codec_dai->driver->ops->bespoke_trigger(substream, cmd, codec_dai);
-		if (ret < 0)
-			return ret;
+	struct snd_soc_dai *codec_dai;
+	int i, ret;
+
+	for (i = 0; i < rtd->num_codecs; i++) {
+		codec_dai = rtd->codec_dais[i];
+		if (codec_dai->driver->ops &&
+		    codec_dai->driver->ops->bespoke_trigger) {
+			ret = codec_dai->driver->ops->bespoke_trigger(substream,
+								cmd, codec_dai);
+			if (ret < 0)
+				return ret;
+		}
 	}
 
 	if (platform->driver->bespoke_trigger) {
@@ -880,10 +1033,12 @@ static snd_pcm_uframes_t soc_pcm_pointer(struct snd_pcm_substream *substream)
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 	struct snd_soc_platform *platform = rtd->platform;
 	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-	struct snd_soc_dai *codec_dai = rtd->codec_dai;
+	struct snd_soc_dai *codec_dai;
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	snd_pcm_uframes_t offset = 0;
 	snd_pcm_sframes_t delay = 0;
+	snd_pcm_sframes_t codec_delay = 0;
+	int i;
 
 	if (platform->driver->ops && platform->driver->ops->pointer)
 		offset = platform->driver->ops->pointer(substream);
@@ -891,11 +1046,21 @@ static snd_pcm_uframes_t soc_pcm_pointer(struct snd_pcm_substream *substream)
 	if (cpu_dai->driver->ops && cpu_dai->driver->ops->delay)
 		delay += cpu_dai->driver->ops->delay(substream, cpu_dai);
 
-	if (codec_dai->driver->ops && codec_dai->driver->ops->delay)
-		delay += codec_dai->driver->ops->delay(substream, codec_dai);
+	for (i = 0; i < rtd->num_codecs; i++) {
+		codec_dai = rtd->codec_dais[i];
+		if (codec_dai->driver->ops && codec_dai->driver->ops->delay)
+			codec_delay = max(codec_delay,
+					codec_dai->driver->ops->delay(substream,
+								    codec_dai));
+	}
+	delay += codec_delay;
 
+	/*
+	 * None of the existing platform drivers implement delay(), so
+	 * for now the codec_dai of first multicodec entry is used
+	 */
 	if (platform->driver->delay)
-		delay += platform->driver->delay(substream, codec_dai);
+		delay += platform->driver->delay(substream, rtd->codec_dais[0]);
 
 	runtime->delay = delay;
 
@@ -998,7 +1163,7 @@ static struct snd_soc_pcm_runtime *dpcm_get_be(struct snd_soc_card *card,
 		struct snd_soc_dapm_widget *widget, int stream)
 {
 	struct snd_soc_pcm_runtime *be;
-	int i;
+	int i, j;
 
 	if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
 		for (i = 0; i < card->num_links; i++) {
@@ -1007,9 +1172,14 @@ static struct snd_soc_pcm_runtime *dpcm_get_be(struct snd_soc_card *card,
 			if (!be->dai_link->no_pcm)
 				continue;
 
-			if (be->cpu_dai->playback_widget == widget ||
-				be->codec_dai->playback_widget == widget)
+			if (be->cpu_dai->playback_widget == widget)
 				return be;
+
+			for (j = 0; j < be->num_codecs; j++) {
+				struct snd_soc_dai *dai = be->codec_dais[j];
+				if (dai->playback_widget == widget)
+					return be;
+			}
 		}
 	} else {
 
@@ -1019,9 +1189,14 @@ static struct snd_soc_pcm_runtime *dpcm_get_be(struct snd_soc_card *card,
 			if (!be->dai_link->no_pcm)
 				continue;
 
-			if (be->cpu_dai->capture_widget == widget ||
-				be->codec_dai->capture_widget == widget)
+			if (be->cpu_dai->capture_widget == widget)
 				return be;
+
+			for (j = 0; j < be->num_codecs; j++) {
+				struct snd_soc_dai *dai = be->codec_dais[j];
+				if (dai->capture_widget == widget)
+					return be;
+			}
 		}
 	}
 
@@ -1084,6 +1259,7 @@ static int dpcm_prune_paths(struct snd_soc_pcm_runtime *fe, int stream,
 
 	/* Destroy any old FE <--> BE connections */
 	list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) {
+		unsigned int i;
 
 		/* is there a valid CPU DAI widget for this BE */
 		widget = dai_get_widget(dpcm->be->cpu_dai, stream);
@@ -1093,11 +1269,14 @@ static int dpcm_prune_paths(struct snd_soc_pcm_runtime *fe, int stream,
 			continue;
 
 		/* is there a valid CODEC DAI widget for this BE */
-		widget = dai_get_widget(dpcm->be->codec_dai, stream);
+		for (i = 0; i < dpcm->be->num_codecs; i++) {
+			struct snd_soc_dai *dai = dpcm->be->codec_dais[i];
+			widget = dai_get_widget(dai, stream);
 
-		/* prune the BE if it's no longer in our active list */
-		if (widget && widget_in_list(list, widget))
-			continue;
+			/* prune the BE if it's no longer in our active list */
+			if (widget && widget_in_list(list, widget))
+				continue;
+		}
 
 		dev_dbg(fe->dev, "ASoC: pruning %s BE %s for %s\n",
 			stream ? "capture" : "playback",
@@ -2127,16 +2306,22 @@ int soc_dpcm_be_digital_mute(struct snd_soc_pcm_runtime *fe, int mute)
 	list_for_each_entry(dpcm, clients, list_be) {
 
 		struct snd_soc_pcm_runtime *be = dpcm->be;
-		struct snd_soc_dai *dai = be->codec_dai;
-		struct snd_soc_dai_driver *drv = dai->driver;
+		int i;
 
 		if (be->dai_link->ignore_suspend)
 			continue;
 
-		dev_dbg(be->dev, "ASoC: BE digital mute %s\n", be->dai_link->name);
+		for (i = 0; i < be->num_codecs; i++) {
+			struct snd_soc_dai *dai = be->codec_dais[i];
+			struct snd_soc_dai_driver *drv = dai->driver;
+
+			dev_dbg(be->dev, "ASoC: BE digital mute %s\n",
+					 be->dai_link->name);
 
-		if (drv->ops && drv->ops->digital_mute && dai->playback_active)
-			drv->ops->digital_mute(dai, mute);
+			if (drv->ops && drv->ops->digital_mute &&
+							dai->playback_active)
+				drv->ops->digital_mute(dai, mute);
+		}
 	}
 
 	return 0;
@@ -2201,22 +2386,27 @@ static int dpcm_fe_dai_close(struct snd_pcm_substream *fe_substream)
 int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num)
 {
 	struct snd_soc_platform *platform = rtd->platform;
-	struct snd_soc_dai *codec_dai = rtd->codec_dai;
+	struct snd_soc_dai *codec_dai;
 	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
 	struct snd_pcm *pcm;
 	char new_name[64];
 	int ret = 0, playback = 0, capture = 0;
+	int i;
 
 	if (rtd->dai_link->dynamic || rtd->dai_link->no_pcm) {
 		playback = rtd->dai_link->dpcm_playback;
 		capture = rtd->dai_link->dpcm_capture;
 	} else {
-		if (codec_dai->driver->playback.channels_min &&
-		    cpu_dai->driver->playback.channels_min)
-			playback = 1;
-		if (codec_dai->driver->capture.channels_min &&
-		    cpu_dai->driver->capture.channels_min)
-			capture = 1;
+		for (i = 0; i < rtd->num_codecs; i++) {
+			codec_dai = rtd->codec_dais[i];
+			if (codec_dai->driver->playback.channels_min)
+				playback = 1;
+			if (codec_dai->driver->capture.channels_min)
+				capture = 1;
+		}
+
+		capture = capture && cpu_dai->driver->capture.channels_min;
+		playback = playback && cpu_dai->driver->playback.channels_min;
 	}
 
 	if (rtd->dai_link->playback_only) {
@@ -2242,7 +2432,9 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num)
 				rtd->dai_link->stream_name);
 		else
 			snprintf(new_name, sizeof(new_name), "%s %s-%d",
-				rtd->dai_link->stream_name, codec_dai->name, num);
+				rtd->dai_link->stream_name,
+				(rtd->num_codecs > 1) ?
+				"multicodec" : rtd->codec_dai->name, num);
 
 		ret = snd_pcm_new(rtd->card->snd_card, new_name, num, playback,
 			capture, &pcm);
@@ -2315,8 +2507,9 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num)
 
 	pcm->private_free = platform->driver->pcm_free;
 out:
-	dev_info(rtd->card->dev, "%s <-> %s mapping ok\n", codec_dai->name,
-		cpu_dai->name);
+	dev_info(rtd->card->dev, "%s <-> %s mapping ok\n",
+		 (rtd->num_codecs > 1) ? "multicodec" : rtd->codec_dai->name,
+		 cpu_dai->name);
 	return ret;
 }
 
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 43+ messages in thread

* [PATCH v4 5/8] ASoC: dapm: Add support for DAI multicodec
  2014-07-01  7:47 [PATCH v4 0/8] ASoC: core: Add support for DAI multicodec Benoit Cousson
                   ` (3 preceding siblings ...)
  2014-07-01  7:47 ` [PATCH v4 4/8] ASoC: pcm: Add " Benoit Cousson
@ 2014-07-01  7:47 ` Benoit Cousson
  2014-07-01 13:40   ` Lars-Peter Clausen
  2014-07-01  7:47 ` [PATCH v4 6/8] ASoC: compress: " Benoit Cousson
                   ` (2 subsequent siblings)
  7 siblings, 1 reply; 43+ messages in thread
From: Benoit Cousson @ 2014-07-01  7:47 UTC (permalink / raw)
  To: broonie, lgirdwood, lars
  Cc: Fabien Parent, misael.lopez, alsa-devel, Benoit Cousson

Add multicodec support in soc-dapm.c

Signed-off-by: Benoit Cousson <bcousson@baylibre.com>
Signed-off-by: Misael Lopez Cruz <misael.lopez@ti.com>
Signed-off-by: Fabien Parent <fparent@baylibre.com>
---
 sound/soc/soc-dapm.c | 67 ++++++++++++++++++++++++++++++++++++----------------
 1 file changed, 47 insertions(+), 20 deletions(-)

diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index 4bf08cf..5c63c3b 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -2084,12 +2084,8 @@ int snd_soc_dapm_mixer_update_power(struct snd_soc_dapm_context *dapm,
 }
 EXPORT_SYMBOL_GPL(snd_soc_dapm_mixer_update_power);
 
-/* show dapm widget status in sys fs */
-static ssize_t dapm_widget_show(struct device *dev,
-	struct device_attribute *attr, char *buf)
+static ssize_t dapm_widget_show_codec(struct snd_soc_codec *codec, char *buf)
 {
-	struct snd_soc_pcm_runtime *rtd = dev_get_drvdata(dev);
-	struct snd_soc_codec *codec =rtd->codec;
 	struct snd_soc_dapm_widget *w;
 	int count = 0;
 	char *state = "not set";
@@ -2142,6 +2138,21 @@ static ssize_t dapm_widget_show(struct device *dev,
 	return count;
 }
 
+/* show dapm widget status in sys fs */
+static ssize_t dapm_widget_show(struct device *dev,
+	struct device_attribute *attr, char *buf)
+{
+	struct snd_soc_pcm_runtime *rtd = dev_get_drvdata(dev);
+	int i, count = 0;
+
+	for (i = 0; i < rtd->num_codecs; i++) {
+		struct snd_soc_codec *codec = rtd->codec_dais[i]->codec;
+		count += dapm_widget_show_codec(codec, buf + count);
+	}
+
+	return count;
+}
+
 static DEVICE_ATTR(dapm_widget, 0444, dapm_widget_show, NULL);
 
 int snd_soc_dapm_sys_add(struct device *dev)
@@ -3395,25 +3406,18 @@ int snd_soc_dapm_link_dai_widgets(struct snd_soc_card *card)
 	return 0;
 }
 
-void snd_soc_dapm_connect_dai_link_widgets(struct snd_soc_card *card)
+static void dapm_connect_dai_link_widgets(struct snd_soc_card *card,
+					  struct snd_soc_pcm_runtime *rtd)
 {
-	struct snd_soc_pcm_runtime *rtd = card->rtd;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
 	struct snd_soc_dapm_widget *sink, *source;
-	struct snd_soc_dai *cpu_dai, *codec_dai;
+	struct snd_soc_dapm_route r;
 	int i;
 
-	/* for each BE DAI link... */
-	for (i = 0; i < card->num_rtd; i++) {
-		rtd = &card->rtd[i];
-		cpu_dai = rtd->cpu_dai;
-		codec_dai = rtd->codec_dai;
+	memset(&r, 0, sizeof(r));
 
-		/*
-		 * dynamic FE links have no fixed DAI mapping.
-		 * CODEC<->CODEC links have no direct connection.
-		 */
-		if (rtd->dai_link->dynamic || rtd->dai_link->params)
-			continue;
+	for (i = 0; i < rtd->num_codecs; i++) {
+		struct snd_soc_dai *codec_dai = rtd->codec_dais[i];
 
 		/* there is no point in connecting BE DAI links with dummies */
 		if (snd_soc_dai_is_dummy(codec_dai) ||
@@ -3475,11 +3479,34 @@ static void soc_dapm_dai_stream_event(struct snd_soc_dai *dai, int stream,
 	}
 }
 
+void snd_soc_dapm_connect_dai_link_widgets(struct snd_soc_card *card)
+{
+	struct snd_soc_pcm_runtime *rtd = card->rtd;
+	int i;
+
+	/* for each BE DAI link... */
+	for (i = 0; i < card->num_rtd; i++) {
+		rtd = &card->rtd[i];
+
+		/*
+		 * dynamic FE links have no fixed DAI mapping.
+		 * CODEC<->CODEC links have no direct connection.
+		 */
+		if (rtd->dai_link->dynamic || rtd->dai_link->params)
+			continue;
+
+		dapm_connect_dai_link_widgets(card, rtd);
+	}
+}
+
 static void soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, int stream,
 	int event)
 {
+	int i;
+
 	soc_dapm_dai_stream_event(rtd->cpu_dai, stream, event);
-	soc_dapm_dai_stream_event(rtd->codec_dai, stream, event);
+	for (i = 0; i < rtd->num_codecs; i++)
+		soc_dapm_dai_stream_event(rtd->codec_dais[i], stream, event);
 
 	dapm_power_widgets(rtd->card, event);
 }
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 43+ messages in thread

* [PATCH v4 6/8] ASoC: compress: Add support for DAI multicodec
  2014-07-01  7:47 [PATCH v4 0/8] ASoC: core: Add support for DAI multicodec Benoit Cousson
                   ` (4 preceding siblings ...)
  2014-07-01  7:47 ` [PATCH v4 5/8] ASoC: dapm: " Benoit Cousson
@ 2014-07-01  7:47 ` Benoit Cousson
  2014-07-01 13:49   ` Lars-Peter Clausen
  2014-07-01 16:41   ` Vinod Koul
  2014-07-01  7:48 ` [PATCH v4 7/8] ASoC: pcm: Add soc_dai_hw_params helper Benoit Cousson
  2014-07-01  7:48 ` [PATCH v4 8/8] ASoC: core: Add a warning for link_dai_widget in the multicodec case Benoit Cousson
  7 siblings, 2 replies; 43+ messages in thread
From: Benoit Cousson @ 2014-07-01  7:47 UTC (permalink / raw)
  To: broonie, lgirdwood, lars; +Cc: misael.lopez, alsa-devel, Benoit Cousson

Add multicodec support in soc-compress.c

Signed-off-by: Benoit Cousson <bcousson@baylibre.com>
Cc: Misael Lopez Cruz <misael.lopez@ti.com>
---
 sound/soc/soc-compress.c | 94 ++++++++++++++++++++++++++++++------------------
 1 file changed, 59 insertions(+), 35 deletions(-)

diff --git a/sound/soc/soc-compress.c b/sound/soc/soc-compress.c
index f96fb96..cd65b12 100644
--- a/sound/soc/soc-compress.c
+++ b/sound/soc/soc-compress.c
@@ -155,14 +155,17 @@ static void close_delayed_work(struct work_struct *work)
 {
 	struct snd_soc_pcm_runtime *rtd =
 			container_of(work, struct snd_soc_pcm_runtime, delayed_work.work);
-	struct snd_soc_dai *codec_dai = rtd->codec_dai;
+	int i;
 
 	mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
 
-	dev_dbg(rtd->dev, "ASoC: pop wq checking: %s status: %s waiting: %s\n",
-		 codec_dai->driver->playback.stream_name,
-		 codec_dai->playback_active ? "active" : "inactive",
-		 rtd->pop_wait ? "yes" : "no");
+	for (i = 0; i < rtd->num_codecs; i++) {
+		struct snd_soc_dai *codec_dai = rtd->codec_dais[i];
+		dev_dbg(rtd->dev, "ASoC: pop wq checking: %s status: %s waiting: %s\n",
+			 codec_dai->driver->playback.stream_name,
+			 codec_dai->playback_active ? "active" : "inactive",
+			 rtd->pop_wait ? "yes" : "no");
+	}
 
 	/* are we waiting on this codec DAI stream */
 	if (rtd->pop_wait == 1) {
@@ -179,8 +182,7 @@ static int soc_compr_free(struct snd_compr_stream *cstream)
 	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
 	struct snd_soc_platform *platform = rtd->platform;
 	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-	struct snd_soc_dai *codec_dai = rtd->codec_dai;
-	int stream;
+	int stream, i;
 
 	mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
 
@@ -191,14 +193,18 @@ static int soc_compr_free(struct snd_compr_stream *cstream)
 
 	snd_soc_runtime_deactivate(rtd, stream);
 
-	snd_soc_dai_digital_mute(codec_dai, 1, cstream->direction);
+	for (i = 0; i < rtd->num_codecs; i++) {
+		struct snd_soc_dai *codec_dai = rtd->codec_dais[i];
+
+		snd_soc_dai_digital_mute(codec_dai, 1, cstream->direction);
+
+		if (!codec_dai->active)
+			codec_dai->rate = 0;
+	}
 
 	if (!cpu_dai->active)
 		cpu_dai->rate = 0;
 
-	if (!codec_dai->active)
-		codec_dai->rate = 0;
-
 
 	if (rtd->dai_link->compr_ops && rtd->dai_link->compr_ops->shutdown)
 		rtd->dai_link->compr_ops->shutdown(cstream);
@@ -283,8 +289,7 @@ static int soc_compr_trigger(struct snd_compr_stream *cstream, int cmd)
 
 	struct snd_soc_pcm_runtime *rtd = cstream->private_data;
 	struct snd_soc_platform *platform = rtd->platform;
-	struct snd_soc_dai *codec_dai = rtd->codec_dai;
-	int ret = 0;
+	int i, ret = 0;
 
 	mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
 
@@ -294,13 +299,19 @@ static int soc_compr_trigger(struct snd_compr_stream *cstream, int cmd)
 			goto out;
 	}
 
-	switch (cmd) {
-	case SNDRV_PCM_TRIGGER_START:
-		snd_soc_dai_digital_mute(codec_dai, 0, cstream->direction);
-		break;
-	case SNDRV_PCM_TRIGGER_STOP:
-		snd_soc_dai_digital_mute(codec_dai, 1, cstream->direction);
-		break;
+	for (i = 0; i < rtd->num_codecs; i++) {
+		struct snd_soc_dai *codec_dai = rtd->codec_dais[i];
+
+		switch (cmd) {
+		case SNDRV_PCM_TRIGGER_START:
+			snd_soc_dai_digital_mute(codec_dai, 0,
+						 cstream->direction);
+			break;
+		case SNDRV_PCM_TRIGGER_STOP:
+			snd_soc_dai_digital_mute(codec_dai, 1,
+						 cstream->direction);
+			break;
+		}
 	}
 
 out:
@@ -622,23 +633,33 @@ int soc_new_compress(struct snd_soc_pcm_runtime *rtd, int num)
 {
 	struct snd_soc_codec *codec = rtd->codec;
 	struct snd_soc_platform *platform = rtd->platform;
-	struct snd_soc_dai *codec_dai = rtd->codec_dai;
 	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
 	struct snd_compr *compr;
 	struct snd_pcm *be_pcm;
 	char new_name[64];
-	int ret = 0, direction = 0;
-
-	/* check client and interface hw capabilities */
-	snprintf(new_name, sizeof(new_name), "%s %s-%d",
-			rtd->dai_link->stream_name, codec_dai->name, num);
-
-	if (codec_dai->driver->playback.channels_min)
-		direction = SND_COMPRESS_PLAYBACK;
-	else if (codec_dai->driver->capture.channels_min)
-		direction = SND_COMPRESS_CAPTURE;
-	else
-		return -EINVAL;
+	int i, ret = 0, direction = -1;
+
+	for (i = 0; i < rtd->num_codecs; i++) {
+		struct snd_soc_dai *codec_dai = rtd->codec_dais[i];
+		/* check client and interface hw capabilities */
+		snprintf(new_name, sizeof(new_name), "%s %s-%d",
+			 rtd->dai_link->stream_name, codec_dai->name, num);
+
+		if (direction < 0) {
+			if (codec_dai->driver->playback.channels_min)
+				direction = SND_COMPRESS_PLAYBACK;
+			else if (codec_dai->driver->capture.channels_min)
+				direction = SND_COMPRESS_CAPTURE;
+			else
+				return -EINVAL;
+		} else {
+			if ((codec_dai->driver->playback.channels_min &&
+					direction != SND_COMPRESS_PLAYBACK) ||
+			    (codec_dai->driver->capture.channels_min &&
+					direction != SND_COMPRESS_CAPTURE))
+				return -EINVAL;
+		}
+	}
 
 	compr = kzalloc(sizeof(*compr), GFP_KERNEL);
 	if (compr == NULL) {
@@ -692,8 +713,11 @@ int soc_new_compress(struct snd_soc_pcm_runtime *rtd, int num)
 	rtd->compr = compr;
 	compr->private_data = rtd;
 
-	printk(KERN_INFO "compress asoc: %s <-> %s mapping ok\n", codec_dai->name,
-		cpu_dai->name);
+	for (i = 0; i < rtd->num_codecs; i++) {
+		struct snd_soc_dai *codec_dai = rtd->codec_dais[i];
+		printk(KERN_INFO "compress asoc: %s <-> %s mapping ok\n",
+		       codec_dai->name, cpu_dai->name);
+	}
 	return ret;
 
 compr_err:
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 43+ messages in thread

* [PATCH v4 7/8] ASoC: pcm: Add soc_dai_hw_params helper
  2014-07-01  7:47 [PATCH v4 0/8] ASoC: core: Add support for DAI multicodec Benoit Cousson
                   ` (5 preceding siblings ...)
  2014-07-01  7:47 ` [PATCH v4 6/8] ASoC: compress: " Benoit Cousson
@ 2014-07-01  7:48 ` Benoit Cousson
  2014-07-01 13:43   ` Lars-Peter Clausen
  2014-07-01  7:48 ` [PATCH v4 8/8] ASoC: core: Add a warning for link_dai_widget in the multicodec case Benoit Cousson
  7 siblings, 1 reply; 43+ messages in thread
From: Benoit Cousson @ 2014-07-01  7:48 UTC (permalink / raw)
  To: broonie, lgirdwood, lars; +Cc: misael.lopez, alsa-devel, Benoit Cousson

Add a function helper to factorize the hw_params code.

Suggested by Lars-Peter Clausen <lars@metafoo.de>

Signed-off-by: Benoit Cousson <bcousson@baylibre.com>
---
 include/sound/soc.h  |  4 ++++
 sound/soc/soc-dapm.c | 26 ++++++--------------------
 sound/soc/soc-pcm.c  | 41 ++++++++++++++++++++++-------------------
 3 files changed, 32 insertions(+), 39 deletions(-)

diff --git a/include/sound/soc.h b/include/sound/soc.h
index f2142cf..98555f8 100644
--- a/include/sound/soc.h
+++ b/include/sound/soc.h
@@ -436,6 +436,10 @@ int snd_soc_set_runtime_hwparams(struct snd_pcm_substream *substream,
 int snd_soc_platform_trigger(struct snd_pcm_substream *substream,
 		int cmd, struct snd_soc_platform *platform);
 
+int soc_dai_hw_params(struct snd_pcm_substream *substream,
+		      struct snd_pcm_hw_params *params,
+		      struct snd_soc_dai *dai);
+
 /* Jack reporting */
 int snd_soc_jack_new(struct snd_soc_codec *codec, const char *id, int type,
 		     struct snd_soc_jack *jack);
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index 5c63c3b..d8a24bb 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -3214,27 +3214,13 @@ static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w,
 
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
-		if (source->driver->ops && source->driver->ops->hw_params) {
-			substream.stream = SNDRV_PCM_STREAM_CAPTURE;
-			ret = source->driver->ops->hw_params(&substream,
-							     params, source);
-			if (ret != 0) {
-				dev_err(source->dev,
-					"ASoC: hw_params() failed: %d\n", ret);
-				goto out;
-			}
-		}
+		substream.stream = SNDRV_PCM_STREAM_CAPTURE;
+		if (soc_dai_hw_params(&substream, params, source) < 0)
+			goto out;
 
-		if (sink->driver->ops && sink->driver->ops->hw_params) {
-			substream.stream = SNDRV_PCM_STREAM_PLAYBACK;
-			ret = sink->driver->ops->hw_params(&substream, params,
-							   sink);
-			if (ret != 0) {
-				dev_err(sink->dev,
-					"ASoC: hw_params() failed: %d\n", ret);
-				goto out;
-			}
-		}
+		substream.stream = SNDRV_PCM_STREAM_PLAYBACK;
+		if (soc_dai_hw_params(&substream, params, sink) < 0)
+			goto out;
 		break;
 
 	case SND_SOC_DAPM_POST_PMU:
diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c
index 981b99c..b48f2a8 100644
--- a/sound/soc/soc-pcm.c
+++ b/sound/soc/soc-pcm.c
@@ -780,6 +780,24 @@ static void soc_pcm_codec_params_fixup(struct snd_pcm_hw_params *params,
 	interval->max = channels;
 }
 
+int soc_dai_hw_params(struct snd_pcm_substream *substream,
+		      struct snd_pcm_hw_params *params,
+		      struct snd_soc_dai *dai)
+{
+	int ret;
+
+	if (dai->driver->ops && dai->driver->ops->hw_params) {
+		ret = dai->driver->ops->hw_params(substream, params, dai);
+		if (ret < 0) {
+			dev_err(dai->dev, "ASoC: can't set %s hw params: %d\n",
+				dai->name, ret);
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
 /*
  * Called by ALSA when the hardware params are set by application. This
  * function can also be called multiple times and can allocate buffers
@@ -823,17 +841,8 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream,
 			soc_pcm_codec_params_fixup(&codec_params,
 						   codec_dai->rx_mask);
 
-		if (codec_dai->driver->ops &&
-		    codec_dai->driver->ops->hw_params) {
-			ret = codec_dai->driver->ops->hw_params(substream,
-						&codec_params, codec_dai);
-			if (ret < 0) {
-				dev_err(codec_dai->dev,
-					"ASoC: can't set %s hw params: %d\n",
-					codec_dai->name, ret);
-				goto codec_err;
-			}
-		}
+		if (soc_dai_hw_params(substream, &codec_params, codec_dai) < 0)
+			goto codec_err;
 
 		codec_dai->rate = params_rate(&codec_params);
 		codec_dai->channels = params_channels(&codec_params);
@@ -841,14 +850,8 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream,
 						params_format(&codec_params));
 	}
 
-	if (cpu_dai->driver->ops && cpu_dai->driver->ops->hw_params) {
-		ret = cpu_dai->driver->ops->hw_params(substream, params, cpu_dai);
-		if (ret < 0) {
-			dev_err(cpu_dai->dev, "ASoC: %s hw params failed: %d\n",
-				cpu_dai->name, ret);
-			goto interface_err;
-		}
-	}
+	if (soc_dai_hw_params(substream, params, cpu_dai) < 0)
+		goto interface_err;
 
 	if (platform->driver->ops && platform->driver->ops->hw_params) {
 		ret = platform->driver->ops->hw_params(substream, params);
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 43+ messages in thread

* [PATCH v4 8/8] ASoC: core: Add a warning for link_dai_widget in the multicodec case
  2014-07-01  7:47 [PATCH v4 0/8] ASoC: core: Add support for DAI multicodec Benoit Cousson
                   ` (6 preceding siblings ...)
  2014-07-01  7:48 ` [PATCH v4 7/8] ASoC: pcm: Add soc_dai_hw_params helper Benoit Cousson
@ 2014-07-01  7:48 ` Benoit Cousson
  2014-07-01 13:41   ` Lars-Peter Clausen
  7 siblings, 1 reply; 43+ messages in thread
From: Benoit Cousson @ 2014-07-01  7:48 UTC (permalink / raw)
  To: broonie, lgirdwood, lars; +Cc: misael.lopez, alsa-devel, Benoit Cousson

Multicodec links are not supported in the case of CODEC to CODEC links.
Just print a warning if it happens.

Signed-off-by: Benoit Cousson <bcousson@baylibre.com>
---
 sound/soc/soc-core.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index 3764150..3640242 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -1486,6 +1486,9 @@ static int soc_link_dai_widgets(struct snd_soc_card *card,
 	struct snd_soc_dapm_widget *play_w, *capture_w;
 	int ret;
 
+	if (rtd->num_codecs > 1)
+		dev_warn(card->dev, "ASoC: Multiple codecs not supported yet\n");
+
 	/* link the DAI widgets */
 	play_w = codec_dai->playback_widget;
 	capture_w = cpu_dai->capture_widget;
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 43+ messages in thread

* Re: [PATCH v4 3/8] ASoC: core: Add initial support for DAI multicodec
  2014-07-01  7:47 ` [PATCH v4 3/8] ASoC: core: Add initial support for DAI multicodec Benoit Cousson
@ 2014-07-01 13:19   ` Lars-Peter Clausen
  2014-07-01 17:27     ` Benoit Cousson
  0 siblings, 1 reply; 43+ messages in thread
From: Lars-Peter Clausen @ 2014-07-01 13:19 UTC (permalink / raw)
  To: Benoit Cousson, broonie, lgirdwood
  Cc: Fabien Parent, misael.lopez, alsa-devel

On 07/01/2014 09:47 AM, Benoit Cousson wrote:
> DAI link assumes a one to one mapping between CPU DAI and CODEC. In
> some cases, the same CPU DAI can be connected to several codecs.
> This is the case for example, if you connect two mono codecs to the
> same I2S link in order to have a stereo card.
> The current ASoC implementation does not allow such setup.
>
> Add support for DAI links composed of a single CPU DAI and multiple
> CODECs. Sound cards have to pass the CODECs array in the corresponding
> DAI link through a new 'snd_soc_dai_link_component' struct. Each CODEC in
> this array is described in the same manner single CODEC DAIs are
> (either DT/OF node or codec_name).
>
> Based on an original code done by Misael.
>
> Signed-off-by: Benoit Cousson <bcousson@baylibre.com>
> Signed-off-by: Misael Lopez Cruz <misael.lopez@ti.com>
> Signed-off-by: Fabien Parent <fparent@baylibre.com>

Almost. There are two more serious issues, the rest is trivial.

> ---
[...]
> diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
> index 37a965c..3764150 100644
> --- a/sound/soc/soc-core.c
> +++ b/sound/soc/soc-core.c
> @@ -554,7 +554,7 @@ int snd_soc_suspend(struct device *dev)
>   {
>   	struct snd_soc_card *card = dev_get_drvdata(dev);
>   	struct snd_soc_codec *codec;
> -	int i;
> +	int i, j;
>
>   	/* If the initialization of this soc device failed, there is no codec
>   	 * associated with it. Just bail out in this case.
> @@ -574,14 +574,16 @@ int snd_soc_suspend(struct device *dev)
>
>   	/* mute any active DACs */
>   	for (i = 0; i < card->num_rtd; i++) {
> -		struct snd_soc_dai *dai = card->rtd[i].codec_dai;
> -		struct snd_soc_dai_driver *drv = dai->driver;
> +		for (j = 0; j < card->rtd[i].num_codecs; j++) {
> +			struct snd_soc_dai *dai = card->rtd[i].codec_dais[j];
> +			struct snd_soc_dai_driver *drv = dai->driver;
>
> -		if (card->rtd[i].dai_link->ignore_suspend)
> -			continue;
> +			if (card->rtd[i].dai_link->ignore_suspend)
> +				continue;

This check can actually stay outside the inner loop. We either want to mute 
all or none.

>
> -		if (drv->ops->digital_mute && dai->playback_active)
> -			drv->ops->digital_mute(dai, 1);
> +			if (drv->ops->digital_mute && dai->playback_active)
> +				drv->ops->digital_mute(dai, 1);
> +		}
>   	}
>
>   	/* suspend all pcms */
[...]
> @@ -697,7 +703,7 @@ static void soc_resume_deferred(struct work_struct *work)
>   	struct snd_soc_card *card =
>   			container_of(work, struct snd_soc_card, deferred_resume_work);
>   	struct snd_soc_codec *codec;
> -	int i;
> +	int i, j;
>
>   	/* our power state is still SNDRV_CTL_POWER_D3hot from suspend time,
>   	 * so userspace apps are blocked from touching us
> @@ -758,14 +764,17 @@ static void soc_resume_deferred(struct work_struct *work)
>
>   	/* unmute any active DACs */
>   	for (i = 0; i < card->num_rtd; i++) {
> -		struct snd_soc_dai *dai = card->rtd[i].codec_dai;
> -		struct snd_soc_dai_driver *drv = dai->driver;
>
> -		if (card->rtd[i].dai_link->ignore_suspend)
> -			continue;
> +		for (j = 0; j < card->rtd[i].num_codecs; j++) {
> +			struct snd_soc_dai *dai = card->rtd[i].codec_dais[j];
> +			struct snd_soc_dai_driver *drv = dai->driver;
> +
> +			if (card->rtd[i].dai_link->ignore_suspend)
> +				continue;

Same as with the mute loop.

>
> -		if (drv->ops->digital_mute && dai->playback_active)
> -			drv->ops->digital_mute(dai, 0);
> +			if (drv->ops->digital_mute && dai->playback_active)
> +				drv->ops->digital_mute(dai, 0);
> +		}
>   	}
>
>   	for (i = 0; i < card->num_rtd; i++) {
[...]			    int num)
> +static int soc_aux_dev_init(struct snd_soc_card *card, int num)
>   {
>   	struct snd_soc_aux_dev *aux_dev = &card->aux_dev[num];
>   	struct snd_soc_pcm_runtime *rtd = &card->rtd_aux[num];
> +	struct snd_soc_codec *codec;
>   	int ret;
>
>   	rtd->card = card;
>
> +	codec = soc_find_codec(NULL, aux_dev->codec_name);

We actually have support for binding the aux dev by DT node now. But I have 
a patch in my componentization branch that cleans all this up. Let me send 
it to you and then you can rebase on-top of that.

> +	if (!codec)
> +		return -EPROBE_DEFER;
> +
>   	/* do machine specific initialization */
>   	if (aux_dev->init) {
>   		ret = aux_dev->init(&codec->dapm);
> @@ -1286,16 +1316,19 @@ static int soc_aux_dev_init(struct snd_soc_card *card,
>   	return 0;
>   }
>
> -static int soc_dai_link_init(struct snd_soc_card *card,
> -			     struct snd_soc_codec *codec,
> -			     int num)
> +static int soc_dai_link_init(struct snd_soc_card *card, int num)
>   {
>   	struct snd_soc_dai_link *dai_link =  &card->dai_link[num];
>   	struct snd_soc_pcm_runtime *rtd = &card->rtd[num];
> -	int ret;
> +	int i, ret;
>
>   	rtd->card = card;
>
> +	for (i = 0; i < rtd->num_codecs; i++) {
> +		/* Make sure all DAPM widgets are instantiated */
> +		snd_soc_dapm_new_widgets(rtd->codec_dais[i]->codec->dapm.card);
> +	}

This is still a left over from a very early revision of this patch. We 
removed this in upstream a while ago.

> +
>   	/* do machine specific initialization */
>   	if (dai_link->init) {
>   		ret = dai_link->init(rtd);
[...]

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH v4 4/8] ASoC: pcm: Add support for DAI multicodec
  2014-07-01  7:47 ` [PATCH v4 4/8] ASoC: pcm: Add " Benoit Cousson
@ 2014-07-01 13:32   ` Lars-Peter Clausen
  0 siblings, 0 replies; 43+ messages in thread
From: Lars-Peter Clausen @ 2014-07-01 13:32 UTC (permalink / raw)
  To: Benoit Cousson, broonie, lgirdwood
  Cc: Fabien Parent, misael.lopez, alsa-devel

On 07/01/2014 09:47 AM, Benoit Cousson wrote:
> Add multicodec support in soc-pcm.c

Also almost.

>
> Signed-off-by: Benoit Cousson <bcousson@baylibre.com>
> Signed-off-by: Misael Lopez Cruz <misael.lopez@ti.com>
> Signed-off-by: Fabien Parent <fparent@baylibre.com>
> ---
[...]
>   /**
> @@ -107,11 +115,15 @@ void snd_soc_runtime_deactivate(struct snd_soc_pcm_runtime *rtd, int stream)
>    */
>   bool snd_soc_runtime_ignore_pmdown_time(struct snd_soc_pcm_runtime *rtd)
>   {
> +	int i, ignore = 0;

The default value for ignore needs to be 1. Also maybe make ignore a bool 
(and default true).

> +
>   	if (!rtd->pmdown_time || rtd->dai_link->ignore_pmdown_time)
>   		return true;
>
> -	return rtd->cpu_dai->component->ignore_pmdown_time &&
> -			rtd->codec_dai->component->ignore_pmdown_time;
> +	for (i = 0; (i < rtd->num_codecs) && !ignore; i++)
> +		ignore &= rtd->codec_dais[i]->component->ignore_pmdown_time;
> +
> +	return rtd->cpu_dai->component->ignore_pmdown_time && ignore;
>   }
>
>   /**
> @@ -309,14 +334,21 @@ static void soc_pcm_apply_msb(struct snd_pcm_substream *substream)
>   {
>   	struct snd_soc_pcm_runtime *rtd = substream->private_data;
>   	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
> -	struct snd_soc_dai *codec_dai = rtd->codec_dai;
> +	struct snd_soc_dai *codec_dai;
> +	int i;
>   	unsigned int bits = 0, cpu_bits;
>
>   	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
> -		bits = codec_dai->driver->playback.sig_bits;
> +		for (i = 0; i < rtd->num_codecs; i++) {
> +			codec_dai = rtd->codec_dais[i];
> +			bits = max(codec_dai->driver->playback.sig_bits, bits);
> +		}

This ignores one important thing. A sig_bits value of 0 means no 
restrictions. Which means that if at least one codec as a sig_bits value of 
0 the overall value should be 0 as well.

Something like
for (i = 0; i < rtd->num_codecs; i++) {
	codec_dai = rtd->codec_dais[i];
	if (codec_dai->driver->playback.sig_bits == 0) {
		bits = 0;
		break;
	}
	bits = max(codec_dai->driver->playback.sig_bits, bits);
}



>   		cpu_bits = cpu_dai->driver->playback.sig_bits;
>   	} else {
> -		bits = codec_dai->driver->capture.sig_bits;
> +		for (i = 0; i < rtd->num_codecs; i++) {
> +			codec_dai = rtd->codec_dais[i];
> +			bits = max(codec_dai->driver->capture.sig_bits, bits);
> +		}
>   		cpu_bits = cpu_dai->driver->capture.sig_bits;
>   	}
>
> @@ -324,32 +356,65 @@ static void soc_pcm_apply_msb(struct snd_pcm_substream *substream)
>   	soc_pcm_set_msb(substream, cpu_dai, cpu_bits);

I'm getting a warning here from the compiler that codec_dai might be 
uninitialized. It won't be since num_codecs > 0, but the compiler does not 
know that, maybe you can restructure this to avoid the warning.

>   }
>
[...]


> +	for (i = 0; i < rtd->num_codecs; i++) {
> +		struct snd_soc_dai *codec_dai = rtd->codec_dais[i];
> +		struct snd_pcm_hw_params codec_params;

> +
> +		/* copy params for each codec */
> +		memcpy(&codec_params, params, sizeof(struct snd_pcm_hw_params));

Just codec_params = *params, this is generally preferred over memcpy since 
it is type safe.

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH v4 5/8] ASoC: dapm: Add support for DAI multicodec
  2014-07-01  7:47 ` [PATCH v4 5/8] ASoC: dapm: " Benoit Cousson
@ 2014-07-01 13:40   ` Lars-Peter Clausen
  0 siblings, 0 replies; 43+ messages in thread
From: Lars-Peter Clausen @ 2014-07-01 13:40 UTC (permalink / raw)
  To: Benoit Cousson, broonie, lgirdwood
  Cc: Fabien Parent, misael.lopez, alsa-devel

On 07/01/2014 09:47 AM, Benoit Cousson wrote:
> Add multicodec support in soc-dapm.c
>
> Signed-off-by: Benoit Cousson <bcousson@baylibre.com>
> Signed-off-by: Misael Lopez Cruz <misael.lopez@ti.com>
> Signed-off-by: Fabien Parent <fparent@baylibre.com>

Reviewed-by: Lars-Peter Clausen <lars@metafoo.de>

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH v4 8/8] ASoC: core: Add a warning for link_dai_widget in the multicodec case
  2014-07-01  7:48 ` [PATCH v4 8/8] ASoC: core: Add a warning for link_dai_widget in the multicodec case Benoit Cousson
@ 2014-07-01 13:41   ` Lars-Peter Clausen
  0 siblings, 0 replies; 43+ messages in thread
From: Lars-Peter Clausen @ 2014-07-01 13:41 UTC (permalink / raw)
  To: Benoit Cousson, broonie, lgirdwood; +Cc: misael.lopez, alsa-devel

On 07/01/2014 09:48 AM, Benoit Cousson wrote:
> Multicodec links are not supported in the case of CODEC to CODEC links.
> Just print a warning if it happens.
>
> Signed-off-by: Benoit Cousson <bcousson@baylibre.com>

This looks good, by maybe just squash it into the other patch that updates 
soc-core.c

> ---
>   sound/soc/soc-core.c | 3 +++
>   1 file changed, 3 insertions(+)
>
> diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
> index 3764150..3640242 100644
> --- a/sound/soc/soc-core.c
> +++ b/sound/soc/soc-core.c
> @@ -1486,6 +1486,9 @@ static int soc_link_dai_widgets(struct snd_soc_card *card,
>   	struct snd_soc_dapm_widget *play_w, *capture_w;
>   	int ret;
>
> +	if (rtd->num_codecs > 1)
> +		dev_warn(card->dev, "ASoC: Multiple codecs not supported yet\n");
> +
>   	/* link the DAI widgets */
>   	play_w = codec_dai->playback_widget;
>   	capture_w = cpu_dai->capture_widget;
>

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH v4 7/8] ASoC: pcm: Add soc_dai_hw_params helper
  2014-07-01  7:48 ` [PATCH v4 7/8] ASoC: pcm: Add soc_dai_hw_params helper Benoit Cousson
@ 2014-07-01 13:43   ` Lars-Peter Clausen
  0 siblings, 0 replies; 43+ messages in thread
From: Lars-Peter Clausen @ 2014-07-01 13:43 UTC (permalink / raw)
  To: Benoit Cousson, broonie, lgirdwood; +Cc: misael.lopez, alsa-devel

On 07/01/2014 09:48 AM, Benoit Cousson wrote:
> Add a function helper to factorize the hw_params code.
>
> Suggested by Lars-Peter Clausen <lars@metafoo.de>
>
> Signed-off-by: Benoit Cousson <bcousson@baylibre.com>
> ---
>   include/sound/soc.h  |  4 ++++
>   sound/soc/soc-dapm.c | 26 ++++++--------------------
>   sound/soc/soc-pcm.c  | 41 ++++++++++++++++++++++-------------------
>   3 files changed, 32 insertions(+), 39 deletions(-)
>
> diff --git a/include/sound/soc.h b/include/sound/soc.h
> index f2142cf..98555f8 100644
> --- a/include/sound/soc.h
> +++ b/include/sound/soc.h
> @@ -436,6 +436,10 @@ int snd_soc_set_runtime_hwparams(struct snd_pcm_substream *substream,
>   int snd_soc_platform_trigger(struct snd_pcm_substream *substream,
>   		int cmd, struct snd_soc_platform *platform);
>
> +int soc_dai_hw_params(struct snd_pcm_substream *substream,
> +		      struct snd_pcm_hw_params *params,
> +		      struct snd_soc_dai *dai);
> +
>   /* Jack reporting */
>   int snd_soc_jack_new(struct snd_soc_codec *codec, const char *id, int type,
>   		     struct snd_soc_jack *jack);
> diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
> index 5c63c3b..d8a24bb 100644
> --- a/sound/soc/soc-dapm.c
> +++ b/sound/soc/soc-dapm.c
> @@ -3214,27 +3214,13 @@ static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w,
>
>   	switch (event) {
>   	case SND_SOC_DAPM_PRE_PMU:
> -		if (source->driver->ops && source->driver->ops->hw_params) {
> -			substream.stream = SNDRV_PCM_STREAM_CAPTURE;
> -			ret = source->driver->ops->hw_params(&substream,
> -							     params, source);
> -			if (ret != 0) {
> -				dev_err(source->dev,
> -					"ASoC: hw_params() failed: %d\n", ret);
> -				goto out;
> -			}
> -		}
> +		substream.stream = SNDRV_PCM_STREAM_CAPTURE;
> +		if (soc_dai_hw_params(&substream, params, source) < 0)
> +			goto out;

ret = ...
if (ret < 0)
	goto out;

This should also fix the compiler warning about using ret uninitialized.

Same comment for the other places in this patch that do the same.

>
> -		if (sink->driver->ops && sink->driver->ops->hw_params) {
> -			substream.stream = SNDRV_PCM_STREAM_PLAYBACK;
> -			ret = sink->driver->ops->hw_params(&substream, params,
> -							   sink);
> -			if (ret != 0) {
> -				dev_err(sink->dev,
> -					"ASoC: hw_params() failed: %d\n", ret);
> -				goto out;
> -			}
> -		}
> +		substream.stream = SNDRV_PCM_STREAM_PLAYBACK;
> +		if (soc_dai_hw_params(&substream, params, sink) < 0)
> +			goto out;
>   		break;
>

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH v4 6/8] ASoC: compress: Add support for DAI multicodec
  2014-07-01  7:47 ` [PATCH v4 6/8] ASoC: compress: " Benoit Cousson
@ 2014-07-01 13:49   ` Lars-Peter Clausen
  2014-07-01 16:25     ` Vinod Koul
  2014-07-01 16:41   ` Vinod Koul
  1 sibling, 1 reply; 43+ messages in thread
From: Lars-Peter Clausen @ 2014-07-01 13:49 UTC (permalink / raw)
  To: Benoit Cousson, broonie, lgirdwood; +Cc: Vinod Koul, misael.lopez, alsa-devel

On 07/01/2014 09:47 AM, Benoit Cousson wrote:
[...]
for (i = 0; i < rtd->num_codecs; i++) {
> +		struct snd_soc_dai *codec_dai = rtd->codec_dais[i];
> +		/* check client and interface hw capabilities */
> +		snprintf(new_name, sizeof(new_name), "%s %s-%d",
> +			 rtd->dai_link->stream_name, codec_dai->name, num);

We may need to rethink how to do the naming for multiple CODEC DAI links 
here. This implementation will just keep overwriting new_name with each loop 
iteration and end up using the last one. Vinod may have some insights.

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH v4 6/8] ASoC: compress: Add support for DAI multicodec
  2014-07-01 13:49   ` Lars-Peter Clausen
@ 2014-07-01 16:25     ` Vinod Koul
  2014-07-01 16:42       ` Lars-Peter Clausen
  2014-07-01 17:32       ` Benoit Cousson
  0 siblings, 2 replies; 43+ messages in thread
From: Vinod Koul @ 2014-07-01 16:25 UTC (permalink / raw)
  To: Lars-Peter Clausen
  Cc: alsa-devel, misael.lopez, broonie, lgirdwood, Benoit Cousson

On Tue, Jul 01, 2014 at 03:49:51PM +0200, Lars-Peter Clausen wrote:
> On 07/01/2014 09:47 AM, Benoit Cousson wrote:
And you should have cced me on this patch

> [...]
> for (i = 0; i < rtd->num_codecs; i++) {
> >+		struct snd_soc_dai *codec_dai = rtd->codec_dais[i];
> >+		/* check client and interface hw capabilities */
> >+		snprintf(new_name, sizeof(new_name), "%s %s-%d",
> >+			 rtd->dai_link->stream_name, codec_dai->name, num);
> 
> We may need to rethink how to do the naming for multiple CODEC DAI
> links here. This implementation will just keep overwriting new_name
> with each loop iteration and end up using the last one. Vinod may
> have some insights.

I am intrugued on how we do this for pcms with multi-codec support.

Looking at the patch series I dont think the soc_pcm_new() has been updated
(please point out if i missed, it is late in night)
Shouldnt this be updated for pcm too?

I would suggest makes sense is to keep appending the codec name for the
dai-link. But yes keep a check on the size. Unless we have better ideas.

-- 
~Vinod

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH v4 6/8] ASoC: compress: Add support for DAI multicodec
  2014-07-01  7:47 ` [PATCH v4 6/8] ASoC: compress: " Benoit Cousson
  2014-07-01 13:49   ` Lars-Peter Clausen
@ 2014-07-01 16:41   ` Vinod Koul
  2014-07-01 17:41     ` Mark Brown
  2014-07-02 12:53     ` Benoit Cousson
  1 sibling, 2 replies; 43+ messages in thread
From: Vinod Koul @ 2014-07-01 16:41 UTC (permalink / raw)
  To: Benoit Cousson; +Cc: alsa-devel, misael.lopez, broonie, lgirdwood, lars

On Tue, Jul 01, 2014 at 09:47:59AM +0200, Benoit Cousson wrote:
> Add multicodec support in soc-compress.c
> 
> @@ -294,13 +299,19 @@ static int soc_compr_trigger(struct snd_compr_stream *cstream, int cmd)
>  			goto out;
>  	}
>  
> -	switch (cmd) {
> -	case SNDRV_PCM_TRIGGER_START:
> -		snd_soc_dai_digital_mute(codec_dai, 0, cstream->direction);
> -		break;
> -	case SNDRV_PCM_TRIGGER_STOP:
> -		snd_soc_dai_digital_mute(codec_dai, 1, cstream->direction);
> -		break;
> +	for (i = 0; i < rtd->num_codecs; i++) {
> +		struct snd_soc_dai *codec_dai = rtd->codec_dais[i];
> +
> +		switch (cmd) {
> +		case SNDRV_PCM_TRIGGER_START:
> +			snd_soc_dai_digital_mute(codec_dai, 0,
> +						 cstream->direction);
> +			break;
> +		case SNDRV_PCM_TRIGGER_STOP:
> +			snd_soc_dai_digital_mute(codec_dai, 1,
> +						 cstream->direction);
Wouldnt it make sense to fix snd_soc_dai_digital_mute() for multi-codecs. Did
you do same thing for pcm?

> +			break;
> +		}
>  	}
>  
>  out:
> @@ -622,23 +633,33 @@ int soc_new_compress(struct snd_soc_pcm_runtime *rtd, int num)
>  {
>  	struct snd_soc_codec *codec = rtd->codec;
>  	struct snd_soc_platform *platform = rtd->platform;
> -	struct snd_soc_dai *codec_dai = rtd->codec_dai;
>  	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
>  	struct snd_compr *compr;
>  	struct snd_pcm *be_pcm;
>  	char new_name[64];
> -	int ret = 0, direction = 0;
> -
> -	/* check client and interface hw capabilities */
> -	snprintf(new_name, sizeof(new_name), "%s %s-%d",
> -			rtd->dai_link->stream_name, codec_dai->name, num);
> -
> -	if (codec_dai->driver->playback.channels_min)
> -		direction = SND_COMPRESS_PLAYBACK;
> -	else if (codec_dai->driver->capture.channels_min)
> -		direction = SND_COMPRESS_CAPTURE;
> -	else
> -		return -EINVAL;
> +	int i, ret = 0, direction = -1;
> +
> +	for (i = 0; i < rtd->num_codecs; i++) {
> +		struct snd_soc_dai *codec_dai = rtd->codec_dais[i];
> +		/* check client and interface hw capabilities */
> +		snprintf(new_name, sizeof(new_name), "%s %s-%d",
> +			 rtd->dai_link->stream_name, codec_dai->name, num);
> +
> +		if (direction < 0) {
> +			if (codec_dai->driver->playback.channels_min)
> +				direction = SND_COMPRESS_PLAYBACK;
> +			else if (codec_dai->driver->capture.channels_min)
> +				direction = SND_COMPRESS_CAPTURE;
direction wont change with multiple codecs, so this loop makes no sense here.
For simplcity perhaps we can use cpu_dai?
> +			else
> +				return -EINVAL;
> +		} else {
when will this get executed? You have initialized direction to -1 and if case is
always true. I think compiler will simply remove the below sinppet.
> +			if ((codec_dai->driver->playback.channels_min &&
> +					direction != SND_COMPRESS_PLAYBACK) ||
> +			    (codec_dai->driver->capture.channels_min &&
> +					direction != SND_COMPRESS_CAPTURE))
and what exactly are we trying to check here?
> +				return -EINVAL;
> +		}
> +	}
>  
>  	compr = kzalloc(sizeof(*compr), GFP_KERNEL);
>  	if (compr == NULL) {
> @@ -692,8 +713,11 @@ int soc_new_compress(struct snd_soc_pcm_runtime *rtd, int num)
>  	rtd->compr = compr;
>  	compr->private_data = rtd;
>  
> -	printk(KERN_INFO "compress asoc: %s <-> %s mapping ok\n", codec_dai->name,
> -		cpu_dai->name);
> +	for (i = 0; i < rtd->num_codecs; i++) {
> +		struct snd_soc_dai *codec_dai = rtd->codec_dais[i];
> +		printk(KERN_INFO "compress asoc: %s <-> %s mapping ok\n",
> +		       codec_dai->name, cpu_dai->name);
wrong again. You are not creating multiple links with multi-codec. Link is still
single.

-- 
~Vinod

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH v4 6/8] ASoC: compress: Add support for DAI multicodec
  2014-07-01 16:25     ` Vinod Koul
@ 2014-07-01 16:42       ` Lars-Peter Clausen
  2014-07-01 16:45         ` Vinod Koul
  2014-07-01 17:32       ` Benoit Cousson
  1 sibling, 1 reply; 43+ messages in thread
From: Lars-Peter Clausen @ 2014-07-01 16:42 UTC (permalink / raw)
  To: Vinod Koul; +Cc: alsa-devel, misael.lopez, broonie, lgirdwood, Benoit Cousson

On 07/01/2014 06:25 PM, Vinod Koul wrote:
> On Tue, Jul 01, 2014 at 03:49:51PM +0200, Lars-Peter Clausen wrote:
>> On 07/01/2014 09:47 AM, Benoit Cousson wrote:
> And you should have cced me on this patch
>
>> [...]
>> for (i = 0; i < rtd->num_codecs; i++) {
>>> +		struct snd_soc_dai *codec_dai = rtd->codec_dais[i];
>>> +		/* check client and interface hw capabilities */
>>> +		snprintf(new_name, sizeof(new_name), "%s %s-%d",
>>> +			 rtd->dai_link->stream_name, codec_dai->name, num);
>>
>> We may need to rethink how to do the naming for multiple CODEC DAI
>> links here. This implementation will just keep overwriting new_name
>> with each loop iteration and end up using the last one. Vinod may
>> have some insights.
>
> I am intrugued on how we do this for pcms with multi-codec support.
>
> Looking at the patch series I dont think the soc_pcm_new() has been updated
> (please point out if i missed, it is late in night)
> Shouldnt this be updated for pcm too?
>
> I would suggest makes sense is to keep appending the codec name for the
> dai-link. But yes keep a check on the size. Unless we have better ideas.
>

This is what the patch series does for normal PCMs

  	snprintf(new_name, sizeof(new_name), "%s %s-%d",
-		rtd->dai_link->stream_name, codec_dai->name, num);
+		rtd->dai_link->stream_name,
+		(rtd->num_codecs > 1) ?
+		"multicodec" : rtd->codec_dai->name, num);

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH v4 6/8] ASoC: compress: Add support for DAI multicodec
  2014-07-01 16:42       ` Lars-Peter Clausen
@ 2014-07-01 16:45         ` Vinod Koul
  0 siblings, 0 replies; 43+ messages in thread
From: Vinod Koul @ 2014-07-01 16:45 UTC (permalink / raw)
  To: Lars-Peter Clausen
  Cc: alsa-devel, misael.lopez, broonie, lgirdwood, Benoit Cousson

On Tue, Jul 01, 2014 at 06:42:12PM +0200, Lars-Peter Clausen wrote:
> On 07/01/2014 06:25 PM, Vinod Koul wrote:
> >On Tue, Jul 01, 2014 at 03:49:51PM +0200, Lars-Peter Clausen wrote:
> >>On 07/01/2014 09:47 AM, Benoit Cousson wrote:
> >And you should have cced me on this patch
> >
> >>[...]
> >>for (i = 0; i < rtd->num_codecs; i++) {
> >>>+		struct snd_soc_dai *codec_dai = rtd->codec_dais[i];
> >>>+		/* check client and interface hw capabilities */
> >>>+		snprintf(new_name, sizeof(new_name), "%s %s-%d",
> >>>+			 rtd->dai_link->stream_name, codec_dai->name, num);
> >>
> >>We may need to rethink how to do the naming for multiple CODEC DAI
> >>links here. This implementation will just keep overwriting new_name
> >>with each loop iteration and end up using the last one. Vinod may
> >>have some insights.
> >
> >I am intrugued on how we do this for pcms with multi-codec support.
> >
> >Looking at the patch series I dont think the soc_pcm_new() has been updated
> >(please point out if i missed, it is late in night)
> >Shouldnt this be updated for pcm too?
> >
> >I would suggest makes sense is to keep appending the codec name for the
> >dai-link. But yes keep a check on the size. Unless we have better ideas.
> >
> 
> This is what the patch series does for normal PCMs
> 
>  	snprintf(new_name, sizeof(new_name), "%s %s-%d",
> -		rtd->dai_link->stream_name, codec_dai->name, num);
> +		rtd->dai_link->stream_name,
> +		(rtd->num_codecs > 1) ?
> +		"multicodec" : rtd->codec_dai->name, num);
Sounds good to me!

-- 
~Vinod

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH v4 1/8] ASoC: core: Change soc_link_dai_widgets signature for multiple codecs
  2014-07-01  7:47 ` [PATCH v4 1/8] ASoC: core: Change soc_link_dai_widgets signature for multiple codecs Benoit Cousson
@ 2014-07-01 17:17   ` Mark Brown
  2014-07-04 16:13     ` Benoit Cousson
  0 siblings, 1 reply; 43+ messages in thread
From: Mark Brown @ 2014-07-01 17:17 UTC (permalink / raw)
  To: Benoit Cousson; +Cc: misael.lopez, lars, lgirdwood, alsa-devel


[-- Attachment #1.1: Type: text/plain, Size: 284 bytes --]

On Tue, Jul 01, 2014 at 09:47:54AM +0200, Benoit Cousson wrote:
> Since multiple codecs DAI will be usable in the future, remove
> explicit unique codec_dai and cpu_dai parameters.
> Replace them with snd_soc_pcm_runtime pointer that will contain
> every instances.

Applied, thanks.

[-- Attachment #1.2: Digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

[-- Attachment #2: Type: text/plain, Size: 0 bytes --]



^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH v4 2/8] ASoC: pcm: Refactor soc_pcm_apply_msb for multicodecs
  2014-07-01  7:47 ` [PATCH v4 2/8] ASoC: pcm: Refactor soc_pcm_apply_msb for multicodecs Benoit Cousson
@ 2014-07-01 17:20   ` Mark Brown
  2014-07-01 17:31     ` Benoit Cousson
  0 siblings, 1 reply; 43+ messages in thread
From: Mark Brown @ 2014-07-01 17:20 UTC (permalink / raw)
  To: Benoit Cousson; +Cc: misael.lopez, lars, lgirdwood, alsa-devel


[-- Attachment #1.1: Type: text/plain, Size: 352 bytes --]

On Tue, Jul 01, 2014 at 09:47:55AM +0200, Benoit Cousson wrote:
> Refactor the function to facilitate the migration to
> multiple codecs.

Applied, thanks.

> Fix a trailing space in the header as well.

Please don't do things like this if they're not in a part of the code
being changed, it makes review a bit harder.  A separate patch would be
fine.

[-- Attachment #1.2: Digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

[-- Attachment #2: Type: text/plain, Size: 0 bytes --]



^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH v4 3/8] ASoC: core: Add initial support for DAI multicodec
  2014-07-01 13:19   ` Lars-Peter Clausen
@ 2014-07-01 17:27     ` Benoit Cousson
  0 siblings, 0 replies; 43+ messages in thread
From: Benoit Cousson @ 2014-07-01 17:27 UTC (permalink / raw)
  To: Lars-Peter Clausen, broonie, lgirdwood
  Cc: Fabien Parent, misael.lopez, alsa-devel

Hi Lars,

On 01/07/2014 15:19, Lars-Peter Clausen wrote:
> On 07/01/2014 09:47 AM, Benoit Cousson wrote:
>> DAI link assumes a one to one mapping between CPU DAI and CODEC. In
>> some cases, the same CPU DAI can be connected to several codecs.
>> This is the case for example, if you connect two mono codecs to the
>> same I2S link in order to have a stereo card.
>> The current ASoC implementation does not allow such setup.
>>
>> Add support for DAI links composed of a single CPU DAI and multiple
>> CODECs. Sound cards have to pass the CODECs array in the corresponding
>> DAI link through a new 'snd_soc_dai_link_component' struct. Each CODEC in
>> this array is described in the same manner single CODEC DAIs are
>> (either DT/OF node or codec_name).
>>
>> Based on an original code done by Misael.
>>
>> Signed-off-by: Benoit Cousson <bcousson@baylibre.com>
>> Signed-off-by: Misael Lopez Cruz <misael.lopez@ti.com>
>> Signed-off-by: Fabien Parent <fparent@baylibre.com>
>
> Almost. There are two more serious issues, the rest is trivial.

Gosh... Another new update to do :-)
I'll try to be faster this time...

>> ---
> [...]
>> diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
>> index 37a965c..3764150 100644
>> --- a/sound/soc/soc-core.c
>> +++ b/sound/soc/soc-core.c
>> @@ -554,7 +554,7 @@ int snd_soc_suspend(struct device *dev)
>>   {
>>       struct snd_soc_card *card = dev_get_drvdata(dev);
>>       struct snd_soc_codec *codec;
>> -    int i;
>> +    int i, j;
>>
>>       /* If the initialization of this soc device failed, there is no
>> codec
>>        * associated with it. Just bail out in this case.
>> @@ -574,14 +574,16 @@ int snd_soc_suspend(struct device *dev)
>>
>>       /* mute any active DACs */
>>       for (i = 0; i < card->num_rtd; i++) {
>> -        struct snd_soc_dai *dai = card->rtd[i].codec_dai;
>> -        struct snd_soc_dai_driver *drv = dai->driver;
>> +        for (j = 0; j < card->rtd[i].num_codecs; j++) {
>> +            struct snd_soc_dai *dai = card->rtd[i].codec_dais[j];
>> +            struct snd_soc_dai_driver *drv = dai->driver;
>>
>> -        if (card->rtd[i].dai_link->ignore_suspend)
>> -            continue;
>> +            if (card->rtd[i].dai_link->ignore_suspend)
>> +                continue;
>
> This check can actually stay outside the inner loop. We either want to
> mute all or none.

Indeed.

>
>>
>> -        if (drv->ops->digital_mute && dai->playback_active)
>> -            drv->ops->digital_mute(dai, 1);
>> +            if (drv->ops->digital_mute && dai->playback_active)
>> +                drv->ops->digital_mute(dai, 1);
>> +        }
>>       }
>>
>>       /* suspend all pcms */
> [...]
>> @@ -697,7 +703,7 @@ static void soc_resume_deferred(struct work_struct
>> *work)
>>       struct snd_soc_card *card =
>>               container_of(work, struct snd_soc_card,
>> deferred_resume_work);
>>       struct snd_soc_codec *codec;
>> -    int i;
>> +    int i, j;
>>
>>       /* our power state is still SNDRV_CTL_POWER_D3hot from suspend
>> time,
>>        * so userspace apps are blocked from touching us
>> @@ -758,14 +764,17 @@ static void soc_resume_deferred(struct
>> work_struct *work)
>>
>>       /* unmute any active DACs */
>>       for (i = 0; i < card->num_rtd; i++) {
>> -        struct snd_soc_dai *dai = card->rtd[i].codec_dai;
>> -        struct snd_soc_dai_driver *drv = dai->driver;
>>
>> -        if (card->rtd[i].dai_link->ignore_suspend)
>> -            continue;
>> +        for (j = 0; j < card->rtd[i].num_codecs; j++) {
>> +            struct snd_soc_dai *dai = card->rtd[i].codec_dais[j];
>> +            struct snd_soc_dai_driver *drv = dai->driver;
>> +
>> +            if (card->rtd[i].dai_link->ignore_suspend)
>> +                continue;
>
> Same as with the mute loop.

OK

>
>>
>> -        if (drv->ops->digital_mute && dai->playback_active)
>> -            drv->ops->digital_mute(dai, 0);
>> +            if (drv->ops->digital_mute && dai->playback_active)
>> +                drv->ops->digital_mute(dai, 0);
>> +        }
>>       }
>>
>>       for (i = 0; i < card->num_rtd; i++) {
> [...]                int num)
>> +static int soc_aux_dev_init(struct snd_soc_card *card, int num)
>>   {
>>       struct snd_soc_aux_dev *aux_dev = &card->aux_dev[num];
>>       struct snd_soc_pcm_runtime *rtd = &card->rtd_aux[num];
>> +    struct snd_soc_codec *codec;
>>       int ret;
>>
>>       rtd->card = card;
>>
>> +    codec = soc_find_codec(NULL, aux_dev->codec_name);
>
> We actually have support for binding the aux dev by DT node now. But I
> have a patch in my componentization branch that cleans all this up. Let
> me send it to you and then you can rebase on-top of that.

OK, I guess you are talking about soc_find_matching_codec API introduced 
by Sebatian. Are you gonna merge it with the soc_find_codec API?

>
>> +    if (!codec)
>> +        return -EPROBE_DEFER;
>> +
>>       /* do machine specific initialization */
>>       if (aux_dev->init) {
>>           ret = aux_dev->init(&codec->dapm);
>> @@ -1286,16 +1316,19 @@ static int soc_aux_dev_init(struct
>> snd_soc_card *card,
>>       return 0;
>>   }
>>
>> -static int soc_dai_link_init(struct snd_soc_card *card,
>> -                 struct snd_soc_codec *codec,
>> -                 int num)
>> +static int soc_dai_link_init(struct snd_soc_card *card, int num)
>>   {
>>       struct snd_soc_dai_link *dai_link =  &card->dai_link[num];
>>       struct snd_soc_pcm_runtime *rtd = &card->rtd[num];
>> -    int ret;
>> +    int i, ret;
>>
>>       rtd->card = card;
>>
>> +    for (i = 0; i < rtd->num_codecs; i++) {
>> +        /* Make sure all DAPM widgets are instantiated */
>> +        snd_soc_dapm_new_widgets(rtd->codec_dais[i]->codec->dapm.card);
>> +    }
>
> This is still a left over from a very early revision of this patch. We
> removed this in upstream a while ago.

Oops, sorry about that :-(

Thanks,
Benoit

-- 
Benoît Cousson
BayLibre
Embedded Linux Technology Lab
www.baylibre.com

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH v4 2/8] ASoC: pcm: Refactor soc_pcm_apply_msb for multicodecs
  2014-07-01 17:20   ` Mark Brown
@ 2014-07-01 17:31     ` Benoit Cousson
  0 siblings, 0 replies; 43+ messages in thread
From: Benoit Cousson @ 2014-07-01 17:31 UTC (permalink / raw)
  To: Mark Brown; +Cc: misael.lopez, lars, lgirdwood, alsa-devel

On 01/07/2014 19:20, Mark Brown wrote:
> On Tue, Jul 01, 2014 at 09:47:55AM +0200, Benoit Cousson wrote:
>> Refactor the function to facilitate the migration to
>> multiple codecs.
>
> Applied, thanks.
>
>> Fix a trailing space in the header as well.
>
> Please don't do things like this if they're not in a part of the code
> being changed, it makes review a bit harder.  A separate patch would be
> fine.

OK, sorry about that. I'll not do it again.

Thanks,
Benoit

-- 
Benoît Cousson
BayLibre
Embedded Linux Technology Lab
www.baylibre.com

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH v4 6/8] ASoC: compress: Add support for DAI multicodec
  2014-07-01 16:25     ` Vinod Koul
  2014-07-01 16:42       ` Lars-Peter Clausen
@ 2014-07-01 17:32       ` Benoit Cousson
  1 sibling, 0 replies; 43+ messages in thread
From: Benoit Cousson @ 2014-07-01 17:32 UTC (permalink / raw)
  To: Vinod Koul, Lars-Peter Clausen
  Cc: misael.lopez, broonie, lgirdwood, alsa-devel

On 01/07/2014 18:25, Vinod Koul wrote:
> On Tue, Jul 01, 2014 at 03:49:51PM +0200, Lars-Peter Clausen wrote:
>> On 07/01/2014 09:47 AM, Benoit Cousson wrote:
> And you should have cced me on this patch

Sorry, my mistake. I'll add you for the next release.

Regards,
Benoit

>
>> [...]
>> for (i = 0; i < rtd->num_codecs; i++) {
>>> +		struct snd_soc_dai *codec_dai = rtd->codec_dais[i];
>>> +		/* check client and interface hw capabilities */
>>> +		snprintf(new_name, sizeof(new_name), "%s %s-%d",
>>> +			 rtd->dai_link->stream_name, codec_dai->name, num);
>>
>> We may need to rethink how to do the naming for multiple CODEC DAI
>> links here. This implementation will just keep overwriting new_name
>> with each loop iteration and end up using the last one. Vinod may
>> have some insights.
>
> I am intrugued on how we do this for pcms with multi-codec support.
>
> Looking at the patch series I dont think the soc_pcm_new() has been updated
> (please point out if i missed, it is late in night)
> Shouldnt this be updated for pcm too?
>
> I would suggest makes sense is to keep appending the codec name for the
> dai-link. But yes keep a check on the size. Unless we have better ideas.
>


-- 
Benoît Cousson
BayLibre
Embedded Linux Technology Lab
www.baylibre.com

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH v4 6/8] ASoC: compress: Add support for DAI multicodec
  2014-07-01 16:41   ` Vinod Koul
@ 2014-07-01 17:41     ` Mark Brown
  2014-07-03  6:39       ` Vinod Koul
  2014-07-02 12:53     ` Benoit Cousson
  1 sibling, 1 reply; 43+ messages in thread
From: Mark Brown @ 2014-07-01 17:41 UTC (permalink / raw)
  To: Vinod Koul; +Cc: alsa-devel, misael.lopez, lars, lgirdwood, Benoit Cousson


[-- Attachment #1.1: Type: text/plain, Size: 827 bytes --]

On Tue, Jul 01, 2014 at 10:11:34PM +0530, Vinod Koul wrote:
> On Tue, Jul 01, 2014 at 09:47:59AM +0200, Benoit Cousson wrote:

> > +	for (i = 0; i < rtd->num_codecs; i++) {
> > +		struct snd_soc_dai *codec_dai = rtd->codec_dais[i];
> > +
> > +		switch (cmd) {
> > +		case SNDRV_PCM_TRIGGER_START:
> > +			snd_soc_dai_digital_mute(codec_dai, 0,
> > +						 cstream->direction);
> > +			break;
> > +		case SNDRV_PCM_TRIGGER_STOP:
> > +			snd_soc_dai_digital_mute(codec_dai, 1,
> > +						 cstream->direction);

> Wouldnt it make sense to fix snd_soc_dai_digital_mute() for multi-codecs. Did
> you do same thing for pcm?

Yes, the other callers also iterate through all the CODECs.  It might be
sensible to have a wrapper which does the iteration but I do think it's
reasonable for _dai_digital_mute() to just operate on one DAI.

[-- Attachment #1.2: Digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

[-- Attachment #2: Type: text/plain, Size: 0 bytes --]



^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH v4 6/8] ASoC: compress: Add support for DAI multicodec
  2014-07-01 16:41   ` Vinod Koul
  2014-07-01 17:41     ` Mark Brown
@ 2014-07-02 12:53     ` Benoit Cousson
  2014-07-03  6:41       ` Vinod Koul
  1 sibling, 1 reply; 43+ messages in thread
From: Benoit Cousson @ 2014-07-02 12:53 UTC (permalink / raw)
  To: Vinod Koul; +Cc: alsa-devel, misael.lopez, broonie, lgirdwood, lars

On 01/07/2014 18:41, Vinod Koul wrote:
> On Tue, Jul 01, 2014 at 09:47:59AM +0200, Benoit Cousson wrote:
>> Add multicodec support in soc-compress.c
>>
>> @@ -294,13 +299,19 @@ static int soc_compr_trigger(struct snd_compr_stream *cstream, int cmd)
>>   			goto out;
>>   	}
>>
>> -	switch (cmd) {
>> -	case SNDRV_PCM_TRIGGER_START:
>> -		snd_soc_dai_digital_mute(codec_dai, 0, cstream->direction);
>> -		break;
>> -	case SNDRV_PCM_TRIGGER_STOP:
>> -		snd_soc_dai_digital_mute(codec_dai, 1, cstream->direction);
>> -		break;
>> +	for (i = 0; i < rtd->num_codecs; i++) {
>> +		struct snd_soc_dai *codec_dai = rtd->codec_dais[i];
>> +
>> +		switch (cmd) {
>> +		case SNDRV_PCM_TRIGGER_START:
>> +			snd_soc_dai_digital_mute(codec_dai, 0,
>> +						 cstream->direction);
>> +			break;
>> +		case SNDRV_PCM_TRIGGER_STOP:
>> +			snd_soc_dai_digital_mute(codec_dai, 1,
>> +						 cstream->direction);
> Wouldnt it make sense to fix snd_soc_dai_digital_mute() for multi-codecs. Did
> you do same thing for pcm?

What do you mean by fix for multi-codecs?

>
>> +			break;
>> +		}
>>   	}
>>
>>   out:
>> @@ -622,23 +633,33 @@ int soc_new_compress(struct snd_soc_pcm_runtime *rtd, int num)
>>   {
>>   	struct snd_soc_codec *codec = rtd->codec;
>>   	struct snd_soc_platform *platform = rtd->platform;
>> -	struct snd_soc_dai *codec_dai = rtd->codec_dai;
>>   	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
>>   	struct snd_compr *compr;
>>   	struct snd_pcm *be_pcm;
>>   	char new_name[64];
>> -	int ret = 0, direction = 0;
>> -
>> -	/* check client and interface hw capabilities */
>> -	snprintf(new_name, sizeof(new_name), "%s %s-%d",
>> -			rtd->dai_link->stream_name, codec_dai->name, num);
>> -
>> -	if (codec_dai->driver->playback.channels_min)
>> -		direction = SND_COMPRESS_PLAYBACK;
>> -	else if (codec_dai->driver->capture.channels_min)
>> -		direction = SND_COMPRESS_CAPTURE;
>> -	else
>> -		return -EINVAL;
>> +	int i, ret = 0, direction = -1;
>> +
>> +	for (i = 0; i < rtd->num_codecs; i++) {
>> +		struct snd_soc_dai *codec_dai = rtd->codec_dais[i];
>> +		/* check client and interface hw capabilities */
>> +		snprintf(new_name, sizeof(new_name), "%s %s-%d",
>> +			 rtd->dai_link->stream_name, codec_dai->name, num);
>> +
>> +		if (direction < 0) {
>> +			if (codec_dai->driver->playback.channels_min)
>> +				direction = SND_COMPRESS_PLAYBACK;
>> +			else if (codec_dai->driver->capture.channels_min)
>> +				direction = SND_COMPRESS_CAPTURE;
> direction wont change with multiple codecs, so this loop makes no sense here.
> For simplcity perhaps we can use cpu_dai?
>> +			else
>> +				return -EINVAL;
>> +		} else {
> when will this get executed? You have initialized direction to -1 and if case is
> always true. I think compiler will simply remove the below sinppet.

direction is set to -1, then the first iteration will set it to the 
direction of the first codec_dai. The other iteration are just checking 
that there are all in the same direction and will fail otherwise.

>> +			if ((codec_dai->driver->playback.channels_min &&
>> +					direction != SND_COMPRESS_PLAYBACK) ||
>> +			    (codec_dai->driver->capture.channels_min &&
>> +					direction != SND_COMPRESS_CAPTURE))
> and what exactly are we trying to check here?

That every codec_dai are in the same direction.

If you think this is pointless since every DAI are always in the same 
direction, we can just remove it.

>> +				return -EINVAL;
>> +		}
>> +	}
>>
>>   	compr = kzalloc(sizeof(*compr), GFP_KERNEL);
>>   	if (compr == NULL) {
>> @@ -692,8 +713,11 @@ int soc_new_compress(struct snd_soc_pcm_runtime *rtd, int num)
>>   	rtd->compr = compr;
>>   	compr->private_data = rtd;
>>
>> -	printk(KERN_INFO "compress asoc: %s <-> %s mapping ok\n", codec_dai->name,
>> -		cpu_dai->name);
>> +	for (i = 0; i < rtd->num_codecs; i++) {
>> +		struct snd_soc_dai *codec_dai = rtd->codec_dais[i];
>> +		printk(KERN_INFO "compress asoc: %s <-> %s mapping ok\n",
>> +		       codec_dai->name, cpu_dai->name);
> wrong again. You are not creating multiple links with multi-codec. Link is still
> single.

Yeah, I know, the idea was to print that we have multiple codec. I'll 
use the same "multicodec" info like we did for PCM.

Thanks for the feedback,
Benoit

-- 
Benoît Cousson
BayLibre
Embedded Linux Technology Lab
www.baylibre.com

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH v4 6/8] ASoC: compress: Add support for DAI multicodec
  2014-07-01 17:41     ` Mark Brown
@ 2014-07-03  6:39       ` Vinod Koul
  0 siblings, 0 replies; 43+ messages in thread
From: Vinod Koul @ 2014-07-03  6:39 UTC (permalink / raw)
  To: Mark Brown; +Cc: alsa-devel, lars, misael.lopez, Benoit Cousson, lgirdwood


[-- Attachment #1.1: Type: text/plain, Size: 996 bytes --]

On Tue, Jul 01, 2014 at 06:41:17PM +0100, Mark Brown wrote:
> On Tue, Jul 01, 2014 at 10:11:34PM +0530, Vinod Koul wrote:
> > On Tue, Jul 01, 2014 at 09:47:59AM +0200, Benoit Cousson wrote:
> 
> > > +	for (i = 0; i < rtd->num_codecs; i++) {
> > > +		struct snd_soc_dai *codec_dai = rtd->codec_dais[i];
> > > +
> > > +		switch (cmd) {
> > > +		case SNDRV_PCM_TRIGGER_START:
> > > +			snd_soc_dai_digital_mute(codec_dai, 0,
> > > +						 cstream->direction);
> > > +			break;
> > > +		case SNDRV_PCM_TRIGGER_STOP:
> > > +			snd_soc_dai_digital_mute(codec_dai, 1,
> > > +						 cstream->direction);
> 
> > Wouldnt it make sense to fix snd_soc_dai_digital_mute() for multi-codecs. Did
> > you do same thing for pcm?
> 
> Yes, the other callers also iterate through all the CODECs.  It might be
> sensible to have a wrapper which does the iteration but I do think it's
> reasonable for _dai_digital_mute() to just operate on one DAI.
Yes that sounds okay as well

-- 
~Vinod

[-- Attachment #1.2: Digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

[-- Attachment #2: Type: text/plain, Size: 0 bytes --]



^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH v4 6/8] ASoC: compress: Add support for DAI multicodec
  2014-07-02 12:53     ` Benoit Cousson
@ 2014-07-03  6:41       ` Vinod Koul
  2014-07-03 11:09         ` Benoit Cousson
  0 siblings, 1 reply; 43+ messages in thread
From: Vinod Koul @ 2014-07-03  6:41 UTC (permalink / raw)
  To: Benoit Cousson; +Cc: alsa-devel, misael.lopez, broonie, lgirdwood, lars

On Wed, Jul 02, 2014 at 02:53:50PM +0200, Benoit Cousson wrote:
> >>@@ -622,23 +633,33 @@ int soc_new_compress(struct snd_soc_pcm_runtime *rtd, int num)
> >>  {
> >>  	struct snd_soc_codec *codec = rtd->codec;
> >>  	struct snd_soc_platform *platform = rtd->platform;
> >>-	struct snd_soc_dai *codec_dai = rtd->codec_dai;
> >>  	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
> >>  	struct snd_compr *compr;
> >>  	struct snd_pcm *be_pcm;
> >>  	char new_name[64];
> >>-	int ret = 0, direction = 0;
> >>-
> >>-	/* check client and interface hw capabilities */
> >>-	snprintf(new_name, sizeof(new_name), "%s %s-%d",
> >>-			rtd->dai_link->stream_name, codec_dai->name, num);
> >>-
> >>-	if (codec_dai->driver->playback.channels_min)
> >>-		direction = SND_COMPRESS_PLAYBACK;
> >>-	else if (codec_dai->driver->capture.channels_min)
> >>-		direction = SND_COMPRESS_CAPTURE;
> >>-	else
> >>-		return -EINVAL;
> >>+	int i, ret = 0, direction = -1;
> >>+
> >>+	for (i = 0; i < rtd->num_codecs; i++) {
> >>+		struct snd_soc_dai *codec_dai = rtd->codec_dais[i];
> >>+		/* check client and interface hw capabilities */
> >>+		snprintf(new_name, sizeof(new_name), "%s %s-%d",
> >>+			 rtd->dai_link->stream_name, codec_dai->name, num);
> >>+
> >>+		if (direction < 0) {
> >>+			if (codec_dai->driver->playback.channels_min)
> >>+				direction = SND_COMPRESS_PLAYBACK;
> >>+			else if (codec_dai->driver->capture.channels_min)
> >>+				direction = SND_COMPRESS_CAPTURE;
> >direction wont change with multiple codecs, so this loop makes no sense here.
> >For simplcity perhaps we can use cpu_dai?
> >>+			else
> >>+				return -EINVAL;
> >>+		} else {
> >when will this get executed? You have initialized direction to -1 and if case is
> >always true. I think compiler will simply remove the below sinppet.
> 
> direction is set to -1, then the first iteration will set it to the
> direction of the first codec_dai. The other iteration are just
> checking that there are all in the same direction and will fail
> otherwise.
> 
> >>+			if ((codec_dai->driver->playback.channels_min &&
> >>+					direction != SND_COMPRESS_PLAYBACK) ||
> >>+			    (codec_dai->driver->capture.channels_min &&
> >>+					direction != SND_COMPRESS_CAPTURE))
> >and what exactly are we trying to check here?
> 
> That every codec_dai are in the same direction.
> 
> If you think this is pointless since every DAI are always in the
> same direction, we can just remove it.
I think that will simplify it. we certainly dont expect different direction,
right?

-- 
~Vinod

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH v4 6/8] ASoC: compress: Add support for DAI multicodec
  2014-07-03  6:41       ` Vinod Koul
@ 2014-07-03 11:09         ` Benoit Cousson
  2014-07-03 11:16           ` Mark Brown
  2014-07-03 11:20           ` Lars-Peter Clausen
  0 siblings, 2 replies; 43+ messages in thread
From: Benoit Cousson @ 2014-07-03 11:09 UTC (permalink / raw)
  To: Vinod Koul, broonie, lars; +Cc: misael.lopez, lgirdwood, alsa-devel

On 03/07/2014 08:41, Vinod Koul wrote:
> On Wed, Jul 02, 2014 at 02:53:50PM +0200, Benoit Cousson wrote:
>>>> @@ -622,23 +633,33 @@ int soc_new_compress(struct snd_soc_pcm_runtime *rtd, int num)
>>>>   {
>>>>   	struct snd_soc_codec *codec = rtd->codec;
>>>>   	struct snd_soc_platform *platform = rtd->platform;
>>>> -	struct snd_soc_dai *codec_dai = rtd->codec_dai;
>>>>   	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
>>>>   	struct snd_compr *compr;
>>>>   	struct snd_pcm *be_pcm;
>>>>   	char new_name[64];
>>>> -	int ret = 0, direction = 0;
>>>> -
>>>> -	/* check client and interface hw capabilities */
>>>> -	snprintf(new_name, sizeof(new_name), "%s %s-%d",
>>>> -			rtd->dai_link->stream_name, codec_dai->name, num);
>>>> -
>>>> -	if (codec_dai->driver->playback.channels_min)
>>>> -		direction = SND_COMPRESS_PLAYBACK;
>>>> -	else if (codec_dai->driver->capture.channels_min)
>>>> -		direction = SND_COMPRESS_CAPTURE;
>>>> -	else
>>>> -		return -EINVAL;
>>>> +	int i, ret = 0, direction = -1;
>>>> +
>>>> +	for (i = 0; i < rtd->num_codecs; i++) {
>>>> +		struct snd_soc_dai *codec_dai = rtd->codec_dais[i];
>>>> +		/* check client and interface hw capabilities */
>>>> +		snprintf(new_name, sizeof(new_name), "%s %s-%d",
>>>> +			 rtd->dai_link->stream_name, codec_dai->name, num);
>>>> +
>>>> +		if (direction < 0) {
>>>> +			if (codec_dai->driver->playback.channels_min)
>>>> +				direction = SND_COMPRESS_PLAYBACK;
>>>> +			else if (codec_dai->driver->capture.channels_min)
>>>> +				direction = SND_COMPRESS_CAPTURE;
>>> direction wont change with multiple codecs, so this loop makes no sense here.
>>> For simplcity perhaps we can use cpu_dai?
>>>> +			else
>>>> +				return -EINVAL;
>>>> +		} else {
>>> when will this get executed? You have initialized direction to -1 and if case is
>>> always true. I think compiler will simply remove the below sinppet.
>>
>> direction is set to -1, then the first iteration will set it to the
>> direction of the first codec_dai. The other iteration are just
>> checking that there are all in the same direction and will fail
>> otherwise.
>>
>>>> +			if ((codec_dai->driver->playback.channels_min &&
>>>> +					direction != SND_COMPRESS_PLAYBACK) ||
>>>> +			    (codec_dai->driver->capture.channels_min &&
>>>> +					direction != SND_COMPRESS_CAPTURE))
>>> and what exactly are we trying to check here?
>>
>> That every codec_dai are in the same direction.
>>
>> If you think this is pointless since every DAI are always in the
>> same direction, we can just remove it.
> I think that will simplify it. we certainly dont expect different direction,
> right?

Lars, Mark
Any thought on that? Does that sound reasonable to you to use only the 
first codec_dai to figure out the direction?

Thanks,
Benoit

-- 
Benoît Cousson
BayLibre
Embedded Linux Technology Lab
www.baylibre.com

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH v4 6/8] ASoC: compress: Add support for DAI multicodec
  2014-07-03 11:09         ` Benoit Cousson
@ 2014-07-03 11:16           ` Mark Brown
  2014-07-03 11:20           ` Lars-Peter Clausen
  1 sibling, 0 replies; 43+ messages in thread
From: Mark Brown @ 2014-07-03 11:16 UTC (permalink / raw)
  To: Benoit Cousson; +Cc: Vinod Koul, misael.lopez, lars, lgirdwood, alsa-devel


[-- Attachment #1.1: Type: text/plain, Size: 355 bytes --]

On Thu, Jul 03, 2014 at 01:09:28PM +0200, Benoit Cousson wrote:
> On 03/07/2014 08:41, Vinod Koul wrote:

> >I think that will simplify it. we certainly dont expect different direction,
> >right?

> Any thought on that? Does that sound reasonable to you to use only the first
> codec_dai to figure out the direction?

Yes, it seems sensible enough to me.

[-- Attachment #1.2: Digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

[-- Attachment #2: Type: text/plain, Size: 0 bytes --]



^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH v4 6/8] ASoC: compress: Add support for DAI multicodec
  2014-07-03 11:09         ` Benoit Cousson
  2014-07-03 11:16           ` Mark Brown
@ 2014-07-03 11:20           ` Lars-Peter Clausen
  2014-07-03 11:39             ` Benoit Cousson
  1 sibling, 1 reply; 43+ messages in thread
From: Lars-Peter Clausen @ 2014-07-03 11:20 UTC (permalink / raw)
  To: Benoit Cousson, Vinod Koul, broonie; +Cc: misael.lopez, lgirdwood, alsa-devel

On 07/03/2014 01:09 PM, Benoit Cousson wrote:
> On 03/07/2014 08:41, Vinod Koul wrote:
>> On Wed, Jul 02, 2014 at 02:53:50PM +0200, Benoit Cousson wrote:
>>>>> @@ -622,23 +633,33 @@ int soc_new_compress(struct snd_soc_pcm_runtime
>>>>> *rtd, int num)
>>>>>   {
>>>>>       struct snd_soc_codec *codec = rtd->codec;
>>>>>       struct snd_soc_platform *platform = rtd->platform;
>>>>> -    struct snd_soc_dai *codec_dai = rtd->codec_dai;
>>>>>       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
>>>>>       struct snd_compr *compr;
>>>>>       struct snd_pcm *be_pcm;
>>>>>       char new_name[64];
>>>>> -    int ret = 0, direction = 0;
>>>>> -
>>>>> -    /* check client and interface hw capabilities */
>>>>> -    snprintf(new_name, sizeof(new_name), "%s %s-%d",
>>>>> -            rtd->dai_link->stream_name, codec_dai->name, num);
>>>>> -
>>>>> -    if (codec_dai->driver->playback.channels_min)
>>>>> -        direction = SND_COMPRESS_PLAYBACK;
>>>>> -    else if (codec_dai->driver->capture.channels_min)
>>>>> -        direction = SND_COMPRESS_CAPTURE;
>>>>> -    else
>>>>> -        return -EINVAL;
>>>>> +    int i, ret = 0, direction = -1;
>>>>> +
>>>>> +    for (i = 0; i < rtd->num_codecs; i++) {
>>>>> +        struct snd_soc_dai *codec_dai = rtd->codec_dais[i];
>>>>> +        /* check client and interface hw capabilities */
>>>>> +        snprintf(new_name, sizeof(new_name), "%s %s-%d",
>>>>> +             rtd->dai_link->stream_name, codec_dai->name, num);
>>>>> +
>>>>> +        if (direction < 0) {
>>>>> +            if (codec_dai->driver->playback.channels_min)
>>>>> +                direction = SND_COMPRESS_PLAYBACK;
>>>>> +            else if (codec_dai->driver->capture.channels_min)
>>>>> +                direction = SND_COMPRESS_CAPTURE;
>>>> direction wont change with multiple codecs, so this loop makes no sense
>>>> here.
>>>> For simplcity perhaps we can use cpu_dai?
>>>>> +            else
>>>>> +                return -EINVAL;
>>>>> +        } else {
>>>> when will this get executed? You have initialized direction to -1 and if
>>>> case is
>>>> always true. I think compiler will simply remove the below sinppet.
>>>
>>> direction is set to -1, then the first iteration will set it to the
>>> direction of the first codec_dai. The other iteration are just
>>> checking that there are all in the same direction and will fail
>>> otherwise.
>>>
>>>>> +            if ((codec_dai->driver->playback.channels_min &&
>>>>> +                    direction != SND_COMPRESS_PLAYBACK) ||
>>>>> +                (codec_dai->driver->capture.channels_min &&
>>>>> +                    direction != SND_COMPRESS_CAPTURE))
>>>> and what exactly are we trying to check here?
>>>
>>> That every codec_dai are in the same direction.
>>>
>>> If you think this is pointless since every DAI are always in the
>>> same direction, we can just remove it.
>> I think that will simplify it. we certainly dont expect different direction,
>> right?
>
> Lars, Mark
> Any thought on that? Does that sound reasonable to you to use only the first
> codec_dai to figure out the direction?
>

I guess it is ok. But I'm wondering if the direction shouldn't depend on the 
CPU dai rather than the CODEC dai? E.g. it is possible to have a CODEC with 
both playback and capture support in two dai_links, one for capture, one for 
playback. The check above would create a SND_COMPRESS_PLAYBACK stream in 
both cases. Even if the CPU dai only supported capture in one of the cases.

- Lars

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH v4 6/8] ASoC: compress: Add support for DAI multicodec
  2014-07-03 11:20           ` Lars-Peter Clausen
@ 2014-07-03 11:39             ` Benoit Cousson
  2014-07-03 11:43               ` Lars-Peter Clausen
  0 siblings, 1 reply; 43+ messages in thread
From: Benoit Cousson @ 2014-07-03 11:39 UTC (permalink / raw)
  To: Lars-Peter Clausen, Vinod Koul, broonie
  Cc: misael.lopez, lgirdwood, alsa-devel

On 03/07/2014 13:20, Lars-Peter Clausen wrote:
> On 07/03/2014 01:09 PM, Benoit Cousson wrote:
>> On 03/07/2014 08:41, Vinod Koul wrote:
>>> On Wed, Jul 02, 2014 at 02:53:50PM +0200, Benoit Cousson wrote:
>>>>>> @@ -622,23 +633,33 @@ int soc_new_compress(struct snd_soc_pcm_runtime
>>>>>> *rtd, int num)
>>>>>>   {
>>>>>>       struct snd_soc_codec *codec = rtd->codec;
>>>>>>       struct snd_soc_platform *platform = rtd->platform;
>>>>>> -    struct snd_soc_dai *codec_dai = rtd->codec_dai;
>>>>>>       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
>>>>>>       struct snd_compr *compr;
>>>>>>       struct snd_pcm *be_pcm;
>>>>>>       char new_name[64];
>>>>>> -    int ret = 0, direction = 0;
>>>>>> -
>>>>>> -    /* check client and interface hw capabilities */
>>>>>> -    snprintf(new_name, sizeof(new_name), "%s %s-%d",
>>>>>> -            rtd->dai_link->stream_name, codec_dai->name, num);
>>>>>> -
>>>>>> -    if (codec_dai->driver->playback.channels_min)
>>>>>> -        direction = SND_COMPRESS_PLAYBACK;
>>>>>> -    else if (codec_dai->driver->capture.channels_min)
>>>>>> -        direction = SND_COMPRESS_CAPTURE;
>>>>>> -    else
>>>>>> -        return -EINVAL;
>>>>>> +    int i, ret = 0, direction = -1;
>>>>>> +
>>>>>> +    for (i = 0; i < rtd->num_codecs; i++) {
>>>>>> +        struct snd_soc_dai *codec_dai = rtd->codec_dais[i];
>>>>>> +        /* check client and interface hw capabilities */
>>>>>> +        snprintf(new_name, sizeof(new_name), "%s %s-%d",
>>>>>> +             rtd->dai_link->stream_name, codec_dai->name, num);
>>>>>> +
>>>>>> +        if (direction < 0) {
>>>>>> +            if (codec_dai->driver->playback.channels_min)
>>>>>> +                direction = SND_COMPRESS_PLAYBACK;
>>>>>> +            else if (codec_dai->driver->capture.channels_min)
>>>>>> +                direction = SND_COMPRESS_CAPTURE;
>>>>> direction wont change with multiple codecs, so this loop makes no
>>>>> sense
>>>>> here.
>>>>> For simplcity perhaps we can use cpu_dai?
>>>>>> +            else
>>>>>> +                return -EINVAL;
>>>>>> +        } else {
>>>>> when will this get executed? You have initialized direction to -1
>>>>> and if
>>>>> case is
>>>>> always true. I think compiler will simply remove the below sinppet.
>>>>
>>>> direction is set to -1, then the first iteration will set it to the
>>>> direction of the first codec_dai. The other iteration are just
>>>> checking that there are all in the same direction and will fail
>>>> otherwise.
>>>>
>>>>>> +            if ((codec_dai->driver->playback.channels_min &&
>>>>>> +                    direction != SND_COMPRESS_PLAYBACK) ||
>>>>>> +                (codec_dai->driver->capture.channels_min &&
>>>>>> +                    direction != SND_COMPRESS_CAPTURE))
>>>>> and what exactly are we trying to check here?
>>>>
>>>> That every codec_dai are in the same direction.
>>>>
>>>> If you think this is pointless since every DAI are always in the
>>>> same direction, we can just remove it.
>>> I think that will simplify it. we certainly dont expect different
>>> direction,
>>> right?
>>
>> Lars, Mark
>> Any thought on that? Does that sound reasonable to you to use only the
>> first
>> codec_dai to figure out the direction?
>>
>
> I guess it is ok. But I'm wondering if the direction shouldn't depend on
> the CPU dai rather than the CODEC dai? E.g. it is possible to have a
> CODEC with both playback and capture support in two dai_links, one for
> capture, one for playback. The check above would create a
> SND_COMPRESS_PLAYBACK stream in both cases. Even if the CPU dai only
> supported capture in one of the cases.

OK, I'll use the cpu_dai then.

Thanks,
Benoit

-- 
Benoît Cousson
BayLibre
Embedded Linux Technology Lab
www.baylibre.com

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH v4 6/8] ASoC: compress: Add support for DAI multicodec
  2014-07-03 11:39             ` Benoit Cousson
@ 2014-07-03 11:43               ` Lars-Peter Clausen
  2014-07-03 11:46                 ` Benoit Cousson
  0 siblings, 1 reply; 43+ messages in thread
From: Lars-Peter Clausen @ 2014-07-03 11:43 UTC (permalink / raw)
  To: Benoit Cousson, Vinod Koul, broonie; +Cc: misael.lopez, lgirdwood, alsa-devel

On 07/03/2014 01:39 PM, Benoit Cousson wrote:
> On 03/07/2014 13:20, Lars-Peter Clausen wrote:
>> On 07/03/2014 01:09 PM, Benoit Cousson wrote:
>>> On 03/07/2014 08:41, Vinod Koul wrote:
>>>> On Wed, Jul 02, 2014 at 02:53:50PM +0200, Benoit Cousson wrote:
>>>>>>> @@ -622,23 +633,33 @@ int soc_new_compress(struct snd_soc_pcm_runtime
>>>>>>> *rtd, int num)
>>>>>>>   {
>>>>>>>       struct snd_soc_codec *codec = rtd->codec;
>>>>>>>       struct snd_soc_platform *platform = rtd->platform;
>>>>>>> -    struct snd_soc_dai *codec_dai = rtd->codec_dai;
>>>>>>>       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
>>>>>>>       struct snd_compr *compr;
>>>>>>>       struct snd_pcm *be_pcm;
>>>>>>>       char new_name[64];
>>>>>>> -    int ret = 0, direction = 0;
>>>>>>> -
>>>>>>> -    /* check client and interface hw capabilities */
>>>>>>> -    snprintf(new_name, sizeof(new_name), "%s %s-%d",
>>>>>>> -            rtd->dai_link->stream_name, codec_dai->name, num);
>>>>>>> -
>>>>>>> -    if (codec_dai->driver->playback.channels_min)
>>>>>>> -        direction = SND_COMPRESS_PLAYBACK;
>>>>>>> -    else if (codec_dai->driver->capture.channels_min)
>>>>>>> -        direction = SND_COMPRESS_CAPTURE;
>>>>>>> -    else
>>>>>>> -        return -EINVAL;
>>>>>>> +    int i, ret = 0, direction = -1;
>>>>>>> +
>>>>>>> +    for (i = 0; i < rtd->num_codecs; i++) {
>>>>>>> +        struct snd_soc_dai *codec_dai = rtd->codec_dais[i];
>>>>>>> +        /* check client and interface hw capabilities */
>>>>>>> +        snprintf(new_name, sizeof(new_name), "%s %s-%d",
>>>>>>> +             rtd->dai_link->stream_name, codec_dai->name, num);
>>>>>>> +
>>>>>>> +        if (direction < 0) {
>>>>>>> +            if (codec_dai->driver->playback.channels_min)
>>>>>>> +                direction = SND_COMPRESS_PLAYBACK;
>>>>>>> +            else if (codec_dai->driver->capture.channels_min)
>>>>>>> +                direction = SND_COMPRESS_CAPTURE;
>>>>>> direction wont change with multiple codecs, so this loop makes no
>>>>>> sense
>>>>>> here.
>>>>>> For simplcity perhaps we can use cpu_dai?
>>>>>>> +            else
>>>>>>> +                return -EINVAL;
>>>>>>> +        } else {
>>>>>> when will this get executed? You have initialized direction to -1
>>>>>> and if
>>>>>> case is
>>>>>> always true. I think compiler will simply remove the below sinppet.
>>>>>
>>>>> direction is set to -1, then the first iteration will set it to the
>>>>> direction of the first codec_dai. The other iteration are just
>>>>> checking that there are all in the same direction and will fail
>>>>> otherwise.
>>>>>
>>>>>>> +            if ((codec_dai->driver->playback.channels_min &&
>>>>>>> +                    direction != SND_COMPRESS_PLAYBACK) ||
>>>>>>> +                (codec_dai->driver->capture.channels_min &&
>>>>>>> +                    direction != SND_COMPRESS_CAPTURE))
>>>>>> and what exactly are we trying to check here?
>>>>>
>>>>> That every codec_dai are in the same direction.
>>>>>
>>>>> If you think this is pointless since every DAI are always in the
>>>>> same direction, we can just remove it.
>>>> I think that will simplify it. we certainly dont expect different
>>>> direction,
>>>> right?
>>>
>>> Lars, Mark
>>> Any thought on that? Does that sound reasonable to you to use only the
>>> first
>>> codec_dai to figure out the direction?
>>>
>>
>> I guess it is ok. But I'm wondering if the direction shouldn't depend on
>> the CPU dai rather than the CODEC dai? E.g. it is possible to have a
>> CODEC with both playback and capture support in two dai_links, one for
>> capture, one for playback. The check above would create a
>> SND_COMPRESS_PLAYBACK stream in both cases. Even if the CPU dai only
>> supported capture in one of the cases.
>
> OK, I'll use the cpu_dai then.

Lets wait for Vinod's feedback on this first. He knows this code best and 
what the intentions are.

- Lars

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH v4 6/8] ASoC: compress: Add support for DAI multicodec
  2014-07-03 11:43               ` Lars-Peter Clausen
@ 2014-07-03 11:46                 ` Benoit Cousson
  2014-07-03 12:06                   ` Vinod Koul
  0 siblings, 1 reply; 43+ messages in thread
From: Benoit Cousson @ 2014-07-03 11:46 UTC (permalink / raw)
  To: Lars-Peter Clausen, Vinod Koul, broonie
  Cc: misael.lopez, lgirdwood, alsa-devel

On 03/07/2014 13:43, Lars-Peter Clausen wrote:
> On 07/03/2014 01:39 PM, Benoit Cousson wrote:
>> On 03/07/2014 13:20, Lars-Peter Clausen wrote:
>>> On 07/03/2014 01:09 PM, Benoit Cousson wrote:
>>>> On 03/07/2014 08:41, Vinod Koul wrote:
>>>>> On Wed, Jul 02, 2014 at 02:53:50PM +0200, Benoit Cousson wrote:
>>>>>>>> @@ -622,23 +633,33 @@ int soc_new_compress(struct 
>>>>>>>> snd_soc_pcm_runtime
>>>>>>>> *rtd, int num)
>>>>>>>>   {
>>>>>>>>       struct snd_soc_codec *codec = rtd->codec;
>>>>>>>>       struct snd_soc_platform *platform = rtd->platform;
>>>>>>>> -    struct snd_soc_dai *codec_dai = rtd->codec_dai;
>>>>>>>>       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
>>>>>>>>       struct snd_compr *compr;
>>>>>>>>       struct snd_pcm *be_pcm;
>>>>>>>>       char new_name[64];
>>>>>>>> -    int ret = 0, direction = 0;
>>>>>>>> -
>>>>>>>> -    /* check client and interface hw capabilities */
>>>>>>>> -    snprintf(new_name, sizeof(new_name), "%s %s-%d",
>>>>>>>> -            rtd->dai_link->stream_name, codec_dai->name, num);
>>>>>>>> -
>>>>>>>> -    if (codec_dai->driver->playback.channels_min)
>>>>>>>> -        direction = SND_COMPRESS_PLAYBACK;
>>>>>>>> -    else if (codec_dai->driver->capture.channels_min)
>>>>>>>> -        direction = SND_COMPRESS_CAPTURE;
>>>>>>>> -    else
>>>>>>>> -        return -EINVAL;
>>>>>>>> +    int i, ret = 0, direction = -1;
>>>>>>>> +
>>>>>>>> +    for (i = 0; i < rtd->num_codecs; i++) {
>>>>>>>> +        struct snd_soc_dai *codec_dai = rtd->codec_dais[i];
>>>>>>>> +        /* check client and interface hw capabilities */
>>>>>>>> +        snprintf(new_name, sizeof(new_name), "%s %s-%d",
>>>>>>>> +             rtd->dai_link->stream_name, codec_dai->name, num);
>>>>>>>> +
>>>>>>>> +        if (direction < 0) {
>>>>>>>> +            if (codec_dai->driver->playback.channels_min)
>>>>>>>> +                direction = SND_COMPRESS_PLAYBACK;
>>>>>>>> +            else if (codec_dai->driver->capture.channels_min)
>>>>>>>> +                direction = SND_COMPRESS_CAPTURE;
>>>>>>> direction wont change with multiple codecs, so this loop makes no
>>>>>>> sense
>>>>>>> here.
>>>>>>> For simplcity perhaps we can use cpu_dai?
>>>>>>>> +            else
>>>>>>>> +                return -EINVAL;
>>>>>>>> +        } else {
>>>>>>> when will this get executed? You have initialized direction to -1
>>>>>>> and if
>>>>>>> case is
>>>>>>> always true. I think compiler will simply remove the below sinppet.
>>>>>>
>>>>>> direction is set to -1, then the first iteration will set it to the
>>>>>> direction of the first codec_dai. The other iteration are just
>>>>>> checking that there are all in the same direction and will fail
>>>>>> otherwise.
>>>>>>
>>>>>>>> +            if ((codec_dai->driver->playback.channels_min &&
>>>>>>>> +                    direction != SND_COMPRESS_PLAYBACK) ||
>>>>>>>> +                (codec_dai->driver->capture.channels_min &&
>>>>>>>> +                    direction != SND_COMPRESS_CAPTURE))
>>>>>>> and what exactly are we trying to check here?
>>>>>>
>>>>>> That every codec_dai are in the same direction.
>>>>>>
>>>>>> If you think this is pointless since every DAI are always in the
>>>>>> same direction, we can just remove it.
>>>>> I think that will simplify it. we certainly dont expect different
>>>>> direction,
>>>>> right?
>>>>
>>>> Lars, Mark
>>>> Any thought on that? Does that sound reasonable to you to use only the
>>>> first
>>>> codec_dai to figure out the direction?
>>>>
>>>
>>> I guess it is ok. But I'm wondering if the direction shouldn't depend on
>>> the CPU dai rather than the CODEC dai? E.g. it is possible to have a
>>> CODEC with both playback and capture support in two dai_links, one for
>>> capture, one for playback. The check above would create a
>>> SND_COMPRESS_PLAYBACK stream in both cases. Even if the CPU dai only
>>> supported capture in one of the cases.
>>
>> OK, I'll use the cpu_dai then.
> 
> Lets wait for Vinod's feedback on this first. He knows this code best 
> and what the intentions are.

Sure, but he was the first one to propose using that :-)

>>>>>>> direction wont change with multiple codecs, so this loop makes no
>>>>>>> sense
>>>>>>> here.
>>>>>>> For simplcity perhaps we can use cpu_dai?

Regards,
Benoit

-- 
Benoît Cousson
BayLibre
Embedded Linux Technology Lab
www.baylibre.com

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH v4 6/8] ASoC: compress: Add support for DAI multicodec
  2014-07-03 11:46                 ` Benoit Cousson
@ 2014-07-03 12:06                   ` Vinod Koul
  2014-07-03 12:18                     ` Mark Brown
  0 siblings, 1 reply; 43+ messages in thread
From: Vinod Koul @ 2014-07-03 12:06 UTC (permalink / raw)
  To: Benoit Cousson
  Cc: broonie, Lars-Peter Clausen, lgirdwood, alsa-devel, misael.lopez

On Thu, Jul 03, 2014 at 01:46:23PM +0200, Benoit Cousson wrote:
> On 03/07/2014 13:43, Lars-Peter Clausen wrote:
> > On 07/03/2014 01:39 PM, Benoit Cousson wrote:
> >> On 03/07/2014 13:20, Lars-Peter Clausen wrote:
> >>> On 07/03/2014 01:09 PM, Benoit Cousson wrote:
> >>>> On 03/07/2014 08:41, Vinod Koul wrote:
> >>>>> On Wed, Jul 02, 2014 at 02:53:50PM +0200, Benoit Cousson wrote:
> >>>>>>>> @@ -622,23 +633,33 @@ int soc_new_compress(struct 
> >>>>>>>> snd_soc_pcm_runtime
> >>>>>>>> *rtd, int num)
> >>>>>>>>   {
> >>>>>>>>       struct snd_soc_codec *codec = rtd->codec;
> >>>>>>>>       struct snd_soc_platform *platform = rtd->platform;
> >>>>>>>> -    struct snd_soc_dai *codec_dai = rtd->codec_dai;
> >>>>>>>>       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
> >>>>>>>>       struct snd_compr *compr;
> >>>>>>>>       struct snd_pcm *be_pcm;
> >>>>>>>>       char new_name[64];
> >>>>>>>> -    int ret = 0, direction = 0;
> >>>>>>>> -
> >>>>>>>> -    /* check client and interface hw capabilities */
> >>>>>>>> -    snprintf(new_name, sizeof(new_name), "%s %s-%d",
> >>>>>>>> -            rtd->dai_link->stream_name, codec_dai->name, num);
> >>>>>>>> -
> >>>>>>>> -    if (codec_dai->driver->playback.channels_min)
> >>>>>>>> -        direction = SND_COMPRESS_PLAYBACK;
> >>>>>>>> -    else if (codec_dai->driver->capture.channels_min)
> >>>>>>>> -        direction = SND_COMPRESS_CAPTURE;
> >>>>>>>> -    else
> >>>>>>>> -        return -EINVAL;
> >>>>>>>> +    int i, ret = 0, direction = -1;
> >>>>>>>> +
> >>>>>>>> +    for (i = 0; i < rtd->num_codecs; i++) {
> >>>>>>>> +        struct snd_soc_dai *codec_dai = rtd->codec_dais[i];
> >>>>>>>> +        /* check client and interface hw capabilities */
> >>>>>>>> +        snprintf(new_name, sizeof(new_name), "%s %s-%d",
> >>>>>>>> +             rtd->dai_link->stream_name, codec_dai->name, num);
> >>>>>>>> +
> >>>>>>>> +        if (direction < 0) {
> >>>>>>>> +            if (codec_dai->driver->playback.channels_min)
> >>>>>>>> +                direction = SND_COMPRESS_PLAYBACK;
> >>>>>>>> +            else if (codec_dai->driver->capture.channels_min)
> >>>>>>>> +                direction = SND_COMPRESS_CAPTURE;
> >>>>>>> direction wont change with multiple codecs, so this loop makes no
> >>>>>>> sense
> >>>>>>> here.
> >>>>>>> For simplcity perhaps we can use cpu_dai?
> >>>>>>>> +            else
> >>>>>>>> +                return -EINVAL;
> >>>>>>>> +        } else {
> >>>>>>> when will this get executed? You have initialized direction to -1
> >>>>>>> and if
> >>>>>>> case is
> >>>>>>> always true. I think compiler will simply remove the below sinppet.
> >>>>>>
> >>>>>> direction is set to -1, then the first iteration will set it to the
> >>>>>> direction of the first codec_dai. The other iteration are just
> >>>>>> checking that there are all in the same direction and will fail
> >>>>>> otherwise.
> >>>>>>
> >>>>>>>> +            if ((codec_dai->driver->playback.channels_min &&
> >>>>>>>> +                    direction != SND_COMPRESS_PLAYBACK) ||
> >>>>>>>> +                (codec_dai->driver->capture.channels_min &&
> >>>>>>>> +                    direction != SND_COMPRESS_CAPTURE))
> >>>>>>> and what exactly are we trying to check here?
> >>>>>>
> >>>>>> That every codec_dai are in the same direction.
> >>>>>>
> >>>>>> If you think this is pointless since every DAI are always in the
> >>>>>> same direction, we can just remove it.
> >>>>> I think that will simplify it. we certainly dont expect different
> >>>>> direction,
> >>>>> right?
> >>>>
> >>>> Lars, Mark
> >>>> Any thought on that? Does that sound reasonable to you to use only the
> >>>> first
> >>>> codec_dai to figure out the direction?
> >>>>
> >>>
> >>> I guess it is ok. But I'm wondering if the direction shouldn't depend on
> >>> the CPU dai rather than the CODEC dai? E.g. it is possible to have a
> >>> CODEC with both playback and capture support in two dai_links, one for
> >>> capture, one for playback. The check above would create a
> >>> SND_COMPRESS_PLAYBACK stream in both cases. Even if the CPU dai only
> >>> supported capture in one of the cases.
> >>
> >> OK, I'll use the cpu_dai then.
> > 
> > Lets wait for Vinod's feedback on this first. He knows this code best 
> > and what the intentions are.
> 
> Sure, but he was the first one to propose using that :-)
cpu_dai should be okay :)

BUT Now thinking over this again, does this make sense do do with multiple
codecs??

For folks haveing decoders in DSP inside SoC, the compressed device will be
actually a FE. The BE will be PCM to which codec would be linked. The folks
supporting decoders inside codec like WM wont ever need this.

Mark, do you agree to this?

So re-thinking again on why we need this??

-- 
~Vinod

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH v4 6/8] ASoC: compress: Add support for DAI multicodec
  2014-07-03 12:06                   ` Vinod Koul
@ 2014-07-03 12:18                     ` Mark Brown
  2014-07-03 16:15                       ` Vinod Koul
  0 siblings, 1 reply; 43+ messages in thread
From: Mark Brown @ 2014-07-03 12:18 UTC (permalink / raw)
  To: Vinod Koul
  Cc: alsa-devel, misael.lopez, Lars-Peter Clausen, lgirdwood, Benoit Cousson


[-- Attachment #1.1: Type: text/plain, Size: 1373 bytes --]

On Thu, Jul 03, 2014 at 05:36:13PM +0530, Vinod Koul wrote:
> On Thu, Jul 03, 2014 at 01:46:23PM +0200, Benoit Cousson wrote:
> > On 03/07/2014 13:43, Lars-Peter Clausen wrote:
> > > On 07/03/2014 01:39 PM, Benoit Cousson wrote:
> > >> On 03/07/2014 13:20, Lars-Peter Clausen wrote:
> > >>> On 07/03/2014 01:09 PM, Benoit Cousson wrote:
> > >>>> On 03/07/2014 08:41, Vinod Koul wrote:
> > >>>>> On Wed, Jul 02, 2014 at 02:53:50PM +0200, Benoit Cousson wrote:

People, please delete irrelevant context from your e-mails - it makes it
easier to find the new content.

> BUT Now thinking over this again, does this make sense do do with multiple
> codecs??

> For folks haveing decoders in DSP inside SoC, the compressed device will be
> actually a FE. The BE will be PCM to which codec would be linked. The folks
> supporting decoders inside codec like WM wont ever need this.

> Mark, do you agree to this?

> So re-thinking again on why we need this??

The use case tends to be for applications that have one device per
physical output.  This isn't normally mobile, it's normally high
performance audio applications where people are doing things to try to
electrically isolate the analogue outputs or dealing with high power so
need to keep speaker outputs physically separate.  I can imagine set top
box type applications (which do use offloaded media decode) doing this.

[-- Attachment #1.2: Digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

[-- Attachment #2: Type: text/plain, Size: 0 bytes --]



^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH v4 6/8] ASoC: compress: Add support for DAI multicodec
  2014-07-03 12:18                     ` Mark Brown
@ 2014-07-03 16:15                       ` Vinod Koul
  2014-07-03 18:23                         ` Lars-Peter Clausen
  2014-07-03 18:38                         ` Mark Brown
  0 siblings, 2 replies; 43+ messages in thread
From: Vinod Koul @ 2014-07-03 16:15 UTC (permalink / raw)
  To: Mark Brown
  Cc: alsa-devel, misael.lopez, Lars-Peter Clausen, lgirdwood, Benoit Cousson


[-- Attachment #1.1: Type: text/plain, Size: 1420 bytes --]

On Thu, Jul 03, 2014 at 01:18:46PM +0100, Mark Brown wrote:
> > BUT Now thinking over this again, does this make sense do do with multiple
> > codecs??
> 
> > For folks haveing decoders in DSP inside SoC, the compressed device will be
> > actually a FE. The BE will be PCM to which codec would be linked. The folks
> > supporting decoders inside codec like WM wont ever need this.
> 
> > Mark, do you agree to this?
> 
> > So re-thinking again on why we need this??
> 
> The use case tends to be for applications that have one device per
> physical output.  This isn't normally mobile, it's normally high
> performance audio applications where people are doing things to try to
> electrically isolate the analogue outputs or dealing with high power so
> need to keep speaker outputs physically separate.  I can imagine set top
> box type applications (which do use offloaded media decode) doing this.

Not sure if I follow you, I have no idea of how these systems work.

But if sound card has compressed device it would need to represent using DPCM as
we don't know the decoder PCM output. The multiple codecs would then connect to
the PCM BE. 
So on Compressed FE, we wont have multiple codecs.

For codecs, the compressed audio will go to one codec, multiple ones wont make
sense.

So how can we have a situation where we have compressed device linked to
multiple codecs?

-- 
~Vinod

[-- Attachment #1.2: Digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

[-- Attachment #2: Type: text/plain, Size: 0 bytes --]



^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH v4 6/8] ASoC: compress: Add support for DAI multicodec
  2014-07-03 16:15                       ` Vinod Koul
@ 2014-07-03 18:23                         ` Lars-Peter Clausen
  2014-07-04 13:55                           ` Benoit Cousson
  2014-07-03 18:38                         ` Mark Brown
  1 sibling, 1 reply; 43+ messages in thread
From: Lars-Peter Clausen @ 2014-07-03 18:23 UTC (permalink / raw)
  To: Vinod Koul
  Cc: alsa-devel, misael.lopez, Mark Brown, lgirdwood, Benoit Cousson

On 07/03/2014 06:15 PM, Vinod Koul wrote:
> On Thu, Jul 03, 2014 at 01:18:46PM +0100, Mark Brown wrote:
>>> BUT Now thinking over this again, does this make sense do do with multiple
>>> codecs??
>>
>>> For folks haveing decoders in DSP inside SoC, the compressed device will be
>>> actually a FE. The BE will be PCM to which codec would be linked. The folks
>>> supporting decoders inside codec like WM wont ever need this.
>>
>>> Mark, do you agree to this?
>>
>>> So re-thinking again on why we need this??
>>
>> The use case tends to be for applications that have one device per
>> physical output.  This isn't normally mobile, it's normally high
>> performance audio applications where people are doing things to try to
>> electrically isolate the analogue outputs or dealing with high power so
>> need to keep speaker outputs physically separate.  I can imagine set top
>> box type applications (which do use offloaded media decode) doing this.
>
> Not sure if I follow you, I have no idea of how these systems work.
>
> But if sound card has compressed device it would need to represent using DPCM as
> we don't know the decoder PCM output. The multiple codecs would then connect to
> the PCM BE.
> So on Compressed FE, we wont have multiple codecs.
>
> For codecs, the compressed audio will go to one codec, multiple ones wont make
> sense.
>
> So how can we have a situation where we have compressed device linked to
> multiple codecs?
>

If the assumption is that a DAI link that has a compressed DAI on the CPU side 
is never connected to a 'real' CODEC (or multiple CODECS) on the CODEC side. I 
think we can just leave soc-compress.c alone and just add a sanity check to 
make sure that num_codecs is always 1.

- Lars

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH v4 6/8] ASoC: compress: Add support for DAI multicodec
  2014-07-03 16:15                       ` Vinod Koul
  2014-07-03 18:23                         ` Lars-Peter Clausen
@ 2014-07-03 18:38                         ` Mark Brown
  2014-07-03 19:09                           ` Pierre-Louis Bossart
  1 sibling, 1 reply; 43+ messages in thread
From: Mark Brown @ 2014-07-03 18:38 UTC (permalink / raw)
  To: Vinod Koul
  Cc: alsa-devel, misael.lopez, Lars-Peter Clausen, lgirdwood, Benoit Cousson


[-- Attachment #1.1: Type: text/plain, Size: 1063 bytes --]

On Thu, Jul 03, 2014 at 09:45:17PM +0530, Vinod Koul wrote:
> On Thu, Jul 03, 2014 at 01:18:46PM +0100, Mark Brown wrote:

> > The use case tends to be for applications that have one device per
> > physical output.  This isn't normally mobile, it's normally high
> > performance audio applications where people are doing things to try to
> > electrically isolate the analogue outputs or dealing with high power so
> > need to keep speaker outputs physically separate.  I can imagine set top
> > box type applications (which do use offloaded media decode) doing this.

> Not sure if I follow you, I have no idea of how these systems work.

They're having the SoC play stereo (or whatever) data and then having
multiple CODECs on the bus, each parsing some subset of the channels
(typically one channel per CODEC).

> So how can we have a situation where we have compressed device linked to
> multiple codecs?

If it's intended to be DPCM only (which it iss now I think about it) it
sounds like you can't have it linked to *any* real CODECS, at least not
directly!

[-- Attachment #1.2: Digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

[-- Attachment #2: Type: text/plain, Size: 0 bytes --]



^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH v4 6/8] ASoC: compress: Add support for DAI multicodec
  2014-07-03 18:38                         ` Mark Brown
@ 2014-07-03 19:09                           ` Pierre-Louis Bossart
  0 siblings, 0 replies; 43+ messages in thread
From: Pierre-Louis Bossart @ 2014-07-03 19:09 UTC (permalink / raw)
  To: Mark Brown, Vinod Koul
  Cc: alsa-devel, Lars-Peter Clausen, misael.lopez, Benoit Cousson, lgirdwood


>>> The use case tends to be for applications that have one device per
>>> physical output.  This isn't normally mobile, it's normally high
>>> performance audio applications where people are doing things to try to
>>> electrically isolate the analogue outputs or dealing with high power so
>>> need to keep speaker outputs physically separate.  I can imagine set top
>>> box type applications (which do use offloaded media decode) doing this.
>
>> Not sure if I follow you, I have no idea of how these systems work.
>
> They're having the SoC play stereo (or whatever) data and then having
> multiple CODECs on the bus, each parsing some subset of the channels
> (typically one channel per CODEC).

This sort of stream aggregation/split is a very valid use case that's 
coming to mobiles in the very near future with new interfaces being 
standardized.

>
>> So how can we have a situation where we have compressed device linked to
>> multiple codecs?
>
> If it's intended to be DPCM only (which it iss now I think about it) it
> sounds like you can't have it linked to *any* real CODECS, at least not
> directly!

there are very few references to codec_dais in soc-compress and some are 
in sections copy/pasted from soc-pcm, which makes me wonder as well if 
they needed to be there in the first place.
-Pierre

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH v4 6/8] ASoC: compress: Add support for DAI multicodec
  2014-07-03 18:23                         ` Lars-Peter Clausen
@ 2014-07-04 13:55                           ` Benoit Cousson
  0 siblings, 0 replies; 43+ messages in thread
From: Benoit Cousson @ 2014-07-04 13:55 UTC (permalink / raw)
  To: Lars-Peter Clausen, Vinod Koul
  Cc: misael.lopez, Mark Brown, lgirdwood, alsa-devel

On 03/07/2014 20:23, Lars-Peter Clausen wrote:

[...]

> If the assumption is that a DAI link that has a compressed DAI on the
> CPU side is never connected to a 'real' CODEC (or multiple CODECS) on
> the CODEC side. I think we can just leave soc-compress.c alone and just
> add a sanity check to make sure that num_codecs is always 1.

OK, I'll repost the series without any change on soc-compress.c beside a 
test.

Thanks,
Benoit

-- 
Benoît Cousson
BayLibre
Embedded Linux Technology Lab
www.baylibre.com

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH v4 1/8] ASoC: core: Change soc_link_dai_widgets signature for multiple codecs
  2014-07-01 17:17   ` Mark Brown
@ 2014-07-04 16:13     ` Benoit Cousson
  2014-07-04 16:51       ` Mark Brown
  0 siblings, 1 reply; 43+ messages in thread
From: Benoit Cousson @ 2014-07-04 16:13 UTC (permalink / raw)
  To: Mark Brown; +Cc: misael.lopez, lars, lgirdwood, alsa-devel

Hi Mark,

On 01/07/2014 19:17, Mark Brown wrote:
> On Tue, Jul 01, 2014 at 09:47:54AM +0200, Benoit Cousson wrote:
>> Since multiple codecs DAI will be usable in the future, remove
>> explicit unique codec_dai and cpu_dai parameters.
>> Replace them with snd_soc_pcm_runtime pointer that will contain
>> every instances.
>
> Applied, thanks.

Where did you applied this patch and the next one? I couldn't find them 
during the rebase. Neither in asoc/for-next nor in topic/multicodec.

Thanks,
Benoit

-- 
Benoît Cousson
BayLibre
Embedded Linux Technology Lab
www.baylibre.com

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH v4 1/8] ASoC: core: Change soc_link_dai_widgets signature for multiple codecs
  2014-07-04 16:13     ` Benoit Cousson
@ 2014-07-04 16:51       ` Mark Brown
  0 siblings, 0 replies; 43+ messages in thread
From: Mark Brown @ 2014-07-04 16:51 UTC (permalink / raw)
  To: Benoit Cousson; +Cc: misael.lopez, lars, lgirdwood, alsa-devel


[-- Attachment #1.1: Type: text/plain, Size: 224 bytes --]

On Fri, Jul 04, 2014 at 06:13:38PM +0200, Benoit Cousson wrote:

> Where did you applied this patch and the next one? I couldn't find them
> during the rebase. Neither in asoc/for-next nor in topic/multicodec.

topic/multi.

[-- Attachment #1.2: Digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

[-- Attachment #2: Type: text/plain, Size: 0 bytes --]



^ permalink raw reply	[flat|nested] 43+ messages in thread

end of thread, other threads:[~2014-07-04 16:52 UTC | newest]

Thread overview: 43+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-07-01  7:47 [PATCH v4 0/8] ASoC: core: Add support for DAI multicodec Benoit Cousson
2014-07-01  7:47 ` [PATCH v4 1/8] ASoC: core: Change soc_link_dai_widgets signature for multiple codecs Benoit Cousson
2014-07-01 17:17   ` Mark Brown
2014-07-04 16:13     ` Benoit Cousson
2014-07-04 16:51       ` Mark Brown
2014-07-01  7:47 ` [PATCH v4 2/8] ASoC: pcm: Refactor soc_pcm_apply_msb for multicodecs Benoit Cousson
2014-07-01 17:20   ` Mark Brown
2014-07-01 17:31     ` Benoit Cousson
2014-07-01  7:47 ` [PATCH v4 3/8] ASoC: core: Add initial support for DAI multicodec Benoit Cousson
2014-07-01 13:19   ` Lars-Peter Clausen
2014-07-01 17:27     ` Benoit Cousson
2014-07-01  7:47 ` [PATCH v4 4/8] ASoC: pcm: Add " Benoit Cousson
2014-07-01 13:32   ` Lars-Peter Clausen
2014-07-01  7:47 ` [PATCH v4 5/8] ASoC: dapm: " Benoit Cousson
2014-07-01 13:40   ` Lars-Peter Clausen
2014-07-01  7:47 ` [PATCH v4 6/8] ASoC: compress: " Benoit Cousson
2014-07-01 13:49   ` Lars-Peter Clausen
2014-07-01 16:25     ` Vinod Koul
2014-07-01 16:42       ` Lars-Peter Clausen
2014-07-01 16:45         ` Vinod Koul
2014-07-01 17:32       ` Benoit Cousson
2014-07-01 16:41   ` Vinod Koul
2014-07-01 17:41     ` Mark Brown
2014-07-03  6:39       ` Vinod Koul
2014-07-02 12:53     ` Benoit Cousson
2014-07-03  6:41       ` Vinod Koul
2014-07-03 11:09         ` Benoit Cousson
2014-07-03 11:16           ` Mark Brown
2014-07-03 11:20           ` Lars-Peter Clausen
2014-07-03 11:39             ` Benoit Cousson
2014-07-03 11:43               ` Lars-Peter Clausen
2014-07-03 11:46                 ` Benoit Cousson
2014-07-03 12:06                   ` Vinod Koul
2014-07-03 12:18                     ` Mark Brown
2014-07-03 16:15                       ` Vinod Koul
2014-07-03 18:23                         ` Lars-Peter Clausen
2014-07-04 13:55                           ` Benoit Cousson
2014-07-03 18:38                         ` Mark Brown
2014-07-03 19:09                           ` Pierre-Louis Bossart
2014-07-01  7:48 ` [PATCH v4 7/8] ASoC: pcm: Add soc_dai_hw_params helper Benoit Cousson
2014-07-01 13:43   ` Lars-Peter Clausen
2014-07-01  7:48 ` [PATCH v4 8/8] ASoC: core: Add a warning for link_dai_widget in the multicodec case Benoit Cousson
2014-07-01 13:41   ` Lars-Peter Clausen

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.