1 // SPDX-License-Identifier: GPL-2.0
2 //
3 // mt8183-da7219-max98357.c
4 //	--  MT8183-DA7219-MAX98357 ALSA SoC machine driver
5 //
6 // Copyright (c) 2018 MediaTek Inc.
7 // Author: Shunli Wang <shunli.wang@mediatek.com>
8 
9 #include <linux/module.h>
10 #include <sound/pcm_params.h>
11 #include <sound/soc.h>
12 #include <sound/jack.h>
13 #include <linux/pinctrl/consumer.h>
14 
15 #include "mt8183-afe-common.h"
16 #include "../../codecs/da7219-aad.h"
17 #include "../../codecs/da7219.h"
18 
19 static struct snd_soc_jack headset_jack;
20 
21 /* Headset jack detection DAPM pins */
22 static struct snd_soc_jack_pin headset_jack_pins[] = {
23 	{
24 		.pin = "Headphone",
25 		.mask = SND_JACK_HEADPHONE,
26 	},
27 	{
28 		.pin = "Headset Mic",
29 		.mask = SND_JACK_MICROPHONE,
30 	},
31 };
32 
33 static struct snd_soc_dai_link_component
34 mt8183_da7219_max98357_external_codecs[] = {
35 	{
36 		.name = "max98357a",
37 		.dai_name = "HiFi",
38 	},
39 	{
40 		.name = "da7219.5-001a",
41 		.dai_name = "da7219-hifi",
42 	},
43 };
44 
45 static int mt8183_mt6358_i2s_hw_params(struct snd_pcm_substream *substream,
46 				       struct snd_pcm_hw_params *params)
47 {
48 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
49 	unsigned int rate = params_rate(params);
50 	unsigned int mclk_fs_ratio = 128;
51 	unsigned int mclk_fs = rate * mclk_fs_ratio;
52 
53 	return snd_soc_dai_set_sysclk(rtd->cpu_dai,
54 				      0, mclk_fs, SND_SOC_CLOCK_OUT);
55 }
56 
57 static const struct snd_soc_ops mt8183_mt6358_i2s_ops = {
58 	.hw_params = mt8183_mt6358_i2s_hw_params,
59 };
60 
61 static int mt8183_da7219_i2s_hw_params(struct snd_pcm_substream *substream,
62 				       struct snd_pcm_hw_params *params)
63 {
64 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
65 	unsigned int rate = params_rate(params);
66 	unsigned int mclk_fs_ratio = 256;
67 	unsigned int mclk_fs = rate * mclk_fs_ratio;
68 	unsigned int freq;
69 	int ret = 0, j;
70 
71 	ret = snd_soc_dai_set_sysclk(rtd->cpu_dai, 0,
72 				     mclk_fs, SND_SOC_CLOCK_OUT);
73 	if (ret < 0)
74 		dev_err(rtd->dev, "failed to set cpu dai sysclk\n");
75 
76 	for (j = 0; j < rtd->num_codecs; j++) {
77 		struct snd_soc_dai *codec_dai = rtd->codec_dais[j];
78 
79 		if (!strcmp(codec_dai->component->name, "da7219.5-001a")) {
80 			ret = snd_soc_dai_set_sysclk(codec_dai,
81 						     DA7219_CLKSRC_MCLK,
82 						     mclk_fs,
83 						     SND_SOC_CLOCK_IN);
84 			if (ret < 0)
85 				dev_err(rtd->dev, "failed to set sysclk\n");
86 
87 			if ((rate % 8000) == 0)
88 				freq = DA7219_PLL_FREQ_OUT_98304;
89 			else
90 				freq = DA7219_PLL_FREQ_OUT_90316;
91 
92 			ret = snd_soc_dai_set_pll(codec_dai, 0,
93 						  DA7219_SYSCLK_PLL_SRM,
94 						  0, freq);
95 			if (ret)
96 				dev_err(rtd->dev, "failed to start PLL: %d\n",
97 					ret);
98 		}
99 	}
100 
101 	return ret;
102 }
103 
104 static int mt8183_da7219_hw_free(struct snd_pcm_substream *substream)
105 {
106 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
107 	int ret = 0, j;
108 
109 	for (j = 0; j < rtd->num_codecs; j++) {
110 		struct snd_soc_dai *codec_dai = rtd->codec_dais[j];
111 
112 		if (!strcmp(codec_dai->component->name, "da7219.5-001a")) {
113 			ret = snd_soc_dai_set_pll(codec_dai,
114 						  0, DA7219_SYSCLK_MCLK, 0, 0);
115 			if (ret < 0) {
116 				dev_err(rtd->dev, "failed to stop PLL: %d\n",
117 					ret);
118 				break;
119 			}
120 		}
121 	}
122 
123 	return ret;
124 }
125 
126 static const struct snd_soc_ops mt8183_da7219_i2s_ops = {
127 	.hw_params = mt8183_da7219_i2s_hw_params,
128 	.hw_free = mt8183_da7219_hw_free,
129 };
130 
131 static int mt8183_i2s_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
132 				      struct snd_pcm_hw_params *params)
133 {
134 	/* fix BE i2s format to 32bit, clean param mask first */
135 	snd_mask_reset_range(hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT),
136 			     0, SNDRV_PCM_FORMAT_LAST);
137 
138 	params_set_format(params, SNDRV_PCM_FORMAT_S32_LE);
139 
140 	return 0;
141 }
142 
143 static const struct snd_soc_dapm_widget
144 mt8183_da7219_max98357_dapm_widgets[] = {
145 	SND_SOC_DAPM_OUTPUT("IT6505_8CH"),
146 };
147 
148 static const struct snd_soc_dapm_route mt8183_da7219_max98357_dapm_routes[] = {
149 	{"IT6505_8CH", NULL, "TDM"},
150 };
151 
152 static struct snd_soc_dai_link mt8183_da7219_max98357_dai_links[] = {
153 	/* FE */
154 	{
155 		.name = "Playback_1",
156 		.stream_name = "Playback_1",
157 		.cpu_dai_name = "DL1",
158 		.codec_name = "snd-soc-dummy",
159 		.codec_dai_name = "snd-soc-dummy-dai",
160 		.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
161 			    SND_SOC_DPCM_TRIGGER_PRE},
162 		.dynamic = 1,
163 		.dpcm_playback = 1,
164 	},
165 	{
166 		.name = "Playback_2",
167 		.stream_name = "Playback_2",
168 		.cpu_dai_name = "DL2",
169 		.codec_name = "snd-soc-dummy",
170 		.codec_dai_name = "snd-soc-dummy-dai",
171 		.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
172 			    SND_SOC_DPCM_TRIGGER_PRE},
173 		.dynamic = 1,
174 		.dpcm_playback = 1,
175 	},
176 	{
177 		.name = "Playback_3",
178 		.stream_name = "Playback_3",
179 		.cpu_dai_name = "DL3",
180 		.codec_name = "snd-soc-dummy",
181 		.codec_dai_name = "snd-soc-dummy-dai",
182 		.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
183 			    SND_SOC_DPCM_TRIGGER_PRE},
184 		.dynamic = 1,
185 		.dpcm_playback = 1,
186 	},
187 	{
188 		.name = "Capture_1",
189 		.stream_name = "Capture_1",
190 		.cpu_dai_name = "UL1",
191 		.codec_name = "snd-soc-dummy",
192 		.codec_dai_name = "snd-soc-dummy-dai",
193 		.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
194 			    SND_SOC_DPCM_TRIGGER_PRE},
195 		.dynamic = 1,
196 		.dpcm_capture = 1,
197 	},
198 	{
199 		.name = "Capture_2",
200 		.stream_name = "Capture_2",
201 		.cpu_dai_name = "UL2",
202 		.codec_name = "snd-soc-dummy",
203 		.codec_dai_name = "snd-soc-dummy-dai",
204 		.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
205 			    SND_SOC_DPCM_TRIGGER_PRE},
206 		.dynamic = 1,
207 		.dpcm_capture = 1,
208 	},
209 	{
210 		.name = "Capture_3",
211 		.stream_name = "Capture_3",
212 		.cpu_dai_name = "UL3",
213 		.codec_name = "snd-soc-dummy",
214 		.codec_dai_name = "snd-soc-dummy-dai",
215 		.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
216 			    SND_SOC_DPCM_TRIGGER_PRE},
217 		.dynamic = 1,
218 		.dpcm_capture = 1,
219 	},
220 	{
221 		.name = "Capture_Mono_1",
222 		.stream_name = "Capture_Mono_1",
223 		.cpu_dai_name = "UL_MONO_1",
224 		.codec_name = "snd-soc-dummy",
225 		.codec_dai_name = "snd-soc-dummy-dai",
226 		.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
227 			    SND_SOC_DPCM_TRIGGER_PRE},
228 		.dynamic = 1,
229 		.dpcm_capture = 1,
230 	},
231 	{
232 		.name = "Playback_HDMI",
233 		.stream_name = "Playback_HDMI",
234 		.cpu_dai_name = "HDMI",
235 		.codec_name = "snd-soc-dummy",
236 		.codec_dai_name = "snd-soc-dummy-dai",
237 		.trigger = {SND_SOC_DPCM_TRIGGER_PRE,
238 			    SND_SOC_DPCM_TRIGGER_PRE},
239 		.dynamic = 1,
240 		.dpcm_playback = 1,
241 	},
242 	/* BE */
243 	{
244 		.name = "Primary Codec",
245 		.cpu_dai_name = "ADDA",
246 		.codec_dai_name = "mt6358-snd-codec-aif1",
247 		.codec_name = "mt6358-sound",
248 		.no_pcm = 1,
249 		.dpcm_playback = 1,
250 		.dpcm_capture = 1,
251 		.ignore_suspend = 1,
252 	},
253 	{
254 		.name = "PCM 1",
255 		.cpu_dai_name = "PCM 1",
256 		.codec_name = "snd-soc-dummy",
257 		.codec_dai_name = "snd-soc-dummy-dai",
258 		.no_pcm = 1,
259 		.dpcm_playback = 1,
260 		.dpcm_capture = 1,
261 		.ignore_suspend = 1,
262 	},
263 	{
264 		.name = "PCM 2",
265 		.cpu_dai_name = "PCM 2",
266 		.codec_name = "snd-soc-dummy",
267 		.codec_dai_name = "snd-soc-dummy-dai",
268 		.no_pcm = 1,
269 		.dpcm_playback = 1,
270 		.dpcm_capture = 1,
271 		.ignore_suspend = 1,
272 	},
273 	{
274 		.name = "I2S0",
275 		.cpu_dai_name = "I2S0",
276 		.codec_dai_name = "bt-sco-pcm",
277 		.codec_name = "bt-sco",
278 		.no_pcm = 1,
279 		.dpcm_capture = 1,
280 		.ignore_suspend = 1,
281 		.be_hw_params_fixup = mt8183_i2s_hw_params_fixup,
282 		.ops = &mt8183_mt6358_i2s_ops,
283 	},
284 	{
285 		.name = "I2S1",
286 		.cpu_dai_name = "I2S1",
287 		.codec_dai_name = "snd-soc-dummy-dai",
288 		.codec_name = "snd-soc-dummy",
289 		.no_pcm = 1,
290 		.dpcm_playback = 1,
291 		.ignore_suspend = 1,
292 		.be_hw_params_fixup = mt8183_i2s_hw_params_fixup,
293 		.ops = &mt8183_mt6358_i2s_ops,
294 	},
295 	{
296 		.name = "I2S2",
297 		.cpu_dai_name = "I2S2",
298 		.codec_dai_name = "da7219-hifi",
299 		.codec_name = "da7219.5-001a",
300 		.no_pcm = 1,
301 		.dpcm_capture = 1,
302 		.ignore_suspend = 1,
303 		.be_hw_params_fixup = mt8183_i2s_hw_params_fixup,
304 		.ops = &mt8183_da7219_i2s_ops,
305 	},
306 	{
307 		.name = "I2S3",
308 		.cpu_dai_name = "I2S3",
309 		.codecs = mt8183_da7219_max98357_external_codecs,
310 		.num_codecs =
311 			ARRAY_SIZE(mt8183_da7219_max98357_external_codecs),
312 		.no_pcm = 1,
313 		.dpcm_playback = 1,
314 		.ignore_suspend = 1,
315 		.be_hw_params_fixup = mt8183_i2s_hw_params_fixup,
316 		.ops = &mt8183_da7219_i2s_ops,
317 	},
318 	{
319 		.name = "I2S5",
320 		.cpu_dai_name = "I2S5",
321 		.codec_dai_name = "bt-sco-pcm",
322 		.codec_name = "bt-sco",
323 		.no_pcm = 1,
324 		.dpcm_playback = 1,
325 		.ignore_suspend = 1,
326 		.be_hw_params_fixup = mt8183_i2s_hw_params_fixup,
327 		.ops = &mt8183_mt6358_i2s_ops,
328 	},
329 	{
330 		.name = "TDM",
331 		.cpu_dai_name = "TDM",
332 		.codec_name = "snd-soc-dummy",
333 		.codec_dai_name = "snd-soc-dummy-dai",
334 		.no_pcm = 1,
335 		.dpcm_playback = 1,
336 		.ignore_suspend = 1,
337 	},
338 };
339 
340 static int
341 mt8183_da7219_max98357_headset_init(struct snd_soc_component *component);
342 
343 static struct snd_soc_aux_dev mt8183_da7219_max98357_headset_dev = {
344 	.name = "Headset Chip",
345 	.init = mt8183_da7219_max98357_headset_init,
346 };
347 
348 static struct snd_soc_codec_conf mt6358_codec_conf[] = {
349 	{
350 		.dev_name = "mt6358-sound",
351 		.name_prefix = "Mt6358",
352 	},
353 };
354 
355 static struct snd_soc_card mt8183_da7219_max98357_card = {
356 	.name = "mt8183_da7219_max98357",
357 	.owner = THIS_MODULE,
358 	.dai_link = mt8183_da7219_max98357_dai_links,
359 	.num_links = ARRAY_SIZE(mt8183_da7219_max98357_dai_links),
360 	.aux_dev = &mt8183_da7219_max98357_headset_dev,
361 	.num_aux_devs = 1,
362 	.codec_conf = mt6358_codec_conf,
363 	.num_configs = ARRAY_SIZE(mt6358_codec_conf),
364 };
365 
366 static int
367 mt8183_da7219_max98357_headset_init(struct snd_soc_component *component)
368 {
369 	int ret;
370 
371 	/* Enable Headset and 4 Buttons Jack detection */
372 	ret = snd_soc_card_jack_new(&mt8183_da7219_max98357_card,
373 				    "Headset Jack",
374 				    SND_JACK_HEADSET |
375 				    SND_JACK_BTN_0 | SND_JACK_BTN_1 |
376 				    SND_JACK_BTN_2 | SND_JACK_BTN_3,
377 				    &headset_jack,
378 				    headset_jack_pins,
379 				    ARRAY_SIZE(headset_jack_pins));
380 	if (ret)
381 		return ret;
382 
383 	da7219_aad_jack_det(component, &headset_jack);
384 
385 	return ret;
386 }
387 
388 static int mt8183_da7219_max98357_dev_probe(struct platform_device *pdev)
389 {
390 	struct snd_soc_card *card = &mt8183_da7219_max98357_card;
391 	struct device_node *platform_node;
392 	struct snd_soc_dai_link *dai_link;
393 	struct pinctrl *default_pins;
394 	int ret, i;
395 
396 	card->dev = &pdev->dev;
397 
398 	platform_node = of_parse_phandle(pdev->dev.of_node,
399 					 "mediatek,platform", 0);
400 	if (!platform_node) {
401 		dev_err(&pdev->dev, "Property 'platform' missing or invalid\n");
402 		return -EINVAL;
403 	}
404 
405 	for_each_card_prelinks(card, i, dai_link) {
406 		/* In the alsa soc-core, the "platform" will be
407 		 * allocated by devm_kzalloc if null.
408 		 * There is a special case that registerring
409 		 * sound card is failed at the first time, but
410 		 * the "platform" will not null when probe is trying
411 		 * again. It's not expected normally.
412 		 */
413 		dai_link->platforms = NULL;
414 
415 		if (dai_link->platform_name)
416 			continue;
417 		dai_link->platform_of_node = platform_node;
418 	}
419 
420 	mt8183_da7219_max98357_headset_dev.codec_of_node =
421 		of_parse_phandle(pdev->dev.of_node,
422 				 "mediatek,headset-codec", 0);
423 	if (!mt8183_da7219_max98357_headset_dev.codec_of_node) {
424 		dev_err(&pdev->dev,
425 			"Property 'mediatek,headset-codec' missing/invalid\n");
426 		return -EINVAL;
427 	}
428 
429 	ret = devm_snd_soc_register_card(&pdev->dev, card);
430 	if (ret) {
431 		dev_err(&pdev->dev, "%s snd_soc_register_card fail %d\n",
432 			__func__, ret);
433 		return ret;
434 	}
435 
436 	default_pins =
437 		devm_pinctrl_get_select(&pdev->dev, PINCTRL_STATE_DEFAULT);
438 	if (IS_ERR(default_pins)) {
439 		dev_err(&pdev->dev, "%s set pins failed\n",
440 			__func__);
441 		return PTR_ERR(default_pins);
442 	}
443 
444 	return ret;
445 }
446 
447 #ifdef CONFIG_OF
448 static const struct of_device_id mt8183_da7219_max98357_dt_match[] = {
449 	{.compatible = "mediatek,mt8183_da7219_max98357",},
450 	{}
451 };
452 #endif
453 
454 static struct platform_driver mt8183_da7219_max98357_driver = {
455 	.driver = {
456 		.name = "mt8183_da7219_max98357",
457 #ifdef CONFIG_OF
458 		.of_match_table = mt8183_da7219_max98357_dt_match,
459 #endif
460 	},
461 	.probe = mt8183_da7219_max98357_dev_probe,
462 };
463 
464 module_platform_driver(mt8183_da7219_max98357_driver);
465 
466 /* Module information */
467 MODULE_DESCRIPTION("MT8183-DA7219-MAX98357 ALSA SoC machine driver");
468 MODULE_AUTHOR("Shunli Wang <shunli.wang@mediatek.com>");
469 MODULE_LICENSE("GPL v2");
470 MODULE_ALIAS("mt8183_da7219_max98357 soc card");
471 
472