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: Peter Ujfalusi <peter.ujfalusi@ti.com> Link: https://lore.kernel.org/r/20191008115720.7135-1-peter.ujfalusi@ti.com Signed-off-by: Mark Brown <broonie@kernel.org>
This commit is contained in:
parent
1466327e8e
commit
cfc28ac124
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue