Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 07ac582c authored by Mark Brown's avatar Mark Brown
Browse files

Merge remote-tracking branch 'asoc/topic/symmetry' into asoc-core

Conflicts (Trivial add/delete):
	sound/soc/soc-pcm.c
parents 0b4bbae8 62e5f676
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -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;
@@ -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;
@@ -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;
+2 −0
Original line number Diff line number Diff line
@@ -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;
+130 −21
Original line number Diff line number Diff line
@@ -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
@@ -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) {
@@ -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) {
@@ -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);
@@ -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);