Skip to content

Commit 9e065e9

Browse files
author
Fox Snowpatch
committed
1 parent 182544a commit 9e065e9

1 file changed

Lines changed: 87 additions & 1 deletion

File tree

sound/soc/fsl/fsl-asoc-card.c

Lines changed: 87 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,18 @@
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
@@ -48,6 +60,9 @@
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
*/
5267
struct 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+
294361
static 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

Comments
 (0)