Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c
26488 views
1
// SPDX-License-Identifier: GPL-2.0
2
/*
3
* mt8173-rt5650-rt5676.c -- MT8173 machine driver with RT5650/5676 codecs
4
*
5
* Copyright (c) 2015 MediaTek Inc.
6
* Author: Koro Chen <[email protected]>
7
*/
8
9
#include <linux/module.h>
10
#include <sound/soc.h>
11
#include <sound/jack.h>
12
#include "../../codecs/rt5645.h"
13
#include "../../codecs/rt5677.h"
14
15
#define MCLK_FOR_CODECS 12288000
16
17
static const struct snd_soc_dapm_widget mt8173_rt5650_rt5676_widgets[] = {
18
SND_SOC_DAPM_SPK("Speaker", NULL),
19
SND_SOC_DAPM_MIC("Int Mic", NULL),
20
SND_SOC_DAPM_HP("Headphone", NULL),
21
SND_SOC_DAPM_MIC("Headset Mic", NULL),
22
};
23
24
static const struct snd_soc_dapm_route mt8173_rt5650_rt5676_routes[] = {
25
{"Speaker", NULL, "SPOL"},
26
{"Speaker", NULL, "SPOR"},
27
{"Speaker", NULL, "Sub AIF2TX"}, /* IF2 ADC to 5650 */
28
{"Sub DMIC L1", NULL, "Int Mic"}, /* DMIC from 5676 */
29
{"Sub DMIC R1", NULL, "Int Mic"},
30
{"Headphone", NULL, "HPOL"},
31
{"Headphone", NULL, "HPOR"},
32
{"Headphone", NULL, "Sub AIF2TX"}, /* IF2 ADC to 5650 */
33
{"IN1P", NULL, "Headset Mic"},
34
{"IN1N", NULL, "Headset Mic"},
35
{"Sub AIF2RX", NULL, "Headset Mic"}, /* IF2 DAC from 5650 */
36
};
37
38
static const struct snd_kcontrol_new mt8173_rt5650_rt5676_controls[] = {
39
SOC_DAPM_PIN_SWITCH("Speaker"),
40
SOC_DAPM_PIN_SWITCH("Int Mic"),
41
SOC_DAPM_PIN_SWITCH("Headphone"),
42
SOC_DAPM_PIN_SWITCH("Headset Mic"),
43
};
44
45
static struct snd_soc_jack_pin mt8173_rt5650_rt5676_jack_pins[] = {
46
{
47
.pin = "Headphone",
48
.mask = SND_JACK_HEADPHONE,
49
},
50
{
51
.pin = "Headset Mic",
52
.mask = SND_JACK_MICROPHONE,
53
},
54
};
55
56
static int mt8173_rt5650_rt5676_hw_params(struct snd_pcm_substream *substream,
57
struct snd_pcm_hw_params *params)
58
{
59
struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
60
struct snd_soc_dai *codec_dai;
61
int i, ret;
62
63
for_each_rtd_codec_dais(rtd, i, codec_dai) {
64
/* pll from mclk 12.288M */
65
ret = snd_soc_dai_set_pll(codec_dai, 0, 0, MCLK_FOR_CODECS,
66
params_rate(params) * 512);
67
if (ret)
68
return ret;
69
70
/* sysclk from pll */
71
ret = snd_soc_dai_set_sysclk(codec_dai, 1,
72
params_rate(params) * 512,
73
SND_SOC_CLOCK_IN);
74
if (ret)
75
return ret;
76
}
77
return 0;
78
}
79
80
static const struct snd_soc_ops mt8173_rt5650_rt5676_ops = {
81
.hw_params = mt8173_rt5650_rt5676_hw_params,
82
};
83
84
static struct snd_soc_jack mt8173_rt5650_rt5676_jack;
85
86
static int mt8173_rt5650_rt5676_init(struct snd_soc_pcm_runtime *runtime)
87
{
88
struct snd_soc_card *card = runtime->card;
89
struct snd_soc_component *component = snd_soc_rtd_to_codec(runtime, 0)->component;
90
struct snd_soc_component *component_sub = snd_soc_rtd_to_codec(runtime, 1)->component;
91
int ret;
92
93
rt5645_sel_asrc_clk_src(component,
94
RT5645_DA_STEREO_FILTER |
95
RT5645_AD_STEREO_FILTER,
96
RT5645_CLK_SEL_I2S1_ASRC);
97
rt5677_sel_asrc_clk_src(component_sub,
98
RT5677_DA_STEREO_FILTER |
99
RT5677_AD_STEREO1_FILTER,
100
RT5677_CLK_SEL_I2S1_ASRC);
101
rt5677_sel_asrc_clk_src(component_sub,
102
RT5677_AD_STEREO2_FILTER |
103
RT5677_I2S2_SOURCE,
104
RT5677_CLK_SEL_I2S2_ASRC);
105
106
/* enable jack detection */
107
ret = snd_soc_card_jack_new_pins(card, "Headset Jack",
108
SND_JACK_HEADPHONE | SND_JACK_MICROPHONE |
109
SND_JACK_BTN_0 | SND_JACK_BTN_1 |
110
SND_JACK_BTN_2 | SND_JACK_BTN_3,
111
&mt8173_rt5650_rt5676_jack,
112
mt8173_rt5650_rt5676_jack_pins,
113
ARRAY_SIZE(mt8173_rt5650_rt5676_jack_pins));
114
if (ret) {
115
dev_err(card->dev, "Can't new Headset Jack %d\n", ret);
116
return ret;
117
}
118
119
return rt5645_set_jack_detect(component,
120
&mt8173_rt5650_rt5676_jack,
121
&mt8173_rt5650_rt5676_jack,
122
&mt8173_rt5650_rt5676_jack);
123
}
124
125
126
enum {
127
DAI_LINK_PLAYBACK,
128
DAI_LINK_CAPTURE,
129
DAI_LINK_HDMI,
130
DAI_LINK_CODEC_I2S,
131
DAI_LINK_HDMI_I2S,
132
DAI_LINK_INTERCODEC
133
};
134
135
SND_SOC_DAILINK_DEFS(playback,
136
DAILINK_COMP_ARRAY(COMP_CPU("DL1")),
137
DAILINK_COMP_ARRAY(COMP_DUMMY()),
138
DAILINK_COMP_ARRAY(COMP_EMPTY()));
139
140
SND_SOC_DAILINK_DEFS(capture,
141
DAILINK_COMP_ARRAY(COMP_CPU("VUL")),
142
DAILINK_COMP_ARRAY(COMP_DUMMY()),
143
DAILINK_COMP_ARRAY(COMP_EMPTY()));
144
145
SND_SOC_DAILINK_DEFS(hdmi_pcm,
146
DAILINK_COMP_ARRAY(COMP_CPU("HDMI")),
147
DAILINK_COMP_ARRAY(COMP_DUMMY()),
148
DAILINK_COMP_ARRAY(COMP_EMPTY()));
149
150
SND_SOC_DAILINK_DEFS(codec,
151
DAILINK_COMP_ARRAY(COMP_CPU("I2S")),
152
DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "rt5645-aif1"),
153
COMP_CODEC(NULL, "rt5677-aif1")),
154
DAILINK_COMP_ARRAY(COMP_EMPTY()));
155
156
SND_SOC_DAILINK_DEFS(hdmi_be,
157
DAILINK_COMP_ARRAY(COMP_CPU("HDMIO")),
158
DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "i2s-hifi")),
159
DAILINK_COMP_ARRAY(COMP_EMPTY()));
160
161
SND_SOC_DAILINK_DEFS(intercodec,
162
DAILINK_COMP_ARRAY(COMP_DUMMY()),
163
DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "rt5677-aif2")),
164
DAILINK_COMP_ARRAY(COMP_DUMMY()));
165
166
/* Digital audio interface glue - connects codec <---> CPU */
167
static struct snd_soc_dai_link mt8173_rt5650_rt5676_dais[] = {
168
/* Front End DAI links */
169
[DAI_LINK_PLAYBACK] = {
170
.name = "rt5650_rt5676 Playback",
171
.stream_name = "rt5650_rt5676 Playback",
172
.trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
173
.dynamic = 1,
174
.playback_only = 1,
175
SND_SOC_DAILINK_REG(playback),
176
},
177
[DAI_LINK_CAPTURE] = {
178
.name = "rt5650_rt5676 Capture",
179
.stream_name = "rt5650_rt5676 Capture",
180
.trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
181
.dynamic = 1,
182
.capture_only = 1,
183
SND_SOC_DAILINK_REG(capture),
184
},
185
[DAI_LINK_HDMI] = {
186
.name = "HDMI",
187
.stream_name = "HDMI PCM",
188
.trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
189
.dynamic = 1,
190
.playback_only = 1,
191
SND_SOC_DAILINK_REG(hdmi_pcm),
192
},
193
194
/* Back End DAI links */
195
[DAI_LINK_CODEC_I2S] = {
196
.name = "Codec",
197
.no_pcm = 1,
198
.init = mt8173_rt5650_rt5676_init,
199
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
200
SND_SOC_DAIFMT_CBC_CFC,
201
.ops = &mt8173_rt5650_rt5676_ops,
202
.ignore_pmdown_time = 1,
203
SND_SOC_DAILINK_REG(codec),
204
},
205
[DAI_LINK_HDMI_I2S] = {
206
.name = "HDMI BE",
207
.no_pcm = 1,
208
.playback_only = 1,
209
SND_SOC_DAILINK_REG(hdmi_be),
210
},
211
/* rt5676 <-> rt5650 intercodec link: Sets rt5676 I2S2 as master */
212
[DAI_LINK_INTERCODEC] = {
213
.name = "rt5650_rt5676 intercodec",
214
.stream_name = "rt5650_rt5676 intercodec",
215
.no_pcm = 1,
216
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
217
SND_SOC_DAIFMT_CBP_CFP,
218
SND_SOC_DAILINK_REG(intercodec),
219
},
220
};
221
222
static struct snd_soc_codec_conf mt8173_rt5650_rt5676_codec_conf[] = {
223
{
224
.name_prefix = "Sub",
225
},
226
};
227
228
static struct snd_soc_card mt8173_rt5650_rt5676_card = {
229
.name = "mtk-rt5650-rt5676",
230
.owner = THIS_MODULE,
231
.dai_link = mt8173_rt5650_rt5676_dais,
232
.num_links = ARRAY_SIZE(mt8173_rt5650_rt5676_dais),
233
.codec_conf = mt8173_rt5650_rt5676_codec_conf,
234
.num_configs = ARRAY_SIZE(mt8173_rt5650_rt5676_codec_conf),
235
.controls = mt8173_rt5650_rt5676_controls,
236
.num_controls = ARRAY_SIZE(mt8173_rt5650_rt5676_controls),
237
.dapm_widgets = mt8173_rt5650_rt5676_widgets,
238
.num_dapm_widgets = ARRAY_SIZE(mt8173_rt5650_rt5676_widgets),
239
.dapm_routes = mt8173_rt5650_rt5676_routes,
240
.num_dapm_routes = ARRAY_SIZE(mt8173_rt5650_rt5676_routes),
241
};
242
243
static int mt8173_rt5650_rt5676_dev_probe(struct platform_device *pdev)
244
{
245
struct snd_soc_card *card = &mt8173_rt5650_rt5676_card;
246
struct device_node *platform_node;
247
struct snd_soc_dai_link *dai_link;
248
int i, ret;
249
250
platform_node = of_parse_phandle(pdev->dev.of_node,
251
"mediatek,platform", 0);
252
if (!platform_node) {
253
dev_err(&pdev->dev, "Property 'platform' missing or invalid\n");
254
return -EINVAL;
255
}
256
257
for_each_card_prelinks(card, i, dai_link) {
258
if (dai_link->platforms->name)
259
continue;
260
dai_link->platforms->of_node = platform_node;
261
}
262
263
mt8173_rt5650_rt5676_dais[DAI_LINK_CODEC_I2S].codecs[0].of_node =
264
of_parse_phandle(pdev->dev.of_node, "mediatek,audio-codec", 0);
265
if (!mt8173_rt5650_rt5676_dais[DAI_LINK_CODEC_I2S].codecs[0].of_node) {
266
dev_err(&pdev->dev,
267
"Property 'audio-codec' missing or invalid\n");
268
ret = -EINVAL;
269
goto put_node;
270
}
271
mt8173_rt5650_rt5676_dais[DAI_LINK_CODEC_I2S].codecs[1].of_node =
272
of_parse_phandle(pdev->dev.of_node, "mediatek,audio-codec", 1);
273
if (!mt8173_rt5650_rt5676_dais[DAI_LINK_CODEC_I2S].codecs[1].of_node) {
274
dev_err(&pdev->dev,
275
"Property 'audio-codec' missing or invalid\n");
276
ret = -EINVAL;
277
goto put_node;
278
}
279
mt8173_rt5650_rt5676_codec_conf[0].dlc.of_node =
280
mt8173_rt5650_rt5676_dais[DAI_LINK_CODEC_I2S].codecs[1].of_node;
281
282
mt8173_rt5650_rt5676_dais[DAI_LINK_INTERCODEC].codecs->of_node =
283
mt8173_rt5650_rt5676_dais[DAI_LINK_CODEC_I2S].codecs[1].of_node;
284
285
mt8173_rt5650_rt5676_dais[DAI_LINK_HDMI_I2S].codecs->of_node =
286
of_parse_phandle(pdev->dev.of_node, "mediatek,audio-codec", 2);
287
if (!mt8173_rt5650_rt5676_dais[DAI_LINK_HDMI_I2S].codecs->of_node) {
288
dev_err(&pdev->dev,
289
"Property 'audio-codec' missing or invalid\n");
290
ret = -EINVAL;
291
goto put_node;
292
}
293
294
card->dev = &pdev->dev;
295
296
ret = devm_snd_soc_register_card(&pdev->dev, card);
297
298
put_node:
299
of_node_put(platform_node);
300
return ret;
301
}
302
303
static const struct of_device_id mt8173_rt5650_rt5676_dt_match[] = {
304
{ .compatible = "mediatek,mt8173-rt5650-rt5676", },
305
{ }
306
};
307
MODULE_DEVICE_TABLE(of, mt8173_rt5650_rt5676_dt_match);
308
309
static struct platform_driver mt8173_rt5650_rt5676_driver = {
310
.driver = {
311
.name = "mtk-rt5650-rt5676",
312
.of_match_table = mt8173_rt5650_rt5676_dt_match,
313
.pm = &snd_soc_pm_ops,
314
},
315
.probe = mt8173_rt5650_rt5676_dev_probe,
316
};
317
318
module_platform_driver(mt8173_rt5650_rt5676_driver);
319
320
/* Module information */
321
MODULE_DESCRIPTION("MT8173 RT5650 and RT5676 SoC machine driver");
322
MODULE_AUTHOR("Koro Chen <[email protected]>");
323
MODULE_LICENSE("GPL v2");
324
MODULE_ALIAS("platform:mtk-rt5650-rt5676");
325
326
327