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 -
 | 
							ret = snd_pcm_hw_constraint_minmax(substream->runtime,
 | 
				
			||||||
	 * the second can need to get its constraints before the first has
 | 
											SNDRV_PCM_HW_PARAM_RATE,
 | 
				
			||||||
	 * picked a rate.  Complain and allow the application to carry on.
 | 
											soc_dai->rate, soc_dai->rate);
 | 
				
			||||||
	 */
 | 
							if (ret < 0) {
 | 
				
			||||||
	if (!soc_dai->rate) {
 | 
								dev_err(soc_dai->dev,
 | 
				
			||||||
		dev_warn(soc_dai->dev,
 | 
									"ASoC: Unable to apply rate constraint: %d\n",
 | 
				
			||||||
			 "ASoC: Not enforcing symmetric_rates due to race\n");
 | 
									ret);
 | 
				
			||||||
		return 0;
 | 
								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,
 | 
							ret = snd_pcm_hw_constraint_minmax(substream->runtime,
 | 
				
			||||||
					   SNDRV_PCM_HW_PARAM_RATE,
 | 
											SNDRV_PCM_HW_PARAM_CHANNELS,
 | 
				
			||||||
					   soc_dai->rate, soc_dai->rate);
 | 
											soc_dai->channels,
 | 
				
			||||||
	if (ret < 0) {
 | 
											soc_dai->channels);
 | 
				
			||||||
		dev_err(soc_dai->dev,
 | 
							if (ret < 0) {
 | 
				
			||||||
			"ASoC: Unable to apply rate symmetry constraint: %d\n",
 | 
								dev_err(soc_dai->dev,
 | 
				
			||||||
			ret);
 | 
									"ASoC: Unable to apply channel symmetry constraint: %d\n",
 | 
				
			||||||
		return ret;
 | 
									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