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