Merge remote-tracking branch 'asoc/topic/symmetry' into asoc-fsl
This commit is contained in:
commit
e73462f573
3 changed files with 138 additions and 28 deletions
|
|
@ -220,6 +220,8 @@ struct snd_soc_dai_driver {
|
||||||
struct snd_soc_pcm_stream capture;
|
struct snd_soc_pcm_stream capture;
|
||||||
struct snd_soc_pcm_stream playback;
|
struct snd_soc_pcm_stream playback;
|
||||||
unsigned int symmetric_rates:1;
|
unsigned int symmetric_rates:1;
|
||||||
|
unsigned int symmetric_channels:1;
|
||||||
|
unsigned int symmetric_samplebits:1;
|
||||||
|
|
||||||
/* probe ordering - for components with runtime dependencies */
|
/* probe ordering - for components with runtime dependencies */
|
||||||
int probe_order;
|
int probe_order;
|
||||||
|
|
@ -244,6 +246,8 @@ struct snd_soc_dai {
|
||||||
unsigned int capture_active:1; /* stream is in use */
|
unsigned int capture_active:1; /* stream is in use */
|
||||||
unsigned int playback_active:1; /* stream is in use */
|
unsigned int playback_active:1; /* stream is in use */
|
||||||
unsigned int symmetric_rates:1;
|
unsigned int symmetric_rates:1;
|
||||||
|
unsigned int symmetric_channels:1;
|
||||||
|
unsigned int symmetric_samplebits:1;
|
||||||
struct snd_pcm_runtime *runtime;
|
struct snd_pcm_runtime *runtime;
|
||||||
unsigned int active;
|
unsigned int active;
|
||||||
unsigned char probed:1;
|
unsigned char probed:1;
|
||||||
|
|
@ -258,6 +262,8 @@ struct snd_soc_dai {
|
||||||
|
|
||||||
/* Symmetry data - only valid if symmetry is being enforced */
|
/* Symmetry data - only valid if symmetry is being enforced */
|
||||||
unsigned int rate;
|
unsigned int rate;
|
||||||
|
unsigned int channels;
|
||||||
|
unsigned int sample_bits;
|
||||||
|
|
||||||
/* parent platform/codec */
|
/* parent platform/codec */
|
||||||
struct snd_soc_platform *platform;
|
struct snd_soc_platform *platform;
|
||||||
|
|
|
||||||
|
|
@ -879,6 +879,8 @@ struct snd_soc_dai_link {
|
||||||
|
|
||||||
/* Symmetry requirements */
|
/* Symmetry requirements */
|
||||||
unsigned int symmetric_rates:1;
|
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) */
|
/* Do not create a PCM for this DAI link (Backend link) */
|
||||||
unsigned int no_pcm:1;
|
unsigned int no_pcm:1;
|
||||||
|
|
|
||||||
|
|
@ -84,35 +84,117 @@ static int soc_pcm_apply_symmetry(struct snd_pcm_substream *substream,
|
||||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (!soc_dai->driver->symmetric_rates &&
|
if (soc_dai->rate && (soc_dai->driver->symmetric_rates ||
|
||||||
!rtd->dai_link->symmetric_rates)
|
rtd->dai_link->symmetric_rates)) {
|
||||||
return 0;
|
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
dev_dbg(soc_dai->dev, "ASoC: Symmetry forces %dHz rate\n", soc_dai->rate);
|
|
||||||
|
|
||||||
ret = snd_pcm_hw_constraint_minmax(substream->runtime,
|
ret = snd_pcm_hw_constraint_minmax(substream->runtime,
|
||||||
SNDRV_PCM_HW_PARAM_RATE,
|
SNDRV_PCM_HW_PARAM_RATE,
|
||||||
soc_dai->rate, soc_dai->rate);
|
soc_dai->rate, soc_dai->rate);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
dev_err(soc_dai->dev,
|
dev_err(soc_dai->dev,
|
||||||
"ASoC: Unable to apply rate symmetry constraint: %d\n",
|
"ASoC: Unable to apply rate constraint: %d\n",
|
||||||
ret);
|
ret);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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_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 sample bits symmetry constraint: %d\n",
|
||||||
|
ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
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
|
* List of sample sizes that might go over the bus for parameter
|
||||||
* application. There ought to be a wildcard sample size for things
|
* application. There ought to be a wildcard sample size for things
|
||||||
|
|
@ -242,6 +324,9 @@ static int soc_pcm_open(struct snd_pcm_substream *substream)
|
||||||
&cpu_dai_drv->capture);
|
&cpu_dai_drv->capture);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (soc_pcm_has_symmetry(substream))
|
||||||
|
runtime->hw.info |= SNDRV_PCM_INFO_JOINT_DUPLEX;
|
||||||
|
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
snd_pcm_limit_hw_rates(runtime);
|
snd_pcm_limit_hw_rates(runtime);
|
||||||
if (!runtime->hw.rates) {
|
if (!runtime->hw.rates) {
|
||||||
|
|
@ -383,13 +468,6 @@ static int soc_pcm_close(struct snd_pcm_substream *substream)
|
||||||
codec_dai->active--;
|
codec_dai->active--;
|
||||||
codec->active--;
|
codec->active--;
|
||||||
|
|
||||||
/* clear the corresponding DAIs rate when inactive */
|
|
||||||
if (!cpu_dai->active)
|
|
||||||
cpu_dai->rate = 0;
|
|
||||||
|
|
||||||
if (!codec_dai->active)
|
|
||||||
codec_dai->rate = 0;
|
|
||||||
|
|
||||||
/* Muting the DAC suppresses artifacts caused during digital
|
/* Muting the DAC suppresses artifacts caused during digital
|
||||||
* shutdown, for example from stopping clocks.
|
* shutdown, for example from stopping clocks.
|
||||||
*/
|
*/
|
||||||
|
|
@ -525,6 +603,10 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream,
|
||||||
|
|
||||||
mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
|
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) {
|
if (rtd->dai_link->ops && rtd->dai_link->ops->hw_params) {
|
||||||
ret = rtd->dai_link->ops->hw_params(substream, params);
|
ret = rtd->dai_link->ops->hw_params(substream, params);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
|
|
@ -561,9 +643,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->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->rate = params_rate(params);
|
||||||
|
codec_dai->channels = params_channels(params);
|
||||||
|
codec_dai->sample_bits =
|
||||||
|
snd_pcm_format_physical_width(params_format(params));
|
||||||
|
|
||||||
out:
|
out:
|
||||||
mutex_unlock(&rtd->pcm_mutex);
|
mutex_unlock(&rtd->pcm_mutex);
|
||||||
|
|
@ -598,6 +687,19 @@ static int soc_pcm_hw_free(struct snd_pcm_substream *substream)
|
||||||
|
|
||||||
mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
|
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 */
|
/* apply codec digital mute */
|
||||||
if (!codec->active)
|
if (!codec->active)
|
||||||
snd_soc_dai_digital_mute(codec_dai, 1, substream->stream);
|
snd_soc_dai_digital_mute(codec_dai, 1, substream->stream);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue