From 58ba9b25454fe9b6ded804f69cb7ed4500b685fc Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 16 Jan 2012 18:38:51 +0000 Subject: ASoC: Allow drivers to specify how many bits are significant on a DAI Most devices accept data in formats that don't correspond directly to their internal format. ALSA allows us to set a msbits constraint which tells userspace about this in case it finds it useful (for example, in order to avoid wasting effort dithering bits that will be ignored when raising the sample size of data) so provide a mechanism for drivers to specify the number of bits that are actually significant on a DAI and add the appropriate constraints along with all the others. This is done slightly awkwardly as the constraint is specified per sample size - we loop over every possible sample size, including ones that the device doesn't support and including ones that have fewer bits than are actually used, but this is harmless as the upper layers do the right thing in these cases. Signed-off-by: Mark Brown Acked-by: Liam Girdwood --- sound/soc/soc-pcm.c | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) (limited to 'sound/soc/soc-pcm.c') diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index cdc860a5ff3..8bb17937d59 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -62,6 +62,39 @@ static int soc_pcm_apply_symmetry(struct snd_pcm_substream *substream, return 0; } +/* + * List of sample sizes that might go over the bus for parameter + * application. There ought to be a wildcard sample size for things + * like the DAC/ADC resolution to use but there isn't right now. + */ +static int sample_sizes[] = { + 8, 16, 24, 32, +}; + +static void soc_pcm_apply_msb(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + int ret, i, bits; + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + bits = dai->driver->playback.sig_bits; + else + bits = dai->driver->capture.sig_bits; + + if (!bits) + return; + + for (i = 0; i < ARRAY_SIZE(sample_sizes); i++) { + ret = snd_pcm_hw_constraint_msbits(substream->runtime, + 0, sample_sizes[i], + bits); + if (ret != 0) + dev_warn(dai->dev, + "Failed to set MSB %d/%d: %d\n", + bits, sample_sizes[i], ret); + } +} + /* * Called by ALSA when a PCM substream is opened, the runtime->hw record is * then initialized and any private data can be allocated. This also calls @@ -187,6 +220,9 @@ 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); + /* Symmetry only applies if we've already got an active stream. */ if (cpu_dai->active) { ret = soc_pcm_apply_symmetry(substream, cpu_dai); -- cgit v1.2.3-18-g5258 From 278047fd654dde7ed95c8604fcefeeacc5c0bb2b Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 19 Jan 2012 18:04:18 +0000 Subject: ASoC: Don't tell applications about msbits unless we're ignoring input On the off chance that an application both pays attention and gets confused. Signed-off-by: Mark Brown --- sound/soc/soc-pcm.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'sound/soc/soc-pcm.c') diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 8bb17937d59..326890148a2 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -85,9 +85,11 @@ static void soc_pcm_apply_msb(struct snd_pcm_substream *substream, return; for (i = 0; i < ARRAY_SIZE(sample_sizes); i++) { - ret = snd_pcm_hw_constraint_msbits(substream->runtime, - 0, sample_sizes[i], - bits); + if (bits >= sample_sizes[i]) + continue; + + ret = snd_pcm_hw_constraint_msbits(substream->runtime, 0, + sample_sizes[i], bits); if (ret != 0) dev_warn(dai->dev, "Failed to set MSB %d/%d: %d\n", -- cgit v1.2.3-18-g5258 From 88e339541d28153b6d2bfad9b25b3462fcd2bcaa Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Wed, 25 Jan 2012 10:09:41 +0200 Subject: ASoC: soc-pcm: msbits constraint: Drop 8 and 16 bit sample sizes As per discussion we can safely ignore the 8 and 16 bit sample sizes when applying the msbits constraint. Signed-off-by: Peter Ujfalusi Signed-off-by: Mark Brown --- sound/soc/soc-pcm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound/soc/soc-pcm.c') diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 326890148a2..93be95b7864 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -68,7 +68,7 @@ static int soc_pcm_apply_symmetry(struct snd_pcm_substream *substream, * like the DAC/ADC resolution to use but there isn't right now. */ static int sample_sizes[] = { - 8, 16, 24, 32, + 24, 32, }; static void soc_pcm_apply_msb(struct snd_pcm_substream *substream, -- cgit v1.2.3-18-g5258 From 25bfe662e8c42f84851f79ed6ada5ef96a2ff329 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 1 Feb 2012 21:30:32 +0000 Subject: ASoC: pcm: Improve error logging Use the standard logging macros and use dev_ variants where we can, also reporting error codes whenever we report an error. These changes (the error codes in particular) make it noticeably easier to figure out what went wrong just from the basic dmesg output. Signed-off-by: Mark Brown Acked-by: Liam Girdwood --- sound/soc/soc-pcm.c | 39 ++++++++++++++++++++++----------------- 1 file changed, 22 insertions(+), 17 deletions(-) (limited to 'sound/soc/soc-pcm.c') diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 93be95b7864..121318defea 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -123,8 +123,8 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) if (cpu_dai->driver->ops->startup) { ret = cpu_dai->driver->ops->startup(substream, cpu_dai); if (ret < 0) { - printk(KERN_ERR "asoc: can't open interface %s\n", - cpu_dai->name); + dev_err(cpu_dai->dev, "can't open interface %s: %d\n", + cpu_dai->name, ret); goto out; } } @@ -132,7 +132,8 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) if (platform->driver->ops && platform->driver->ops->open) { ret = platform->driver->ops->open(substream); if (ret < 0) { - printk(KERN_ERR "asoc: can't open platform %s\n", platform->name); + dev_err(platform->dev, "can't open platform %s: %d\n", + platform->name, ret); goto platform_err; } } @@ -140,8 +141,8 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) if (codec_dai->driver->ops->startup) { ret = codec_dai->driver->ops->startup(substream, codec_dai); if (ret < 0) { - printk(KERN_ERR "asoc: can't open codec %s\n", - codec_dai->name); + dev_err(codec_dai->dev, "can't open codec %s: %d\n", + codec_dai->name, ret); goto codec_dai_err; } } @@ -149,7 +150,8 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) if (rtd->dai_link->ops && rtd->dai_link->ops->startup) { ret = rtd->dai_link->ops->startup(substream); if (ret < 0) { - printk(KERN_ERR "asoc: %s startup failed\n", rtd->dai_link->name); + pr_err("asoc: %s startup failed: %d\n", + rtd->dai_link->name, ret); goto machine_err; } } @@ -413,7 +415,7 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream) if (rtd->dai_link->ops && rtd->dai_link->ops->prepare) { ret = rtd->dai_link->ops->prepare(substream); if (ret < 0) { - printk(KERN_ERR "asoc: machine prepare error\n"); + pr_err("asoc: machine prepare error: %d\n", ret); goto out; } } @@ -421,7 +423,8 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream) if (platform->driver->ops && platform->driver->ops->prepare) { ret = platform->driver->ops->prepare(substream); if (ret < 0) { - printk(KERN_ERR "asoc: platform prepare error\n"); + dev_err(platform->dev, "platform prepare error: %d\n", + ret); goto out; } } @@ -429,7 +432,8 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream) if (codec_dai->driver->ops->prepare) { ret = codec_dai->driver->ops->prepare(substream, codec_dai); if (ret < 0) { - printk(KERN_ERR "asoc: codec DAI prepare error\n"); + dev_err(codec_dai->dev, "DAI prepare error: %d\n", + ret); goto out; } } @@ -437,7 +441,8 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream) if (cpu_dai->driver->ops->prepare) { ret = cpu_dai->driver->ops->prepare(substream, cpu_dai); if (ret < 0) { - printk(KERN_ERR "asoc: cpu DAI prepare error\n"); + dev_err(cpu_dai->dev, "DAI prepare error: %d\n", + ret); goto out; } } @@ -484,7 +489,7 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream, if (rtd->dai_link->ops && rtd->dai_link->ops->hw_params) { ret = rtd->dai_link->ops->hw_params(substream, params); if (ret < 0) { - printk(KERN_ERR "asoc: machine hw_params failed\n"); + pr_err("asoc: machine hw_params failed: %d\n", ret); goto out; } } @@ -492,8 +497,8 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream, if (codec_dai->driver->ops->hw_params) { ret = codec_dai->driver->ops->hw_params(substream, params, codec_dai); if (ret < 0) { - printk(KERN_ERR "asoc: can't set codec %s hw params\n", - codec_dai->name); + dev_err(codec_dai->dev, "can't set %s hw params: %d\n", + codec_dai->name, ret); goto codec_err; } } @@ -501,8 +506,8 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream, if (cpu_dai->driver->ops->hw_params) { ret = cpu_dai->driver->ops->hw_params(substream, params, cpu_dai); if (ret < 0) { - printk(KERN_ERR "asoc: interface %s hw params failed\n", - cpu_dai->name); + dev_err(cpu_dai->dev, "%s hw params failed: %d\n", + cpu_dai->name, ret); goto interface_err; } } @@ -510,8 +515,8 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream, if (platform->driver->ops && platform->driver->ops->hw_params) { ret = platform->driver->ops->hw_params(substream, params); if (ret < 0) { - printk(KERN_ERR "asoc: platform %s hw params failed\n", - platform->name); + dev_err(platform->dev, "%s hw params failed: %d\n", + platform->name, ret); goto platform_err; } } -- cgit v1.2.3-18-g5258 From b5d1d036eadb30996184cc335c798219dd5922a9 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 8 Feb 2012 20:10:56 +0000 Subject: ASoC: pcm: If pmdown_time is zero then shut down DAPM immediately Since we've already got logic to special case immediate teardown of the stream we may as well use it if the pmdown_time has been set to zero by the application layer instead of scheduling a work item with zero delay. Signed-off-by: Mark Brown Acked-by: Liam Girdwood --- sound/soc/soc-pcm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound/soc/soc-pcm.c') diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 121318defea..15816eccad3 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -369,7 +369,7 @@ static int soc_pcm_close(struct snd_pcm_substream *substream) cpu_dai->runtime = NULL; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - if (codec->ignore_pmdown_time || + if (!rtd->pmdown_time || codec->ignore_pmdown_time || rtd->dai_link->ignore_pmdown_time) { /* powered down playback stream now */ snd_soc_dapm_stream_event(rtd, -- cgit v1.2.3-18-g5258 From 7bd3a6f34cdd4b1776ca34d0b6fab216e9323759 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 16 Feb 2012 15:03:27 -0800 Subject: ASoC: dapm: Supply the DAI and substream when calling stream events In order to allow us to do something smarter than iterate through widgets doing strcmp() to work out what to power up for stream events change the interface used to generate them to be based on the combination of a DAI and a stream direction rather than just a simple string identifying the stream. At some point we'll probably want a set of channels too. Signed-off-by: Mark Brown Acked-by: Liam Girdwood --- sound/soc/soc-pcm.c | 25 +++++++++---------------- 1 file changed, 9 insertions(+), 16 deletions(-) (limited to 'sound/soc/soc-pcm.c') diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 15816eccad3..0ad8dcacd2f 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -307,9 +307,8 @@ static void close_delayed_work(struct work_struct *work) /* are we waiting on this codec DAI stream */ if (codec_dai->pop_wait == 1) { codec_dai->pop_wait = 0; - snd_soc_dapm_stream_event(rtd, - codec_dai->driver->playback.stream_name, - SND_SOC_DAPM_STREAM_STOP); + snd_soc_dapm_stream_event(rtd, SNDRV_PCM_STREAM_PLAYBACK, + codec_dai, SND_SOC_DAPM_STREAM_STOP); } mutex_unlock(&rtd->pcm_mutex); @@ -373,8 +372,9 @@ static int soc_pcm_close(struct snd_pcm_substream *substream) rtd->dai_link->ignore_pmdown_time) { /* powered down playback stream now */ snd_soc_dapm_stream_event(rtd, - codec_dai->driver->playback.stream_name, - SND_SOC_DAPM_STREAM_STOP); + SNDRV_PCM_STREAM_PLAYBACK, + codec_dai, + SND_SOC_DAPM_STREAM_STOP); } else { /* start delayed pop wq here for playback streams */ codec_dai->pop_wait = 1; @@ -383,9 +383,8 @@ static int soc_pcm_close(struct snd_pcm_substream *substream) } } else { /* capture streams can be powered down now */ - snd_soc_dapm_stream_event(rtd, - codec_dai->driver->capture.stream_name, - SND_SOC_DAPM_STREAM_STOP); + snd_soc_dapm_stream_event(rtd, SNDRV_PCM_STREAM_CAPTURE, + codec_dai, SND_SOC_DAPM_STREAM_STOP); } mutex_unlock(&rtd->pcm_mutex); @@ -454,14 +453,8 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream) cancel_delayed_work(&rtd->delayed_work); } - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - snd_soc_dapm_stream_event(rtd, - codec_dai->driver->playback.stream_name, - SND_SOC_DAPM_STREAM_START); - else - snd_soc_dapm_stream_event(rtd, - codec_dai->driver->capture.stream_name, - SND_SOC_DAPM_STREAM_START); + snd_soc_dapm_stream_event(rtd, substream->stream, codec_dai, + SND_SOC_DAPM_STREAM_START); snd_soc_dai_digital_mute(codec_dai, 0); -- cgit v1.2.3-18-g5258