[PATCH] ASoC: fsl_ssi: remove unsupported formats in i2s master mode
From: Sven Van Asbroeck
Date: Thu Feb 21 2019 - 10:35:58 EST
Quote from the ssi manual:
"The word length is fixed to 32 in I2S Master mode and
the WL bits determine the number of bits that will
contain valid data (out of the 32 transmitted/received
bits in each channel)."
(61.8.1.4, page 5138, IMX6DQRM Rev. 3, 07/2015)
In other words, in i2s master mode, we always get 32
physical bits/channel, no matter what.
However, the supported list of formats for this ssi
contains S8, S16_XX, S18_3XX, and S20_3XX, which have
8, 16, 24 and 24 physical bits/channel respectively.
If one of these is selected in i2s master mode, the
format generated by the ssi will be incorrect.
Fix by constraining the frame bits in i2s master mode
to 32 * channels. This will filter out those formats
that the ssi cannot support.
Tested on imx6 with tda998x and sgtl5k codecs.
Cc: Timur Tabi <timur@xxxxxxxxxx>
Cc: Nicolin Chen <nicoleotsuka@xxxxxxxxx>
Cc: Xiubo Li <Xiubo.Lee@xxxxxxxxx>
Cc: Fabio Estevam <festevam@xxxxxxxxx>
Cc: Liam Girdwood <lgirdwood@xxxxxxxxx>
Cc: Mark Brown <broonie@xxxxxxxxxx>
Cc: Jaroslav Kysela <perex@xxxxxxxx>
Cc: Takashi Iwai <tiwai@xxxxxxxx>
Signed-off-by: Sven Van Asbroeck <TheSven73@xxxxxxxxx>
---
sound/soc/fsl/fsl_ssi.c | 28 ++++++++++++++++++++++++++++
1 file changed, 28 insertions(+)
diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c
index 0a648229e643..3d375f60ecf4 100644
--- a/sound/soc/fsl/fsl_ssi.c
+++ b/sound/soc/fsl/fsl_ssi.c
@@ -627,6 +627,28 @@ static void fsl_ssi_setup_ac97(struct fsl_ssi *ssi)
regmap_write(regs, REG_SSI_SOR, SSI_SOR_WAIT(3));
}
+static int fsl_ssi_hw_rule_i2s_master(struct snd_pcm_hw_params *params,
+ struct snd_pcm_hw_rule *rule)
+{
+ struct snd_interval *it = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_FRAME_BITS);
+ struct fsl_ssi *ssi = rule->private;
+ struct snd_interval t;
+
+ if (!fsl_ssi_is_i2s_master(ssi))
+ return 0;
+
+ /*
+ * In i2s master mode, the ssi always generates 32 physical
+ * bits/channel. Filter out formats that don't have 32 physical
+ * bits/channel, they are unsupported.
+ */
+ memset(&t, 0, sizeof(t));
+ t.min = t.max = params_channels(params) * 32;
+
+ return snd_interval_refine(it, &t);
+}
+
static int fsl_ssi_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
@@ -648,6 +670,12 @@ static int fsl_ssi_startup(struct snd_pcm_substream *substream,
snd_pcm_hw_constraint_step(substream->runtime, 0,
SNDRV_PCM_HW_PARAM_PERIOD_SIZE, 2);
+ snd_pcm_hw_rule_add(substream->runtime, 0,
+ SNDRV_PCM_HW_PARAM_FRAME_BITS,
+ fsl_ssi_hw_rule_i2s_master, ssi,
+ SNDRV_PCM_HW_PARAM_FORMAT, SNDRV_PCM_HW_PARAM_CHANNELS,
+ -1);
+
return 0;
}
--
2.17.1