xref: /linux/sound/soc/mediatek/mt8188/mt8188-dai-pcm.c (revision 3d0fe49454652117522f60bfbefb978ba0e5300b)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * MediaTek ALSA SoC Audio DAI PCM I/F Control
4  *
5  * Copyright (c) 2022 MediaTek Inc.
6  * Author: Bicycle Tsai <bicycle.tsai@mediatek.com>
7  *         Trevor Wu <trevor.wu@mediatek.com>
8  *         Chun-Chia Chiu <chun-chia.chiu@mediatek.com>
9  */
10 
11 #include <linux/bitfield.h>
12 #include <linux/regmap.h>
13 #include <sound/pcm_params.h>
14 #include "mt8188-afe-clk.h"
15 #include "mt8188-afe-common.h"
16 #include "mt8188-reg.h"
17 
18 enum {
19 	MTK_DAI_PCM_FMT_I2S,
20 	MTK_DAI_PCM_FMT_EIAJ,
21 	MTK_DAI_PCM_FMT_MODEA,
22 	MTK_DAI_PCM_FMT_MODEB,
23 };
24 
25 enum {
26 	MTK_DAI_PCM_CLK_A1SYS,
27 	MTK_DAI_PCM_CLK_A2SYS,
28 	MTK_DAI_PCM_CLK_26M_48K,
29 	MTK_DAI_PCM_CLK_26M_441K,
30 };
31 
32 struct mtk_dai_pcm_rate {
33 	unsigned int rate;
34 	unsigned int reg_value;
35 };
36 
37 struct mtk_dai_pcmif_priv {
38 	unsigned int slave_mode;
39 	unsigned int lrck_inv;
40 	unsigned int bck_inv;
41 	unsigned int format;
42 };
43 
44 static const struct mtk_dai_pcm_rate mtk_dai_pcm_rates[] = {
45 	{ .rate = 8000, .reg_value = 0, },
46 	{ .rate = 16000, .reg_value = 1, },
47 	{ .rate = 32000, .reg_value = 2, },
48 	{ .rate = 48000, .reg_value = 3, },
49 	{ .rate = 11025, .reg_value = 1, },
50 	{ .rate = 22050, .reg_value = 2, },
51 	{ .rate = 44100, .reg_value = 3, },
52 };
53 
54 static int mtk_dai_pcm_mode(unsigned int rate)
55 {
56 	int i;
57 
58 	for (i = 0; i < ARRAY_SIZE(mtk_dai_pcm_rates); i++)
59 		if (mtk_dai_pcm_rates[i].rate == rate)
60 			return mtk_dai_pcm_rates[i].reg_value;
61 
62 	return -EINVAL;
63 }
64 
65 static const struct snd_kcontrol_new mtk_dai_pcm_o000_mix[] = {
66 	SOC_DAPM_SINGLE_AUTODISABLE("I000 Switch", AFE_CONN0, 0, 1, 0),
67 	SOC_DAPM_SINGLE_AUTODISABLE("I070 Switch", AFE_CONN0_2, 6, 1, 0),
68 };
69 
70 static const struct snd_kcontrol_new mtk_dai_pcm_o001_mix[] = {
71 	SOC_DAPM_SINGLE_AUTODISABLE("I001 Switch", AFE_CONN1, 1, 1, 0),
72 	SOC_DAPM_SINGLE_AUTODISABLE("I071 Switch", AFE_CONN1_2, 7, 1, 0),
73 };
74 
75 static const struct snd_soc_dapm_widget mtk_dai_pcm_widgets[] = {
76 	SND_SOC_DAPM_MIXER("I002", SND_SOC_NOPM, 0, 0, NULL, 0),
77 	SND_SOC_DAPM_MIXER("I003", SND_SOC_NOPM, 0, 0, NULL, 0),
78 	SND_SOC_DAPM_MIXER("O000", SND_SOC_NOPM, 0, 0,
79 			   mtk_dai_pcm_o000_mix,
80 			   ARRAY_SIZE(mtk_dai_pcm_o000_mix)),
81 	SND_SOC_DAPM_MIXER("O001", SND_SOC_NOPM, 0, 0,
82 			   mtk_dai_pcm_o001_mix,
83 			   ARRAY_SIZE(mtk_dai_pcm_o001_mix)),
84 
85 	SND_SOC_DAPM_SUPPLY("PCM_1_EN", PCM_INTF_CON1, 0, 0, NULL, 0),
86 
87 	SND_SOC_DAPM_INPUT("PCM1_INPUT"),
88 	SND_SOC_DAPM_OUTPUT("PCM1_OUTPUT"),
89 
90 	SND_SOC_DAPM_CLOCK_SUPPLY("aud_asrc11"),
91 	SND_SOC_DAPM_CLOCK_SUPPLY("aud_asrc12"),
92 	SND_SOC_DAPM_CLOCK_SUPPLY("aud_pcmif"),
93 };
94 
95 static const struct snd_soc_dapm_route mtk_dai_pcm_routes[] = {
96 	{"I002", NULL, "PCM1 Capture"},
97 	{"I003", NULL, "PCM1 Capture"},
98 
99 	{"O000", "I000 Switch", "I000"},
100 	{"O001", "I001 Switch", "I001"},
101 
102 	{"O000", "I070 Switch", "I070"},
103 	{"O001", "I071 Switch", "I071"},
104 
105 	{"PCM1 Playback", NULL, "O000"},
106 	{"PCM1 Playback", NULL, "O001"},
107 
108 	{"PCM1 Playback", NULL, "PCM_1_EN"},
109 	{"PCM1 Playback", NULL, "aud_asrc12"},
110 	{"PCM1 Playback", NULL, "aud_pcmif"},
111 
112 	{"PCM1 Capture", NULL, "PCM_1_EN"},
113 	{"PCM1 Capture", NULL, "aud_asrc11"},
114 	{"PCM1 Capture", NULL, "aud_pcmif"},
115 
116 	{"PCM1_OUTPUT", NULL, "PCM1 Playback"},
117 	{"PCM1 Capture", NULL, "PCM1_INPUT"},
118 };
119 
120 static int mtk_dai_pcm_configure(struct snd_pcm_substream *substream,
121 				 struct snd_soc_dai *dai)
122 {
123 	struct snd_pcm_runtime * const runtime = substream->runtime;
124 	struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
125 	struct mt8188_afe_private *afe_priv = afe->platform_priv;
126 	struct mtk_dai_pcmif_priv *pcmif_priv = NULL;
127 	unsigned int slave_mode;
128 	unsigned int lrck_inv;
129 	unsigned int bck_inv;
130 	unsigned int fmt;
131 	unsigned int bit_width = dai->sample_bits;
132 	unsigned int val = 0;
133 	unsigned int mask = 0;
134 	int fs = 0;
135 	int mode = 0;
136 
137 	if (dai->id < 0)
138 		return -EINVAL;
139 
140 	pcmif_priv = afe_priv->dai_priv[dai->id];
141 	slave_mode = pcmif_priv->slave_mode;
142 	lrck_inv = pcmif_priv->lrck_inv;
143 	bck_inv = pcmif_priv->bck_inv;
144 	fmt = pcmif_priv->format;
145 
146 	/* sync freq mode */
147 	fs = mt8188_afe_fs_timing(runtime->rate);
148 	if (fs < 0)
149 		return -EINVAL;
150 
151 	val |= FIELD_PREP(PCM_INTF_CON2_SYNC_FREQ_MODE_MASK, fs);
152 	mask |= PCM_INTF_CON2_SYNC_FREQ_MODE_MASK;
153 
154 	/* clk domain sel */
155 	if (runtime->rate % 8000)
156 		val |= FIELD_PREP(PCM_INTF_CON2_CLK_DOMAIN_SEL_MASK,
157 				  MTK_DAI_PCM_CLK_26M_441K);
158 	else
159 		val |= FIELD_PREP(PCM_INTF_CON2_CLK_DOMAIN_SEL_MASK,
160 				  MTK_DAI_PCM_CLK_26M_48K);
161 	mask |= PCM_INTF_CON2_CLK_DOMAIN_SEL_MASK;
162 
163 	regmap_update_bits(afe->regmap, PCM_INTF_CON2, mask, val);
164 
165 	val = 0;
166 	mask = 0;
167 
168 	/* pcm mode */
169 	mode = mtk_dai_pcm_mode(runtime->rate);
170 	if (mode < 0)
171 		return -EINVAL;
172 
173 	val |= FIELD_PREP(PCM_INTF_CON1_PCM_MODE_MASK, mode);
174 	mask |= PCM_INTF_CON1_PCM_MODE_MASK;
175 
176 	/* pcm format */
177 	val |= FIELD_PREP(PCM_INTF_CON1_PCM_FMT_MASK, fmt);
178 	mask |= PCM_INTF_CON1_PCM_FMT_MASK;
179 
180 	/* pcm sync length */
181 	if (fmt == MTK_DAI_PCM_FMT_MODEA ||
182 	    fmt == MTK_DAI_PCM_FMT_MODEB)
183 		val |= FIELD_PREP(PCM_INTF_CON1_SYNC_LENGTH_MASK, 1);
184 	else
185 		val |= FIELD_PREP(PCM_INTF_CON1_SYNC_LENGTH_MASK, bit_width);
186 	mask |= PCM_INTF_CON1_SYNC_LENGTH_MASK;
187 
188 	/* pcm bits, word length */
189 	if (bit_width > 16) {
190 		val |= PCM_INTF_CON1_PCM_24BIT;
191 		val |= PCM_INTF_CON1_PCM_WLEN_64BCK;
192 	} else {
193 		val |= PCM_INTF_CON1_PCM_16BIT;
194 		val |= PCM_INTF_CON1_PCM_WLEN_32BCK;
195 	}
196 	mask |= PCM_INTF_CON1_PCM_BIT_MASK;
197 	mask |= PCM_INTF_CON1_PCM_WLEN_MASK;
198 
199 	/* master/slave */
200 	if (!slave_mode) {
201 		val |= PCM_INTF_CON1_PCM_MASTER;
202 
203 		if (lrck_inv)
204 			val |= PCM_INTF_CON1_SYNC_OUT_INV;
205 		if (bck_inv)
206 			val |= PCM_INTF_CON1_BCLK_OUT_INV;
207 		mask |= PCM_INTF_CON1_CLK_OUT_INV_MASK;
208 	} else {
209 		val |= PCM_INTF_CON1_PCM_SLAVE;
210 
211 		if (lrck_inv)
212 			val |= PCM_INTF_CON1_SYNC_IN_INV;
213 		if (bck_inv)
214 			val |= PCM_INTF_CON1_BCLK_IN_INV;
215 		mask |= PCM_INTF_CON1_CLK_IN_INV_MASK;
216 
217 		// TODO: add asrc setting for slave mode
218 	}
219 	mask |= PCM_INTF_CON1_PCM_M_S_MASK;
220 
221 	regmap_update_bits(afe->regmap, PCM_INTF_CON1, mask, val);
222 
223 	return 0;
224 }
225 
226 /* dai ops */
227 static int mtk_dai_pcm_prepare(struct snd_pcm_substream *substream,
228 			       struct snd_soc_dai *dai)
229 {
230 	if (snd_soc_dai_get_widget_playback(dai)->active ||
231 	    snd_soc_dai_get_widget_capture(dai)->active)
232 		return 0;
233 
234 	return mtk_dai_pcm_configure(substream, dai);
235 }
236 
237 static int mtk_dai_pcm_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
238 {
239 	struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
240 	struct mt8188_afe_private *afe_priv = afe->platform_priv;
241 	struct mtk_dai_pcmif_priv *pcmif_priv = NULL;
242 
243 	dev_dbg(dai->dev, "%s fmt 0x%x\n", __func__, fmt);
244 
245 	if (dai->id < 0)
246 		return -EINVAL;
247 
248 	pcmif_priv = afe_priv->dai_priv[dai->id];
249 
250 	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
251 	case SND_SOC_DAIFMT_I2S:
252 		pcmif_priv->format = MTK_DAI_PCM_FMT_I2S;
253 		break;
254 	case SND_SOC_DAIFMT_DSP_A:
255 		pcmif_priv->format = MTK_DAI_PCM_FMT_MODEA;
256 		break;
257 	case SND_SOC_DAIFMT_DSP_B:
258 		pcmif_priv->format = MTK_DAI_PCM_FMT_MODEB;
259 		break;
260 	default:
261 		return -EINVAL;
262 	}
263 
264 	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
265 	case SND_SOC_DAIFMT_NB_NF:
266 		pcmif_priv->bck_inv = 0;
267 		pcmif_priv->lrck_inv = 0;
268 		break;
269 	case SND_SOC_DAIFMT_NB_IF:
270 		pcmif_priv->bck_inv = 0;
271 		pcmif_priv->lrck_inv = 1;
272 		break;
273 	case SND_SOC_DAIFMT_IB_NF:
274 		pcmif_priv->bck_inv = 1;
275 		pcmif_priv->lrck_inv = 0;
276 		break;
277 	case SND_SOC_DAIFMT_IB_IF:
278 		pcmif_priv->bck_inv = 1;
279 		pcmif_priv->lrck_inv = 1;
280 		break;
281 	default:
282 		return -EINVAL;
283 	}
284 
285 	switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
286 	case SND_SOC_DAIFMT_BC_FC:
287 		pcmif_priv->slave_mode = 1;
288 		break;
289 	case SND_SOC_DAIFMT_BP_FP:
290 		pcmif_priv->slave_mode = 0;
291 		break;
292 	default:
293 		return -EINVAL;
294 	}
295 
296 	return 0;
297 }
298 
299 static const struct snd_soc_dai_ops mtk_dai_pcm_ops = {
300 	.prepare	= mtk_dai_pcm_prepare,
301 	.set_fmt	= mtk_dai_pcm_set_fmt,
302 };
303 
304 /* dai driver */
305 #define MTK_PCM_RATES (SNDRV_PCM_RATE_8000_48000)
306 
307 #define MTK_PCM_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
308 			 SNDRV_PCM_FMTBIT_S24_LE |\
309 			 SNDRV_PCM_FMTBIT_S32_LE)
310 
311 static struct snd_soc_dai_driver mtk_dai_pcm_driver[] = {
312 	{
313 		.name = "PCM1",
314 		.id = MT8188_AFE_IO_PCM,
315 		.playback = {
316 			.stream_name = "PCM1 Playback",
317 			.channels_min = 1,
318 			.channels_max = 2,
319 			.rates = MTK_PCM_RATES,
320 			.formats = MTK_PCM_FORMATS,
321 		},
322 		.capture = {
323 			.stream_name = "PCM1 Capture",
324 			.channels_min = 1,
325 			.channels_max = 2,
326 			.rates = MTK_PCM_RATES,
327 			.formats = MTK_PCM_FORMATS,
328 		},
329 		.ops = &mtk_dai_pcm_ops,
330 		.symmetric_rate = 1,
331 		.symmetric_sample_bits = 1,
332 	},
333 };
334 
335 static int init_pcmif_priv_data(struct mtk_base_afe *afe)
336 {
337 	struct mt8188_afe_private *afe_priv = afe->platform_priv;
338 	struct mtk_dai_pcmif_priv *pcmif_priv;
339 
340 	pcmif_priv = devm_kzalloc(afe->dev, sizeof(struct mtk_dai_pcmif_priv),
341 				  GFP_KERNEL);
342 	if (!pcmif_priv)
343 		return -ENOMEM;
344 
345 	afe_priv->dai_priv[MT8188_AFE_IO_PCM] = pcmif_priv;
346 	return 0;
347 }
348 
349 int mt8188_dai_pcm_register(struct mtk_base_afe *afe)
350 {
351 	struct mtk_base_afe_dai *dai;
352 
353 	dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL);
354 	if (!dai)
355 		return -ENOMEM;
356 
357 	list_add(&dai->list, &afe->sub_dais);
358 
359 	dai->dai_drivers = mtk_dai_pcm_driver;
360 	dai->num_dai_drivers = ARRAY_SIZE(mtk_dai_pcm_driver);
361 
362 	dai->dapm_widgets = mtk_dai_pcm_widgets;
363 	dai->num_dapm_widgets = ARRAY_SIZE(mtk_dai_pcm_widgets);
364 	dai->dapm_routes = mtk_dai_pcm_routes;
365 	dai->num_dapm_routes = ARRAY_SIZE(mtk_dai_pcm_routes);
366 
367 	return init_pcmif_priv_data(afe);
368 }
369