xref: /linux/sound/soc/mediatek/mt8365/mt8365-dai-pcm.c (revision 2cd86f02c017bf9733e5cd891381b7d40f6f37ad)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * MediaTek 8365 ALSA SoC Audio DAI PCM Control
4  *
5  * Copyright (c) 2024 MediaTek Inc.
6  * Authors: Jia Zeng <jia.zeng@mediatek.com>
7  *          Alexandre Mergnat <amergnat@baylibre.com>
8  */
9 
10 #include <linux/bitops.h>
11 #include <linux/regmap.h>
12 #include <sound/pcm_params.h>
13 #include "mt8365-afe-clk.h"
14 #include "mt8365-afe-common.h"
15 
16 struct mt8365_pcm_intf_data {
17 	bool slave_mode;
18 	bool lrck_inv;
19 	bool bck_inv;
20 	unsigned int format;
21 };
22 
23 /* DAI Drivers */
24 
25 static void mt8365_dai_enable_pcm1(struct mtk_base_afe *afe)
26 {
27 	regmap_update_bits(afe->regmap, PCM_INTF_CON1,
28 			   PCM_INTF_CON1_EN, PCM_INTF_CON1_EN);
29 }
30 
31 static void mt8365_dai_disable_pcm1(struct mtk_base_afe *afe)
32 {
33 	regmap_update_bits(afe->regmap, PCM_INTF_CON1,
34 			   PCM_INTF_CON1_EN, 0x0);
35 }
36 
37 static int mt8365_dai_configure_pcm1(struct snd_pcm_substream *substream,
38 				     struct snd_soc_dai *dai)
39 {
40 	struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
41 	struct mt8365_afe_private *afe_priv = afe->platform_priv;
42 	struct mt8365_pcm_intf_data *pcm_priv = afe_priv->dai_priv[MT8365_AFE_IO_PCM1];
43 	bool slave_mode = pcm_priv->slave_mode;
44 	bool lrck_inv = pcm_priv->lrck_inv;
45 	bool bck_inv = pcm_priv->bck_inv;
46 	unsigned int fmt = pcm_priv->format;
47 	unsigned int bit_width = dai->sample_bits;
48 	unsigned int val = 0;
49 
50 	if (!slave_mode) {
51 		val |= PCM_INTF_CON1_MASTER_MODE |
52 		       PCM_INTF_CON1_BYPASS_ASRC;
53 
54 		if (lrck_inv)
55 			val |= PCM_INTF_CON1_SYNC_OUT_INV;
56 		if (bck_inv)
57 			val |= PCM_INTF_CON1_BCLK_OUT_INV;
58 	} else {
59 		val |= PCM_INTF_CON1_SLAVE_MODE;
60 
61 		if (lrck_inv)
62 			val |= PCM_INTF_CON1_SYNC_IN_INV;
63 		if (bck_inv)
64 			val |= PCM_INTF_CON1_BCLK_IN_INV;
65 
66 		/* TODO: add asrc setting */
67 	}
68 
69 	val |= FIELD_PREP(PCM_INTF_CON1_FORMAT_MASK, fmt);
70 
71 	if (fmt == MT8365_PCM_FORMAT_PCMA ||
72 	    fmt == MT8365_PCM_FORMAT_PCMB)
73 		val |= PCM_INTF_CON1_SYNC_LEN(1);
74 	else
75 		val |= PCM_INTF_CON1_SYNC_LEN(bit_width);
76 
77 	switch (substream->runtime->rate) {
78 	case 48000:
79 		val |= PCM_INTF_CON1_FS_48K;
80 		break;
81 	case 32000:
82 		val |= PCM_INTF_CON1_FS_32K;
83 		break;
84 	case 16000:
85 		val |= PCM_INTF_CON1_FS_16K;
86 		break;
87 	case 8000:
88 		val |= PCM_INTF_CON1_FS_8K;
89 		break;
90 	default:
91 		return -EINVAL;
92 	}
93 
94 	if (bit_width > 16)
95 		val |= PCM_INTF_CON1_24BIT | PCM_INTF_CON1_64BCK;
96 	else
97 		val |= PCM_INTF_CON1_16BIT | PCM_INTF_CON1_32BCK;
98 
99 	val |= PCM_INTF_CON1_EXT_MODEM;
100 
101 	regmap_update_bits(afe->regmap, PCM_INTF_CON1,
102 			   PCM_INTF_CON1_CONFIG_MASK, val);
103 
104 	return 0;
105 }
106 
107 static int mt8365_dai_pcm1_startup(struct snd_pcm_substream *substream,
108 				   struct snd_soc_dai *dai)
109 {
110 	struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
111 
112 	if (snd_soc_dai_active(dai))
113 		return 0;
114 
115 	mt8365_afe_enable_main_clk(afe);
116 
117 	return 0;
118 }
119 
120 static void mt8365_dai_pcm1_shutdown(struct snd_pcm_substream *substream,
121 				     struct snd_soc_dai *dai)
122 {
123 	struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
124 
125 	if (snd_soc_dai_active(dai))
126 		return;
127 
128 	mt8365_dai_disable_pcm1(afe);
129 	mt8365_afe_disable_main_clk(afe);
130 }
131 
132 static int mt8365_dai_pcm1_prepare(struct snd_pcm_substream *substream,
133 				   struct snd_soc_dai *dai)
134 {
135 	struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
136 	int ret;
137 
138 	if ((snd_soc_dai_stream_active(dai, SNDRV_PCM_STREAM_PLAYBACK) +
139 	    snd_soc_dai_stream_active(dai, SNDRV_PCM_STREAM_CAPTURE)) > 1) {
140 		dev_info(afe->dev, "%s '%s' active(%u-%u) already\n",
141 			 __func__, snd_pcm_stream_str(substream),
142 			 snd_soc_dai_stream_active(dai, SNDRV_PCM_STREAM_PLAYBACK),
143 			 snd_soc_dai_stream_active(dai, SNDRV_PCM_STREAM_CAPTURE));
144 		return 0;
145 	}
146 
147 	ret = mt8365_dai_configure_pcm1(substream, dai);
148 	if (ret)
149 		return ret;
150 
151 	mt8365_dai_enable_pcm1(afe);
152 
153 	return 0;
154 }
155 
156 static int mt8365_dai_pcm1_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
157 {
158 	struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
159 	struct mt8365_afe_private *afe_priv = afe->platform_priv;
160 	struct mt8365_pcm_intf_data *pcm_priv = afe_priv->dai_priv[MT8365_AFE_IO_PCM1];
161 
162 	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
163 	case SND_SOC_DAIFMT_I2S:
164 		pcm_priv->format = MT8365_PCM_FORMAT_I2S;
165 		break;
166 	default:
167 		return -EINVAL;
168 	}
169 
170 	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
171 	case SND_SOC_DAIFMT_NB_NF:
172 		pcm_priv->bck_inv = false;
173 		pcm_priv->lrck_inv = false;
174 		break;
175 	case SND_SOC_DAIFMT_NB_IF:
176 		pcm_priv->bck_inv = false;
177 		pcm_priv->lrck_inv = true;
178 		break;
179 	case SND_SOC_DAIFMT_IB_NF:
180 		pcm_priv->bck_inv = true;
181 		pcm_priv->lrck_inv = false;
182 		break;
183 	case SND_SOC_DAIFMT_IB_IF:
184 		pcm_priv->bck_inv = true;
185 		pcm_priv->lrck_inv = true;
186 		break;
187 	default:
188 		return -EINVAL;
189 	}
190 
191 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
192 	case SND_SOC_DAIFMT_CBM_CFM:
193 		pcm_priv->slave_mode = true;
194 		break;
195 	case SND_SOC_DAIFMT_CBS_CFS:
196 		pcm_priv->slave_mode = false;
197 		break;
198 	default:
199 		return -EINVAL;
200 	}
201 
202 	return 0;
203 }
204 
205 static const struct snd_soc_dai_ops mt8365_dai_pcm1_ops = {
206 	.startup	= mt8365_dai_pcm1_startup,
207 	.shutdown	= mt8365_dai_pcm1_shutdown,
208 	.prepare	= mt8365_dai_pcm1_prepare,
209 	.set_fmt	= mt8365_dai_pcm1_set_fmt,
210 };
211 
212 static struct snd_soc_dai_driver mtk_dai_pcm_driver[] = {
213 	{
214 		.name = "PCM1",
215 		.id = MT8365_AFE_IO_PCM1,
216 		.playback = {
217 			.stream_name = "PCM1 Playback",
218 			.channels_min = 1,
219 			.channels_max = 2,
220 			.rates = SNDRV_PCM_RATE_8000 |
221 				 SNDRV_PCM_RATE_16000 |
222 				 SNDRV_PCM_RATE_32000 |
223 				 SNDRV_PCM_RATE_48000,
224 			.formats = SNDRV_PCM_FMTBIT_S16_LE |
225 				   SNDRV_PCM_FMTBIT_S32_LE,
226 		},
227 		.capture = {
228 			.stream_name = "PCM1 Capture",
229 			.channels_min = 1,
230 			.channels_max = 2,
231 			.rates = SNDRV_PCM_RATE_8000 |
232 				 SNDRV_PCM_RATE_16000 |
233 				 SNDRV_PCM_RATE_32000 |
234 				 SNDRV_PCM_RATE_48000,
235 			.formats = SNDRV_PCM_FMTBIT_S16_LE |
236 				   SNDRV_PCM_FMTBIT_S32_LE,
237 		},
238 		.ops = &mt8365_dai_pcm1_ops,
239 		.symmetric_rate = 1,
240 		.symmetric_sample_bits = 1,
241 	}
242 };
243 
244 /* DAI widget */
245 
246 static const struct snd_soc_dapm_widget mtk_dai_pcm_widgets[] = {
247 	SND_SOC_DAPM_OUTPUT("PCM1 Out"),
248 	SND_SOC_DAPM_INPUT("PCM1 In"),
249 };
250 
251 /* DAI route */
252 
253 static const struct snd_soc_dapm_route mtk_dai_pcm_routes[] = {
254 	{"PCM1 Playback", NULL, "O07"},
255 	{"PCM1 Playback", NULL, "O08"},
256 	{"PCM1 Out", NULL, "PCM1 Playback"},
257 
258 	{"I09", NULL, "PCM1 Capture"},
259 	{"I22", NULL, "PCM1 Capture"},
260 	{"PCM1 Capture", NULL, "PCM1 In"},
261 };
262 
263 static int init_pcmif_priv_data(struct mtk_base_afe *afe)
264 {
265 	struct mt8365_afe_private *afe_priv = afe->platform_priv;
266 	struct mt8365_pcm_intf_data *pcmif_priv;
267 
268 	pcmif_priv = devm_kzalloc(afe->dev, sizeof(struct mt8365_pcm_intf_data),
269 				  GFP_KERNEL);
270 	if (!pcmif_priv)
271 		return -ENOMEM;
272 
273 	afe_priv->dai_priv[MT8365_AFE_IO_PCM1] = pcmif_priv;
274 	return 0;
275 }
276 
277 int mt8365_dai_pcm_register(struct mtk_base_afe *afe)
278 {
279 	struct mtk_base_afe_dai *dai;
280 
281 	dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL);
282 	if (!dai)
283 		return -ENOMEM;
284 
285 	list_add(&dai->list, &afe->sub_dais);
286 	dai->dai_drivers = mtk_dai_pcm_driver;
287 	dai->num_dai_drivers = ARRAY_SIZE(mtk_dai_pcm_driver);
288 	dai->dapm_widgets = mtk_dai_pcm_widgets;
289 	dai->num_dapm_widgets = ARRAY_SIZE(mtk_dai_pcm_widgets);
290 	dai->dapm_routes = mtk_dai_pcm_routes;
291 	dai->num_dapm_routes = ARRAY_SIZE(mtk_dai_pcm_routes);
292 	return init_pcmif_priv_data(afe);
293 }
294