Loading include/sound/soc-dai.h +6 −0 Original line number Diff line number Diff line Loading @@ -220,6 +220,8 @@ struct snd_soc_dai_driver { struct snd_soc_pcm_stream capture; struct snd_soc_pcm_stream playback; unsigned int symmetric_rates:1; unsigned int symmetric_channels:1; unsigned int symmetric_samplebits:1; /* probe ordering - for components with runtime dependencies */ int probe_order; Loading @@ -244,6 +246,8 @@ struct snd_soc_dai { unsigned int capture_active:1; /* stream is in use */ unsigned int playback_active:1; /* stream is in use */ unsigned int symmetric_rates:1; unsigned int symmetric_channels:1; unsigned int symmetric_samplebits:1; struct snd_pcm_runtime *runtime; unsigned int active; unsigned char probed:1; Loading @@ -258,6 +262,8 @@ struct snd_soc_dai { /* Symmetry data - only valid if symmetry is being enforced */ unsigned int rate; unsigned int channels; unsigned int sample_bits; /* parent platform/codec */ struct snd_soc_platform *platform; Loading include/sound/soc.h +2 −0 Original line number Diff line number Diff line Loading @@ -879,6 +879,8 @@ struct snd_soc_dai_link { /* Symmetry requirements */ unsigned int symmetric_rates:1; unsigned int symmetric_channels:1; unsigned int symmetric_samplebits:1; /* Do not create a PCM for this DAI link (Backend link) */ unsigned int no_pcm:1; Loading sound/soc/soc-pcm.c +130 −21 Original line number Diff line number Diff line Loading @@ -84,35 +84,117 @@ static int soc_pcm_apply_symmetry(struct snd_pcm_substream *substream, struct snd_soc_pcm_runtime *rtd = substream->private_data; int ret; if (!soc_dai->driver->symmetric_rates && !rtd->dai_link->symmetric_rates) return 0; if (soc_dai->rate && (soc_dai->driver->symmetric_rates || rtd->dai_link->symmetric_rates)) { dev_dbg(soc_dai->dev, "ASoC: Symmetry forces %dHz rate\n", soc_dai->rate); /* This can happen if multiple streams are starting simultaneously - * the second can need to get its constraints before the first has * picked a rate. Complain and allow the application to carry on. */ if (!soc_dai->rate) { dev_warn(soc_dai->dev, "ASoC: Not enforcing symmetric_rates due to race\n"); return 0; ret = snd_pcm_hw_constraint_minmax(substream->runtime, SNDRV_PCM_HW_PARAM_RATE, soc_dai->rate, soc_dai->rate); if (ret < 0) { dev_err(soc_dai->dev, "ASoC: Unable to apply rate constraint: %d\n", ret); return ret; } } dev_dbg(soc_dai->dev, "ASoC: Symmetry forces %dHz rate\n", soc_dai->rate); if (soc_dai->channels && (soc_dai->driver->symmetric_channels || rtd->dai_link->symmetric_channels)) { dev_dbg(soc_dai->dev, "ASoC: Symmetry forces %d channel(s)\n", soc_dai->channels); ret = snd_pcm_hw_constraint_minmax(substream->runtime, SNDRV_PCM_HW_PARAM_RATE, soc_dai->rate, soc_dai->rate); SNDRV_PCM_HW_PARAM_CHANNELS, soc_dai->channels, soc_dai->channels); if (ret < 0) { dev_err(soc_dai->dev, "ASoC: Unable to apply channel symmetry constraint: %d\n", ret); return ret; } } if (soc_dai->sample_bits && (soc_dai->driver->symmetric_samplebits || rtd->dai_link->symmetric_samplebits)) { dev_dbg(soc_dai->dev, "ASoC: Symmetry forces %d sample bits\n", soc_dai->sample_bits); ret = snd_pcm_hw_constraint_minmax(substream->runtime, SNDRV_PCM_HW_PARAM_SAMPLE_BITS, soc_dai->sample_bits, soc_dai->sample_bits); if (ret < 0) { dev_err(soc_dai->dev, "ASoC: Unable to apply rate symmetry constraint: %d\n", "ASoC: Unable to apply sample bits symmetry constraint: %d\n", ret); return ret; } } return 0; } static int soc_pcm_params_symmetry(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { 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; rate = params_rate(params); channels = params_channels(params); sample_bits = snd_pcm_format_physical_width(params_format(params)); /* reject unmatched parameters when applying symmetry */ symmetry = cpu_dai->driver->symmetric_rates || codec_dai->driver->symmetric_rates || rtd->dai_link->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); return -EINVAL; } symmetry = cpu_dai->driver->symmetric_channels || codec_dai->driver->symmetric_channels || rtd->dai_link->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); return -EINVAL; } symmetry = cpu_dai->driver->symmetric_samplebits || codec_dai->driver->symmetric_samplebits || rtd->dai_link->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); return -EINVAL; } return 0; } 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; 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; } /* * List of sample sizes that might go over the bus for parameter * application. There ought to be a wildcard sample size for things Loading Loading @@ -242,6 +324,9 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) &cpu_dai_drv->capture); } if (soc_pcm_has_symmetry(substream)) runtime->hw.info |= SNDRV_PCM_INFO_JOINT_DUPLEX; ret = -EINVAL; snd_pcm_limit_hw_rates(runtime); if (!runtime->hw.rates) { Loading Loading @@ -520,6 +605,10 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream, mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); ret = soc_pcm_params_symmetry(substream, params); if (ret) goto out; if (rtd->dai_link->ops && rtd->dai_link->ops->hw_params) { ret = rtd->dai_link->ops->hw_params(substream, params); if (ret < 0) { Loading Loading @@ -556,9 +645,16 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream, } } /* store the rate for each DAIs */ /* store the parameters for each DAIs */ cpu_dai->rate = params_rate(params); cpu_dai->channels = params_channels(params); 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); Loading Loading @@ -593,6 +689,19 @@ static int soc_pcm_hw_free(struct snd_pcm_substream *substream) mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); /* clear the corresponding DAIs parameters when going to be inactive */ if (cpu_dai->active == 1) { cpu_dai->rate = 0; cpu_dai->channels = 0; cpu_dai->sample_bits = 0; } if (codec_dai->active == 1) { codec_dai->rate = 0; codec_dai->channels = 0; codec_dai->sample_bits = 0; } /* apply codec digital mute */ if (!codec->active) snd_soc_dai_digital_mute(codec_dai, 1, substream->stream); Loading Loading
include/sound/soc-dai.h +6 −0 Original line number Diff line number Diff line Loading @@ -220,6 +220,8 @@ struct snd_soc_dai_driver { struct snd_soc_pcm_stream capture; struct snd_soc_pcm_stream playback; unsigned int symmetric_rates:1; unsigned int symmetric_channels:1; unsigned int symmetric_samplebits:1; /* probe ordering - for components with runtime dependencies */ int probe_order; Loading @@ -244,6 +246,8 @@ struct snd_soc_dai { unsigned int capture_active:1; /* stream is in use */ unsigned int playback_active:1; /* stream is in use */ unsigned int symmetric_rates:1; unsigned int symmetric_channels:1; unsigned int symmetric_samplebits:1; struct snd_pcm_runtime *runtime; unsigned int active; unsigned char probed:1; Loading @@ -258,6 +262,8 @@ struct snd_soc_dai { /* Symmetry data - only valid if symmetry is being enforced */ unsigned int rate; unsigned int channels; unsigned int sample_bits; /* parent platform/codec */ struct snd_soc_platform *platform; Loading
include/sound/soc.h +2 −0 Original line number Diff line number Diff line Loading @@ -879,6 +879,8 @@ struct snd_soc_dai_link { /* Symmetry requirements */ unsigned int symmetric_rates:1; unsigned int symmetric_channels:1; unsigned int symmetric_samplebits:1; /* Do not create a PCM for this DAI link (Backend link) */ unsigned int no_pcm:1; Loading
sound/soc/soc-pcm.c +130 −21 Original line number Diff line number Diff line Loading @@ -84,35 +84,117 @@ static int soc_pcm_apply_symmetry(struct snd_pcm_substream *substream, struct snd_soc_pcm_runtime *rtd = substream->private_data; int ret; if (!soc_dai->driver->symmetric_rates && !rtd->dai_link->symmetric_rates) return 0; if (soc_dai->rate && (soc_dai->driver->symmetric_rates || rtd->dai_link->symmetric_rates)) { dev_dbg(soc_dai->dev, "ASoC: Symmetry forces %dHz rate\n", soc_dai->rate); /* This can happen if multiple streams are starting simultaneously - * the second can need to get its constraints before the first has * picked a rate. Complain and allow the application to carry on. */ if (!soc_dai->rate) { dev_warn(soc_dai->dev, "ASoC: Not enforcing symmetric_rates due to race\n"); return 0; ret = snd_pcm_hw_constraint_minmax(substream->runtime, SNDRV_PCM_HW_PARAM_RATE, soc_dai->rate, soc_dai->rate); if (ret < 0) { dev_err(soc_dai->dev, "ASoC: Unable to apply rate constraint: %d\n", ret); return ret; } } dev_dbg(soc_dai->dev, "ASoC: Symmetry forces %dHz rate\n", soc_dai->rate); if (soc_dai->channels && (soc_dai->driver->symmetric_channels || rtd->dai_link->symmetric_channels)) { dev_dbg(soc_dai->dev, "ASoC: Symmetry forces %d channel(s)\n", soc_dai->channels); ret = snd_pcm_hw_constraint_minmax(substream->runtime, SNDRV_PCM_HW_PARAM_RATE, soc_dai->rate, soc_dai->rate); SNDRV_PCM_HW_PARAM_CHANNELS, soc_dai->channels, soc_dai->channels); if (ret < 0) { dev_err(soc_dai->dev, "ASoC: Unable to apply channel symmetry constraint: %d\n", ret); return ret; } } if (soc_dai->sample_bits && (soc_dai->driver->symmetric_samplebits || rtd->dai_link->symmetric_samplebits)) { dev_dbg(soc_dai->dev, "ASoC: Symmetry forces %d sample bits\n", soc_dai->sample_bits); ret = snd_pcm_hw_constraint_minmax(substream->runtime, SNDRV_PCM_HW_PARAM_SAMPLE_BITS, soc_dai->sample_bits, soc_dai->sample_bits); if (ret < 0) { dev_err(soc_dai->dev, "ASoC: Unable to apply rate symmetry constraint: %d\n", "ASoC: Unable to apply sample bits symmetry constraint: %d\n", ret); return ret; } } return 0; } static int soc_pcm_params_symmetry(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { 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; rate = params_rate(params); channels = params_channels(params); sample_bits = snd_pcm_format_physical_width(params_format(params)); /* reject unmatched parameters when applying symmetry */ symmetry = cpu_dai->driver->symmetric_rates || codec_dai->driver->symmetric_rates || rtd->dai_link->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); return -EINVAL; } symmetry = cpu_dai->driver->symmetric_channels || codec_dai->driver->symmetric_channels || rtd->dai_link->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); return -EINVAL; } symmetry = cpu_dai->driver->symmetric_samplebits || codec_dai->driver->symmetric_samplebits || rtd->dai_link->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); return -EINVAL; } return 0; } 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; 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; } /* * List of sample sizes that might go over the bus for parameter * application. There ought to be a wildcard sample size for things Loading Loading @@ -242,6 +324,9 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) &cpu_dai_drv->capture); } if (soc_pcm_has_symmetry(substream)) runtime->hw.info |= SNDRV_PCM_INFO_JOINT_DUPLEX; ret = -EINVAL; snd_pcm_limit_hw_rates(runtime); if (!runtime->hw.rates) { Loading Loading @@ -520,6 +605,10 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream, mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); ret = soc_pcm_params_symmetry(substream, params); if (ret) goto out; if (rtd->dai_link->ops && rtd->dai_link->ops->hw_params) { ret = rtd->dai_link->ops->hw_params(substream, params); if (ret < 0) { Loading Loading @@ -556,9 +645,16 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream, } } /* store the rate for each DAIs */ /* store the parameters for each DAIs */ cpu_dai->rate = params_rate(params); cpu_dai->channels = params_channels(params); 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); Loading Loading @@ -593,6 +689,19 @@ static int soc_pcm_hw_free(struct snd_pcm_substream *substream) mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); /* clear the corresponding DAIs parameters when going to be inactive */ if (cpu_dai->active == 1) { cpu_dai->rate = 0; cpu_dai->channels = 0; cpu_dai->sample_bits = 0; } if (codec_dai->active == 1) { codec_dai->rate = 0; codec_dai->channels = 0; codec_dai->sample_bits = 0; } /* apply codec digital mute */ if (!codec->active) snd_soc_dai_digital_mute(codec_dai, 1, substream->stream); Loading