4040/* Default DAI format without Master and Slave flag */
4141#define DAI_FMT_BASE (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF)
4242
43+ static const u32 cs42888_rates_48k [] = {
44+ 48000 , 96000 , 192000 ,
45+ };
46+
47+ static const u32 cs42888_rates_44k [] = {
48+ 44100 , 88200 , 176400 ,
49+ };
50+
51+ static const u32 cs42888_channels [] = {
52+ 1 , 2 , 4 , 6 , 8 ,
53+ };
54+
4355/**
4456 * struct codec_priv - CODEC private data
4557 * @mclk: Main clock of the CODEC
4860 * @mclk_id: MCLK (or main clock) id for set_sysclk()
4961 * @fll_id: FLL (or secordary clock) id for set_sysclk()
5062 * @pll_id: PLL id for set_pll()
63+ * @pll_ratio_s24: PLL output ratio for S24_LE format (PLL_freq = sample_rate × ratio)
64+ * Default is 384, but some codecs (e.g., WM8904) require lower values
65+ * to stay within PLL frequency limits
5166 */
5267struct codec_priv {
5368 struct clk * mclk ;
@@ -56,6 +71,7 @@ struct codec_priv {
5671 u32 mclk_id ;
5772 int fll_id ;
5873 int pll_id ;
74+ int pll_ratio_s24 ;
5975};
6076
6177/**
@@ -93,6 +109,10 @@ struct cpu_priv {
93109 * @asrc_rate: ASRC sample rate used by Back-Ends
94110 * @asrc_format: ASRC sample format used by Back-Ends
95111 * @dai_fmt: DAI format between CPU and CODEC
112+ * @support_rates: array of supported rates
113+ * @support_channels: array of supported channels
114+ * @num_rates: Number of entries in support_rates array
115+ * @num_channels: Number of entries in support_channels array
96116 * @name: Card name
97117 */
98118
@@ -110,6 +130,10 @@ struct fsl_asoc_card_priv {
110130 u32 asrc_rate ;
111131 snd_pcm_format_t asrc_format ;
112132 u32 dai_fmt ;
133+ const u32 * support_rates ;
134+ const u32 * support_channels ;
135+ u32 num_rates ;
136+ u32 num_channels ;
113137 char name [32 ];
114138};
115139
@@ -222,7 +246,7 @@ static int fsl_asoc_card_hw_params(struct snd_pcm_substream *substream,
222246
223247 if (codec_priv -> pll_id >= 0 && codec_priv -> fll_id >= 0 ) {
224248 if (priv -> sample_format == SNDRV_PCM_FORMAT_S24_LE )
225- pll_out = priv -> sample_rate * 384 ;
249+ pll_out = priv -> sample_rate * codec_priv -> pll_ratio_s24 ;
226250 else
227251 pll_out = priv -> sample_rate * 256 ;
228252
@@ -291,7 +315,51 @@ static int fsl_asoc_card_hw_free(struct snd_pcm_substream *substream)
291315 return 0 ;
292316}
293317
318+ static int fsl_asoc_card_startup (struct snd_pcm_substream * substream )
319+ {
320+ struct snd_soc_pcm_runtime * rtd = substream -> private_data ;
321+ struct fsl_asoc_card_priv * priv = snd_soc_card_get_drvdata (rtd -> card );
322+ struct snd_pcm_runtime * runtime = substream -> runtime ;
323+ static struct snd_pcm_hw_constraint_list constraint_rates ;
324+ static struct snd_pcm_hw_constraint_list constraint_channels ;
325+ int ret ;
326+
327+ /*
328+ * Remove S20_3LE as the clock (sysclk, bclk) can't be acquired
329+ * due to non-integer divider ratios.
330+ */
331+ ret = snd_pcm_hw_constraint_mask64 (runtime ,
332+ SNDRV_PCM_HW_PARAM_FORMAT ,
333+ ~SNDRV_PCM_FMTBIT_S20_3LE );
334+ if (ret )
335+ return ret ;
336+
337+ constraint_channels .list = priv -> support_channels ;
338+ constraint_channels .count = priv -> num_channels ;
339+ constraint_rates .list = priv -> support_rates ;
340+ constraint_rates .count = priv -> num_rates ;
341+
342+ if (constraint_channels .count ) {
343+ ret = snd_pcm_hw_constraint_list (runtime , 0 ,
344+ SNDRV_PCM_HW_PARAM_CHANNELS ,
345+ & constraint_channels );
346+ if (ret )
347+ return ret ;
348+ }
349+
350+ if (constraint_rates .count ) {
351+ ret = snd_pcm_hw_constraint_list (runtime , 0 ,
352+ SNDRV_PCM_HW_PARAM_RATE ,
353+ & constraint_rates );
354+ if (ret )
355+ return ret ;
356+ }
357+
358+ return 0 ;
359+ }
360+
294361static const struct snd_soc_ops fsl_asoc_card_ops = {
362+ .startup = fsl_asoc_card_startup ,
295363 .hw_params = fsl_asoc_card_hw_params ,
296364 .hw_free = fsl_asoc_card_hw_free ,
297365};
@@ -742,6 +810,7 @@ static int fsl_asoc_card_probe(struct platform_device *pdev)
742810 for (codec_idx = 0 ; codec_idx < 2 ; codec_idx ++ ) {
743811 priv -> codec_priv [codec_idx ].fll_id = -1 ;
744812 priv -> codec_priv [codec_idx ].pll_id = -1 ;
813+ priv -> codec_priv [codec_idx ].pll_ratio_s24 = 384 ;
745814 }
746815
747816 /* Diversify the card configurations */
@@ -753,6 +822,19 @@ static int fsl_asoc_card_probe(struct platform_device *pdev)
753822 priv -> cpu_priv .sysclk_dir [RX ] = SND_SOC_CLOCK_OUT ;
754823 priv -> cpu_priv .slot_width = 32 ;
755824 priv -> dai_fmt |= SND_SOC_DAIFMT_CBC_CFC ;
825+ priv -> support_channels = cs42888_channels ;
826+ priv -> num_channels = ARRAY_SIZE (cs42888_channels );
827+ if (priv -> codec_priv [0 ].mclk_freq % 12288000 == 0 ) {
828+ priv -> support_rates = cs42888_rates_48k ;
829+ priv -> num_rates = ARRAY_SIZE (cs42888_rates_48k );
830+ } else if (priv -> codec_priv [0 ].mclk_freq % 11289600 == 0 ) {
831+ priv -> support_rates = cs42888_rates_44k ;
832+ priv -> num_rates = ARRAY_SIZE (cs42888_rates_44k );
833+ } else {
834+ /* Unknown MCLK, no rate constraints */
835+ dev_warn (& pdev -> dev , "Unknown MCLK frequency %lu, no rate constraints\n" ,
836+ priv -> codec_priv [0 ].mclk_freq );
837+ }
756838 } else if (of_device_is_compatible (np , "fsl,imx-audio-cs427x" )) {
757839 codec_dai_name [0 ] = "cs4271-hifi" ;
758840 priv -> codec_priv [0 ].mclk_id = CS427x_SYSCLK_MCLK ;
@@ -835,6 +917,7 @@ static int fsl_asoc_card_probe(struct platform_device *pdev)
835917 priv -> codec_priv [0 ].mclk_id = WM8904_FLL_MCLK ;
836918 priv -> codec_priv [0 ].fll_id = WM8904_CLK_FLL ;
837919 priv -> codec_priv [0 ].pll_id = WM8904_FLL_MCLK ;
920+ priv -> codec_priv [0 ].pll_ratio_s24 = 192 ;
838921 priv -> dai_fmt |= SND_SOC_DAIFMT_CBP_CFP ;
839922 } else if (of_device_is_compatible (np , "fsl,imx-audio-spdif" )) {
840923 ret = fsl_asoc_card_spdif_init (codec_np , cpu_np , codec_dai_name , priv );
@@ -989,6 +1072,8 @@ static int fsl_asoc_card_probe(struct platform_device *pdev)
9891072
9901073 if (asrc_pdev ) {
9911074 /* DPCM DAI Links only if ASRC exists */
1075+ priv -> dai_link [1 ].dpcm_merged_chan = 1 ;
1076+ priv -> dai_link [1 ].ignore_pmdown_time = 1 ;
9921077 priv -> dai_link [1 ].cpus -> of_node = asrc_np ;
9931078 priv -> dai_link [1 ].platforms -> of_node = asrc_np ;
9941079 for_each_link_codecs ((& (priv -> dai_link [2 ])), codec_idx , codec_comp ) {
@@ -998,6 +1083,7 @@ static int fsl_asoc_card_probe(struct platform_device *pdev)
9981083 }
9991084 priv -> dai_link [2 ].cpus -> of_node = cpu_np ;
10001085 priv -> dai_link [2 ].dai_fmt = priv -> dai_fmt ;
1086+ priv -> dai_link [2 ].ignore_pmdown_time = 1 ;
10011087 priv -> card .num_links = 3 ;
10021088
10031089 ret = of_property_read_u32 (asrc_np , "fsl,asrc-rate" ,
0 commit comments