diff options
author | Shunli Wang <shunli.wang@mediatek.com> | 2019-03-29 04:34:46 -0400 |
---|---|---|
committer | Mark Brown <broonie@kernel.org> | 2019-04-01 04:04:23 -0400 |
commit | 11c0269017b212fd47c593307d2dc3eb9713b2d0 (patch) | |
tree | 924e07dae3774524221ab073d098f6e480a27f71 /sound/soc/mediatek | |
parent | 2b070f6739025ecbf2ccb55daf9e19d3fb343c7e (diff) |
ASoC: Mediatek: MT8183: Add machine driver with TS3A227
This patch adds support for the machine board with TS3A227.
Signed-off-by: Shunli Wang <shunli.wang@mediatek.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
Diffstat (limited to 'sound/soc/mediatek')
-rw-r--r-- | sound/soc/mediatek/Kconfig | 13 | ||||
-rw-r--r-- | sound/soc/mediatek/mt8183/Makefile | 1 | ||||
-rw-r--r-- | sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c | 382 |
3 files changed, 396 insertions, 0 deletions
diff --git a/sound/soc/mediatek/Kconfig b/sound/soc/mediatek/Kconfig index b35410e4020e..617fb8f4f694 100644 --- a/sound/soc/mediatek/Kconfig +++ b/sound/soc/mediatek/Kconfig | |||
@@ -116,6 +116,19 @@ config SND_SOC_MT8183 | |||
116 | Select Y if you have such device. | 116 | Select Y if you have such device. |
117 | If unsure select "N". | 117 | If unsure select "N". |
118 | 118 | ||
119 | config SND_SOC_MT8183_MT6358_TS3A227E_MAX98357A | ||
120 | tristate "ASoC Audio driver for MT8183 with MT6358 TS3A227E MAX98357A codec" | ||
121 | depends on SND_SOC_MT8183 | ||
122 | select SND_SOC_MT6358 | ||
123 | select SND_SOC_MAX98357A | ||
124 | select SND_SOC_BT_SCO | ||
125 | select SND_SOC_TS3A227E | ||
126 | help | ||
127 | This adds ASoC driver for Mediatek MT8183 boards | ||
128 | with the MT6358 TS3A227E MAX98357A audio codec. | ||
129 | Select Y if you have such device. | ||
130 | If unsure select "N". | ||
131 | |||
119 | config SND_SOC_MTK_BTCVSD | 132 | config SND_SOC_MTK_BTCVSD |
120 | tristate "ALSA BT SCO CVSD/MSBC Driver" | 133 | tristate "ALSA BT SCO CVSD/MSBC Driver" |
121 | help | 134 | help |
diff --git a/sound/soc/mediatek/mt8183/Makefile b/sound/soc/mediatek/mt8183/Makefile index f3ee6ac98fe8..6177bbd9caaa 100644 --- a/sound/soc/mediatek/mt8183/Makefile +++ b/sound/soc/mediatek/mt8183/Makefile | |||
@@ -11,3 +11,4 @@ snd-soc-mt8183-afe-objs := \ | |||
11 | mt8183-dai-adda.o | 11 | mt8183-dai-adda.o |
12 | 12 | ||
13 | obj-$(CONFIG_SND_SOC_MT8183) += snd-soc-mt8183-afe.o | 13 | obj-$(CONFIG_SND_SOC_MT8183) += snd-soc-mt8183-afe.o |
14 | obj-$(CONFIG_SND_SOC_MT8183_MT6358_TS3A227E_MAX98357A) += mt8183-mt6358-ts3a227-max98357.o | ||
diff --git a/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c b/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c new file mode 100644 index 000000000000..2da56232a9e1 --- /dev/null +++ b/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c | |||
@@ -0,0 +1,382 @@ | |||
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 struct snd_soc_dai_link | ||
73 | mt8183_mt6358_ts3a227_max98357_dai_links[] = { | ||
74 | /* FE */ | ||
75 | { | ||
76 | .name = "Playback_1", | ||
77 | .stream_name = "Playback_1", | ||
78 | .cpu_dai_name = "DL1", | ||
79 | .codec_name = "snd-soc-dummy", | ||
80 | .codec_dai_name = "snd-soc-dummy-dai", | ||
81 | .trigger = {SND_SOC_DPCM_TRIGGER_PRE, | ||
82 | SND_SOC_DPCM_TRIGGER_PRE}, | ||
83 | .dynamic = 1, | ||
84 | .dpcm_playback = 1, | ||
85 | }, | ||
86 | { | ||
87 | .name = "Playback_2", | ||
88 | .stream_name = "Playback_2", | ||
89 | .cpu_dai_name = "DL2", | ||
90 | .codec_name = "snd-soc-dummy", | ||
91 | .codec_dai_name = "snd-soc-dummy-dai", | ||
92 | .trigger = {SND_SOC_DPCM_TRIGGER_PRE, | ||
93 | SND_SOC_DPCM_TRIGGER_PRE}, | ||
94 | .dynamic = 1, | ||
95 | .dpcm_playback = 1, | ||
96 | }, | ||
97 | { | ||
98 | .name = "Playback_3", | ||
99 | .stream_name = "Playback_3", | ||
100 | .cpu_dai_name = "DL3", | ||
101 | .codec_name = "snd-soc-dummy", | ||
102 | .codec_dai_name = "snd-soc-dummy-dai", | ||
103 | .trigger = {SND_SOC_DPCM_TRIGGER_PRE, | ||
104 | SND_SOC_DPCM_TRIGGER_PRE}, | ||
105 | .dynamic = 1, | ||
106 | .dpcm_playback = 1, | ||
107 | }, | ||
108 | { | ||
109 | .name = "Capture_1", | ||
110 | .stream_name = "Capture_1", | ||
111 | .cpu_dai_name = "UL1", | ||
112 | .codec_name = "snd-soc-dummy", | ||
113 | .codec_dai_name = "snd-soc-dummy-dai", | ||
114 | .trigger = {SND_SOC_DPCM_TRIGGER_PRE, | ||
115 | SND_SOC_DPCM_TRIGGER_PRE}, | ||
116 | .dynamic = 1, | ||
117 | .dpcm_capture = 1, | ||
118 | }, | ||
119 | { | ||
120 | .name = "Capture_2", | ||
121 | .stream_name = "Capture_2", | ||
122 | .cpu_dai_name = "UL2", | ||
123 | .codec_name = "snd-soc-dummy", | ||
124 | .codec_dai_name = "snd-soc-dummy-dai", | ||
125 | .trigger = {SND_SOC_DPCM_TRIGGER_PRE, | ||
126 | SND_SOC_DPCM_TRIGGER_PRE}, | ||
127 | .dynamic = 1, | ||
128 | .dpcm_capture = 1, | ||
129 | }, | ||
130 | { | ||
131 | .name = "Capture_3", | ||
132 | .stream_name = "Capture_3", | ||
133 | .cpu_dai_name = "UL3", | ||
134 | .codec_name = "snd-soc-dummy", | ||
135 | .codec_dai_name = "snd-soc-dummy-dai", | ||
136 | .trigger = {SND_SOC_DPCM_TRIGGER_PRE, | ||
137 | SND_SOC_DPCM_TRIGGER_PRE}, | ||
138 | .dynamic = 1, | ||
139 | .dpcm_capture = 1, | ||
140 | }, | ||
141 | { | ||
142 | .name = "Capture_Mono_1", | ||
143 | .stream_name = "Capture_Mono_1", | ||
144 | .cpu_dai_name = "UL_MONO_1", | ||
145 | .codec_name = "snd-soc-dummy", | ||
146 | .codec_dai_name = "snd-soc-dummy-dai", | ||
147 | .trigger = {SND_SOC_DPCM_TRIGGER_PRE, | ||
148 | SND_SOC_DPCM_TRIGGER_PRE}, | ||
149 | .dynamic = 1, | ||
150 | .dpcm_capture = 1, | ||
151 | }, | ||
152 | { | ||
153 | .name = "Playback_HDMI", | ||
154 | .stream_name = "Playback_HDMI", | ||
155 | .cpu_dai_name = "HDMI", | ||
156 | .codec_name = "snd-soc-dummy", | ||
157 | .codec_dai_name = "snd-soc-dummy-dai", | ||
158 | .trigger = {SND_SOC_DPCM_TRIGGER_PRE, | ||
159 | SND_SOC_DPCM_TRIGGER_PRE}, | ||
160 | .dynamic = 1, | ||
161 | .dpcm_playback = 1, | ||
162 | }, | ||
163 | /* BE */ | ||
164 | { | ||
165 | .name = "Primary Codec", | ||
166 | .cpu_dai_name = "ADDA", | ||
167 | .codec_dai_name = "mt6358-snd-codec-aif1", | ||
168 | .codec_name = "mt6358-sound", | ||
169 | .no_pcm = 1, | ||
170 | .dpcm_playback = 1, | ||
171 | .dpcm_capture = 1, | ||
172 | .ignore_suspend = 1, | ||
173 | }, | ||
174 | { | ||
175 | .name = "PCM 1", | ||
176 | .cpu_dai_name = "PCM 1", | ||
177 | .codec_name = "snd-soc-dummy", | ||
178 | .codec_dai_name = "snd-soc-dummy-dai", | ||
179 | .no_pcm = 1, | ||
180 | .dpcm_playback = 1, | ||
181 | .dpcm_capture = 1, | ||
182 | .ignore_suspend = 1, | ||
183 | }, | ||
184 | { | ||
185 | .name = "PCM 2", | ||
186 | .cpu_dai_name = "PCM 2", | ||
187 | .codec_name = "snd-soc-dummy", | ||
188 | .codec_dai_name = "snd-soc-dummy-dai", | ||
189 | .no_pcm = 1, | ||
190 | .dpcm_playback = 1, | ||
191 | .dpcm_capture = 1, | ||
192 | .ignore_suspend = 1, | ||
193 | }, | ||
194 | { | ||
195 | .name = "I2S0", | ||
196 | .cpu_dai_name = "I2S0", | ||
197 | .codec_dai_name = "bt-sco-pcm", | ||
198 | .codec_name = "bt-sco", | ||
199 | .no_pcm = 1, | ||
200 | .dpcm_capture = 1, | ||
201 | .ignore_suspend = 1, | ||
202 | .be_hw_params_fixup = mt8183_i2s_hw_params_fixup, | ||
203 | .ops = &mt8183_mt6358_i2s_ops, | ||
204 | }, | ||
205 | { | ||
206 | .name = "I2S1", | ||
207 | .cpu_dai_name = "I2S1", | ||
208 | .codec_dai_name = "snd-soc-dummy-dai", | ||
209 | .codec_name = "snd-soc-dummy", | ||
210 | .no_pcm = 1, | ||
211 | .dpcm_playback = 1, | ||
212 | .ignore_suspend = 1, | ||
213 | .be_hw_params_fixup = mt8183_i2s_hw_params_fixup, | ||
214 | .ops = &mt8183_mt6358_i2s_ops, | ||
215 | }, | ||
216 | { | ||
217 | .name = "I2S2", | ||
218 | .cpu_dai_name = "I2S2", | ||
219 | .codec_dai_name = "snd-soc-dummy-dai", | ||
220 | .codec_name = "snd-soc-dummy", | ||
221 | .no_pcm = 1, | ||
222 | .dpcm_capture = 1, | ||
223 | .ignore_suspend = 1, | ||
224 | .be_hw_params_fixup = mt8183_i2s_hw_params_fixup, | ||
225 | .ops = &mt8183_mt6358_i2s_ops, | ||
226 | }, | ||
227 | { | ||
228 | .name = "I2S3", | ||
229 | .cpu_dai_name = "I2S3", | ||
230 | .codec_dai_name = "HiFi", | ||
231 | .codec_name = "max98357a", | ||
232 | .no_pcm = 1, | ||
233 | .dpcm_playback = 1, | ||
234 | .ignore_suspend = 1, | ||
235 | .be_hw_params_fixup = mt8183_i2s_hw_params_fixup, | ||
236 | .ops = &mt8183_mt6358_i2s_ops, | ||
237 | }, | ||
238 | { | ||
239 | .name = "I2S5", | ||
240 | .cpu_dai_name = "I2S5", | ||
241 | .codec_dai_name = "bt-sco-pcm", | ||
242 | .codec_name = "bt-sco", | ||
243 | .no_pcm = 1, | ||
244 | .dpcm_playback = 1, | ||
245 | .ignore_suspend = 1, | ||
246 | .be_hw_params_fixup = mt8183_i2s_hw_params_fixup, | ||
247 | .ops = &mt8183_mt6358_i2s_ops, | ||
248 | }, | ||
249 | { | ||
250 | .name = "TDM", | ||
251 | .cpu_dai_name = "TDM", | ||
252 | .codec_name = "snd-soc-dummy", | ||
253 | .codec_dai_name = "snd-soc-dummy-dai", | ||
254 | .no_pcm = 1, | ||
255 | .dpcm_playback = 1, | ||
256 | .ignore_suspend = 1, | ||
257 | }, | ||
258 | }; | ||
259 | |||
260 | static int | ||
261 | mt8183_mt6358_ts3a227_max98357_headset_init(struct snd_soc_component *cpnt); | ||
262 | |||
263 | static struct snd_soc_aux_dev mt8183_mt6358_ts3a227_max98357_headset_dev = { | ||
264 | .name = "Headset Chip", | ||
265 | .init = mt8183_mt6358_ts3a227_max98357_headset_init, | ||
266 | }; | ||
267 | |||
268 | static struct snd_soc_card mt8183_mt6358_ts3a227_max98357_card = { | ||
269 | .name = "mt8183_mt6358_ts3a227_max98357", | ||
270 | .owner = THIS_MODULE, | ||
271 | .dai_link = mt8183_mt6358_ts3a227_max98357_dai_links, | ||
272 | .num_links = ARRAY_SIZE(mt8183_mt6358_ts3a227_max98357_dai_links), | ||
273 | .aux_dev = &mt8183_mt6358_ts3a227_max98357_headset_dev, | ||
274 | .num_aux_devs = 1, | ||
275 | }; | ||
276 | |||
277 | static int | ||
278 | mt8183_mt6358_ts3a227_max98357_headset_init(struct snd_soc_component *component) | ||
279 | { | ||
280 | int ret; | ||
281 | |||
282 | /* Enable Headset and 4 Buttons Jack detection */ | ||
283 | ret = snd_soc_card_jack_new(&mt8183_mt6358_ts3a227_max98357_card, | ||
284 | "Headset Jack", | ||
285 | SND_JACK_HEADSET | | ||
286 | SND_JACK_BTN_0 | SND_JACK_BTN_1 | | ||
287 | SND_JACK_BTN_2 | SND_JACK_BTN_3, | ||
288 | &headset_jack, | ||
289 | headset_jack_pins, | ||
290 | ARRAY_SIZE(headset_jack_pins)); | ||
291 | if (ret) | ||
292 | return ret; | ||
293 | |||
294 | ret = ts3a227e_enable_jack_detect(component, &headset_jack); | ||
295 | |||
296 | return ret; | ||
297 | } | ||
298 | |||
299 | static int | ||
300 | mt8183_mt6358_ts3a227_max98357_dev_probe(struct platform_device *pdev) | ||
301 | { | ||
302 | struct snd_soc_card *card = &mt8183_mt6358_ts3a227_max98357_card; | ||
303 | struct device_node *platform_node; | ||
304 | struct snd_soc_dai_link *dai_link; | ||
305 | struct pinctrl *default_pins; | ||
306 | int ret, i; | ||
307 | |||
308 | card->dev = &pdev->dev; | ||
309 | |||
310 | platform_node = of_parse_phandle(pdev->dev.of_node, | ||
311 | "mediatek,platform", 0); | ||
312 | if (!platform_node) { | ||
313 | dev_err(&pdev->dev, "Property 'platform' missing or invalid\n"); | ||
314 | return -EINVAL; | ||
315 | } | ||
316 | |||
317 | for_each_card_prelinks(card, i, dai_link) { | ||
318 | /* In the alsa soc-core, the "platform" will be | ||
319 | * allocated by devm_kzalloc if null. | ||
320 | * There is a special case that registerring | ||
321 | * sound card is failed at the first time, but | ||
322 | * the "platform" will not null when probe is trying | ||
323 | * again. It's not expected normally. | ||
324 | */ | ||
325 | dai_link->platform = NULL; | ||
326 | |||
327 | if (dai_link->platform_name) | ||
328 | continue; | ||
329 | dai_link->platform_of_node = platform_node; | ||
330 | } | ||
331 | |||
332 | mt8183_mt6358_ts3a227_max98357_headset_dev.codec_of_node = | ||
333 | of_parse_phandle(pdev->dev.of_node, | ||
334 | "mediatek,headset-codec", 0); | ||
335 | if (!mt8183_mt6358_ts3a227_max98357_headset_dev.codec_of_node) { | ||
336 | dev_err(&pdev->dev, | ||
337 | "Property 'mediatek,headset-codec' missing/invalid\n"); | ||
338 | return -EINVAL; | ||
339 | } | ||
340 | |||
341 | ret = devm_snd_soc_register_card(&pdev->dev, card); | ||
342 | if (ret) | ||
343 | dev_err(&pdev->dev, "%s snd_soc_register_card fail %d\n", | ||
344 | __func__, ret); | ||
345 | |||
346 | default_pins = | ||
347 | devm_pinctrl_get_select(&pdev->dev, PINCTRL_STATE_DEFAULT); | ||
348 | if (IS_ERR(default_pins)) { | ||
349 | dev_err(&pdev->dev, "%s set pins failed\n", | ||
350 | __func__); | ||
351 | return PTR_ERR(default_pins); | ||
352 | } | ||
353 | |||
354 | return ret; | ||
355 | } | ||
356 | |||
357 | #ifdef CONFIG_OF | ||
358 | static const struct of_device_id mt8183_mt6358_ts3a227_max98357_dt_match[] = { | ||
359 | {.compatible = "mediatek,mt8183_mt6358_ts3a227_max98357",}, | ||
360 | {} | ||
361 | }; | ||
362 | #endif | ||
363 | |||
364 | static struct platform_driver mt8183_mt6358_ts3a227_max98357_driver = { | ||
365 | .driver = { | ||
366 | .name = "mt8183_mt6358_ts3a227_max98357", | ||
367 | .owner = THIS_MODULE, | ||
368 | #ifdef CONFIG_OF | ||
369 | .of_match_table = mt8183_mt6358_ts3a227_max98357_dt_match, | ||
370 | #endif | ||
371 | }, | ||
372 | .probe = mt8183_mt6358_ts3a227_max98357_dev_probe, | ||
373 | }; | ||
374 | |||
375 | module_platform_driver(mt8183_mt6358_ts3a227_max98357_driver); | ||
376 | |||
377 | /* Module information */ | ||
378 | MODULE_DESCRIPTION("MT8183-MT6358-TS3A227-MAX98357 ALSA SoC machine driver"); | ||
379 | MODULE_AUTHOR("Shunli Wang <shunli.wang@mediatek.com>"); | ||
380 | MODULE_LICENSE("GPL v2"); | ||
381 | MODULE_ALIAS("mt8183_mt6358_ts3a227_max98357 soc card"); | ||
382 | |||