Commit f1c775ac authored by Peter Ujfalusi's avatar Peter Ujfalusi Committed by Khalid Elmously

ASoC: ti: davinci-mcasp: Correct slot_width posed constraint

BugLink: https://bugs.launchpad.net/bugs/1845036

[ Upstream commit 1e112c35 ]

The slot_width is a property for the bus while the constraint for
SNDRV_PCM_HW_PARAM_SAMPLE_BITS is for the in memory format.

Applying slot_width constraint to sample_bits works most of the time, but
it will blacklist valid formats in some cases.

With slot_width 24 we can support S24_3LE and S24_LE formats as they both
look the same on the bus, but a a 24 constraint on sample_bits would not
allow S24_LE as it is stored in 32bits in memory.

Implement a simple hw_rule function to allow all formats which require less
or equal number of bits on the bus as slot_width (if configured).
Signed-off-by: default avatarPeter Ujfalusi <peter.ujfalusi@ti.com>
Link: https://lore.kernel.org/r/20190726064244.3762-2-peter.ujfalusi@ti.comSigned-off-by: default avatarMark Brown <broonie@kernel.org>
Signed-off-by: default avatarSasha Levin <sashal@kernel.org>
Signed-off-by: default avatarConnor Kuehl <connor.kuehl@canonical.com>
Signed-off-by: default avatarKhalid Elmously <khalid.elmously@canonical.com>
parent e82e90c3
...@@ -1128,6 +1128,28 @@ static int davinci_mcasp_trigger(struct snd_pcm_substream *substream, ...@@ -1128,6 +1128,28 @@ static int davinci_mcasp_trigger(struct snd_pcm_substream *substream,
return ret; return ret;
} }
static int davinci_mcasp_hw_rule_slot_width(struct snd_pcm_hw_params *params,
struct snd_pcm_hw_rule *rule)
{
struct davinci_mcasp_ruledata *rd = rule->private;
struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
struct snd_mask nfmt;
int i, slot_width;
snd_mask_none(&nfmt);
slot_width = rd->mcasp->slot_width;
for (i = 0; i <= SNDRV_PCM_FORMAT_LAST; i++) {
if (snd_mask_test(fmt, i)) {
if (snd_pcm_format_width(i) <= slot_width) {
snd_mask_set(&nfmt, i);
}
}
}
return snd_mask_refine(fmt, &nfmt);
}
static const unsigned int davinci_mcasp_dai_rates[] = { static const unsigned int davinci_mcasp_dai_rates[] = {
8000, 11025, 16000, 22050, 32000, 44100, 48000, 64000, 8000, 11025, 16000, 22050, 32000, 44100, 48000, 64000,
88200, 96000, 176400, 192000, 88200, 96000, 176400, 192000,
...@@ -1219,7 +1241,7 @@ static int davinci_mcasp_startup(struct snd_pcm_substream *substream, ...@@ -1219,7 +1241,7 @@ static int davinci_mcasp_startup(struct snd_pcm_substream *substream,
struct davinci_mcasp_ruledata *ruledata = struct davinci_mcasp_ruledata *ruledata =
&mcasp->ruledata[substream->stream]; &mcasp->ruledata[substream->stream];
u32 max_channels = 0; u32 max_channels = 0;
int i, dir; int i, dir, ret;
int tdm_slots = mcasp->tdm_slots; int tdm_slots = mcasp->tdm_slots;
if (mcasp->tdm_mask[substream->stream]) if (mcasp->tdm_mask[substream->stream])
...@@ -1244,6 +1266,7 @@ static int davinci_mcasp_startup(struct snd_pcm_substream *substream, ...@@ -1244,6 +1266,7 @@ static int davinci_mcasp_startup(struct snd_pcm_substream *substream,
max_channels++; max_channels++;
} }
ruledata->serializers = max_channels; ruledata->serializers = max_channels;
ruledata->mcasp = mcasp;
max_channels *= tdm_slots; max_channels *= tdm_slots;
/* /*
* If the already active stream has less channels than the calculated * If the already active stream has less channels than the calculated
...@@ -1269,20 +1292,22 @@ static int davinci_mcasp_startup(struct snd_pcm_substream *substream, ...@@ -1269,20 +1292,22 @@ static int davinci_mcasp_startup(struct snd_pcm_substream *substream,
0, SNDRV_PCM_HW_PARAM_CHANNELS, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
&mcasp->chconstr[substream->stream]); &mcasp->chconstr[substream->stream]);
if (mcasp->slot_width) if (mcasp->slot_width) {
snd_pcm_hw_constraint_minmax(substream->runtime, /* Only allow formats require <= slot_width bits on the bus */
SNDRV_PCM_HW_PARAM_SAMPLE_BITS, ret = snd_pcm_hw_rule_add(substream->runtime, 0,
8, mcasp->slot_width); SNDRV_PCM_HW_PARAM_FORMAT,
davinci_mcasp_hw_rule_slot_width,
ruledata,
SNDRV_PCM_HW_PARAM_FORMAT, -1);
if (ret)
return ret;
}
/* /*
* If we rely on implicit BCLK divider setting we should * If we rely on implicit BCLK divider setting we should
* set constraints based on what we can provide. * set constraints based on what we can provide.
*/ */
if (mcasp->bclk_master && mcasp->bclk_div == 0 && mcasp->sysclk_freq) { if (mcasp->bclk_master && mcasp->bclk_div == 0 && mcasp->sysclk_freq) {
int ret;
ruledata->mcasp = mcasp;
ret = snd_pcm_hw_rule_add(substream->runtime, 0, ret = snd_pcm_hw_rule_add(substream->runtime, 0,
SNDRV_PCM_HW_PARAM_RATE, SNDRV_PCM_HW_PARAM_RATE,
davinci_mcasp_hw_rule_rate, davinci_mcasp_hw_rule_rate,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment