Unverified Commit cfc28ac1 authored by Peter Ujfalusi's avatar Peter Ujfalusi Committed by Mark Brown
Browse files

ASoC: pcm3168a: Use fixup instead of constraint for channels and formats



The snd_pcm_hw_constraint_minmax() works fine when a single codec is
connected to a single CPU DAI, but in multicodec or DPCM setup the
constraints placed by the driver will apply to the whole PCM stream (FE
included) and thus prevents more than 8 playback channels for example.

Signed-off-by: default avatarPeter Ujfalusi <peter.ujfalusi@ti.com>
Link: https://lore.kernel.org/r/20191008115720.7135-1-peter.ujfalusi@ti.com


Signed-off-by: default avatarMark Brown <broonie@kernel.org>
parent 1466327e
Loading
Loading
Loading
Loading
+40 −58
Original line number Diff line number Diff line
@@ -62,6 +62,7 @@ struct pcm3168a_priv {
	unsigned long sysclk;

	struct pcm3168a_io_params io_params[2];
	struct snd_soc_dai_driver dai_drv[2];
};

static const char *const pcm3168a_roll_off[] = { "Sharp", "Slow" };
@@ -314,6 +315,37 @@ static int pcm3168a_set_dai_sysclk(struct snd_soc_dai *dai,
	return 0;
}

static void pcm3168a_update_fixup_pcm_stream(struct snd_soc_dai *dai)
{
	struct snd_soc_component *component = dai->component;
	struct pcm3168a_priv *pcm3168a = snd_soc_component_get_drvdata(component);
	u64 formats = SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_LE;
	unsigned int channel_max = dai->id == PCM3168A_DAI_DAC ? 8 : 6;

	if (!pcm3168a->io_params[dai->id].fmt)
		return;

	if (pcm3168a->io_params[dai->id].fmt == PCM3168A_FMT_RIGHT_J) {
		/* S16_LE is only supported in RIGHT_J mode */
		formats |= SNDRV_PCM_FMTBIT_S16_LE;

		/*
		 * If multi DIN/DOUT is not selected, RIGHT_J can only support
		 * two channels (no TDM support)
		 */
		if (pcm3168a->io_params[dai->id].tdm_slots != 2)
			channel_max = 2;
	}

	if (dai->id == PCM3168A_DAI_DAC) {
		dai->driver->playback.channels_max = channel_max;
		dai->driver->playback.formats = formats;
	} else {
		dai->driver->capture.channels_max = channel_max;
		dai->driver->capture.formats = formats;
	}
}

static int pcm3168a_set_dai_fmt(struct snd_soc_dai *dai, unsigned int format)
{
	struct snd_soc_component *component = dai->component;
@@ -376,6 +408,8 @@ static int pcm3168a_set_dai_fmt(struct snd_soc_dai *dai, unsigned int format)

	regmap_update_bits(pcm3168a->regmap, reg, mask, fmt << shift);

	pcm3168a_update_fixup_pcm_stream(dai);

	return 0;
}

@@ -409,6 +443,8 @@ static int pcm3168a_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
	else
		io_params->tdm_mask = rx_mask;

	pcm3168a_update_fixup_pcm_stream(dai);

	return 0;
}

@@ -530,63 +566,7 @@ static int pcm3168a_hw_params(struct snd_pcm_substream *substream,
	return 0;
}

static int pcm3168a_startup(struct snd_pcm_substream *substream,
			    struct snd_soc_dai *dai)
{
	struct snd_soc_component *component = dai->component;
	struct pcm3168a_priv *pcm3168a = snd_soc_component_get_drvdata(component);
	unsigned int sample_min;
	unsigned int channel_max;
	unsigned int channel_maxs[] = {
		8, /* DAC */
		6  /* ADC */
	};

	/*
	 * Available Data Bits
	 *
	 * RIGHT_J : 24 / 16
	 * LEFT_J  : 24
	 * I2S     : 24
	 *
	 * TDM available
	 *
	 * I2S
	 * LEFT_J
	 */
	switch (pcm3168a->io_params[dai->id].fmt) {
	case PCM3168A_FMT_RIGHT_J:
		sample_min  = 16;
		channel_max =  2;
		break;
	case PCM3168A_FMT_LEFT_J:
	case PCM3168A_FMT_I2S:
	case PCM3168A_FMT_DSP_A:
	case PCM3168A_FMT_DSP_B:
		sample_min  = 24;
		channel_max = channel_maxs[dai->id];
		break;
	default:
		sample_min  = 24;
		channel_max =  2;
	}

	snd_pcm_hw_constraint_minmax(substream->runtime,
				     SNDRV_PCM_HW_PARAM_SAMPLE_BITS,
				     sample_min, 32);

	/* Allow all channels in multi DIN/DOUT mode */
	if (pcm3168a->io_params[dai->id].tdm_slots == 2)
		channel_max = channel_maxs[dai->id];

	snd_pcm_hw_constraint_minmax(substream->runtime,
				     SNDRV_PCM_HW_PARAM_CHANNELS,
				     2, channel_max);

	return 0;
}
static const struct snd_soc_dai_ops pcm3168a_dai_ops = {
	.startup	= pcm3168a_startup,
	.set_fmt	= pcm3168a_set_dai_fmt,
	.set_sysclk	= pcm3168a_set_dai_sysclk,
	.hw_params	= pcm3168a_hw_params,
@@ -776,8 +756,10 @@ int pcm3168a_probe(struct device *dev, struct regmap *regmap)
	pm_runtime_enable(dev);
	pm_runtime_idle(dev);

	ret = devm_snd_soc_register_component(dev, &pcm3168a_driver, pcm3168a_dais,
			ARRAY_SIZE(pcm3168a_dais));
	memcpy(pcm3168a->dai_drv, pcm3168a_dais, sizeof(pcm3168a->dai_drv));
	ret = devm_snd_soc_register_component(dev, &pcm3168a_driver,
					      pcm3168a->dai_drv,
					      ARRAY_SIZE(pcm3168a->dai_drv));
	if (ret) {
		dev_err(dev, "failed to register component: %d\n", ret);
		goto err_regulator;