1
2
3
4
5
6
7
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
19static struct snd_soc_jack headset_jack;
20
21
22static 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
33static struct snd_soc_dai_link_component
34mt8183_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
45static 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
57static const struct snd_soc_ops mt8183_mt6358_i2s_ops = {
58 .hw_params = mt8183_mt6358_i2s_hw_params,
59};
60
61static 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
104static 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
126static 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
131static int mt8183_i2s_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
132 struct snd_pcm_hw_params *params)
133{
134
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
143static const struct snd_soc_dapm_widget
144mt8183_da7219_max98357_dapm_widgets[] = {
145 SND_SOC_DAPM_OUTPUT("IT6505_8CH"),
146};
147
148static const struct snd_soc_dapm_route mt8183_da7219_max98357_dapm_routes[] = {
149 {"IT6505_8CH", NULL, "TDM"},
150};
151
152static struct snd_soc_dai_link mt8183_da7219_max98357_dai_links[] = {
153
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
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
340static int
341mt8183_da7219_max98357_headset_init(struct snd_soc_component *component);
342
343static struct snd_soc_aux_dev mt8183_da7219_max98357_headset_dev = {
344 .name = "Headset Chip",
345 .init = mt8183_da7219_max98357_headset_init,
346};
347
348static struct snd_soc_codec_conf mt6358_codec_conf[] = {
349 {
350 .dev_name = "mt6358-sound",
351 .name_prefix = "Mt6358",
352 },
353};
354
355static 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
366static int
367mt8183_da7219_max98357_headset_init(struct snd_soc_component *component)
368{
369 int ret;
370
371
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
388static 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
407
408
409
410
411
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
448static const struct of_device_id mt8183_da7219_max98357_dt_match[] = {
449 {.compatible = "mediatek,mt8183_da7219_max98357",},
450 {}
451};
452#endif
453
454static 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
464module_platform_driver(mt8183_da7219_max98357_driver);
465
466
467MODULE_DESCRIPTION("MT8183-DA7219-MAX98357 ALSA SoC machine driver");
468MODULE_AUTHOR("Shunli Wang <shunli.wang@mediatek.com>");
469MODULE_LICENSE("GPL v2");
470MODULE_ALIAS("mt8183_da7219_max98357 soc card");
471
472