Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/sound/soc/mediatek/mt7986/mt7986-wm8960.c
26488 views
1
// SPDX-License-Identifier: GPL-2.0
2
/*
3
* mt7986-wm8960.c -- MT7986-WM8960 ALSA SoC machine driver
4
*
5
* Copyright (c) 2023 MediaTek Inc.
6
* Authors: Vic Wu <[email protected]>
7
* Maso Huang <[email protected]>
8
*/
9
10
#include <linux/module.h>
11
#include <sound/soc.h>
12
13
#include "mt7986-afe-common.h"
14
15
static const struct snd_soc_dapm_widget mt7986_wm8960_widgets[] = {
16
SND_SOC_DAPM_HP("Headphone", NULL),
17
SND_SOC_DAPM_MIC("AMIC", NULL),
18
};
19
20
static const struct snd_kcontrol_new mt7986_wm8960_controls[] = {
21
SOC_DAPM_PIN_SWITCH("Headphone"),
22
SOC_DAPM_PIN_SWITCH("AMIC"),
23
};
24
25
SND_SOC_DAILINK_DEFS(playback,
26
DAILINK_COMP_ARRAY(COMP_CPU("DL1")),
27
DAILINK_COMP_ARRAY(COMP_DUMMY()),
28
DAILINK_COMP_ARRAY(COMP_EMPTY()));
29
30
SND_SOC_DAILINK_DEFS(capture,
31
DAILINK_COMP_ARRAY(COMP_CPU("UL1")),
32
DAILINK_COMP_ARRAY(COMP_DUMMY()),
33
DAILINK_COMP_ARRAY(COMP_EMPTY()));
34
35
SND_SOC_DAILINK_DEFS(codec,
36
DAILINK_COMP_ARRAY(COMP_CPU("ETDM")),
37
DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "wm8960-hifi")),
38
DAILINK_COMP_ARRAY(COMP_EMPTY()));
39
40
static struct snd_soc_dai_link mt7986_wm8960_dai_links[] = {
41
/* FE */
42
{
43
.name = "wm8960-playback",
44
.stream_name = "wm8960-playback",
45
.trigger = {SND_SOC_DPCM_TRIGGER_POST,
46
SND_SOC_DPCM_TRIGGER_POST},
47
.dynamic = 1,
48
.playback_only = 1,
49
SND_SOC_DAILINK_REG(playback),
50
},
51
{
52
.name = "wm8960-capture",
53
.stream_name = "wm8960-capture",
54
.trigger = {SND_SOC_DPCM_TRIGGER_POST,
55
SND_SOC_DPCM_TRIGGER_POST},
56
.dynamic = 1,
57
.capture_only = 1,
58
SND_SOC_DAILINK_REG(capture),
59
},
60
/* BE */
61
{
62
.name = "wm8960-codec",
63
.no_pcm = 1,
64
.dai_fmt = SND_SOC_DAIFMT_I2S |
65
SND_SOC_DAIFMT_NB_NF |
66
SND_SOC_DAIFMT_CBC_CFC |
67
SND_SOC_DAIFMT_GATED,
68
SND_SOC_DAILINK_REG(codec),
69
},
70
};
71
72
static struct snd_soc_card mt7986_wm8960_card = {
73
.name = "mt7986-wm8960",
74
.owner = THIS_MODULE,
75
.dai_link = mt7986_wm8960_dai_links,
76
.num_links = ARRAY_SIZE(mt7986_wm8960_dai_links),
77
.controls = mt7986_wm8960_controls,
78
.num_controls = ARRAY_SIZE(mt7986_wm8960_controls),
79
.dapm_widgets = mt7986_wm8960_widgets,
80
.num_dapm_widgets = ARRAY_SIZE(mt7986_wm8960_widgets),
81
};
82
83
static int mt7986_wm8960_machine_probe(struct platform_device *pdev)
84
{
85
struct snd_soc_card *card = &mt7986_wm8960_card;
86
struct snd_soc_dai_link *dai_link;
87
struct device_node *platform, *codec;
88
struct device_node *platform_dai_node, *codec_dai_node;
89
int ret, i;
90
91
card->dev = &pdev->dev;
92
93
platform = of_get_child_by_name(pdev->dev.of_node, "platform");
94
95
if (platform) {
96
platform_dai_node = of_parse_phandle(platform, "sound-dai", 0);
97
of_node_put(platform);
98
99
if (!platform_dai_node) {
100
dev_err(&pdev->dev, "Failed to parse platform/sound-dai property\n");
101
return -EINVAL;
102
}
103
} else {
104
dev_err(&pdev->dev, "Property 'platform' missing or invalid\n");
105
return -EINVAL;
106
}
107
108
for_each_card_prelinks(card, i, dai_link) {
109
if (dai_link->platforms->name)
110
continue;
111
dai_link->platforms->of_node = platform_dai_node;
112
}
113
114
codec = of_get_child_by_name(pdev->dev.of_node, "codec");
115
116
if (codec) {
117
codec_dai_node = of_parse_phandle(codec, "sound-dai", 0);
118
of_node_put(codec);
119
120
if (!codec_dai_node) {
121
of_node_put(platform_dai_node);
122
dev_err(&pdev->dev, "Failed to parse codec/sound-dai property\n");
123
return -EINVAL;
124
}
125
} else {
126
of_node_put(platform_dai_node);
127
dev_err(&pdev->dev, "Property 'codec' missing or invalid\n");
128
return -EINVAL;
129
}
130
131
for_each_card_prelinks(card, i, dai_link) {
132
if (dai_link->codecs->name)
133
continue;
134
dai_link->codecs->of_node = codec_dai_node;
135
}
136
137
ret = snd_soc_of_parse_audio_routing(card, "audio-routing");
138
if (ret) {
139
dev_err(&pdev->dev, "Failed to parse audio-routing: %d\n", ret);
140
goto err_of_node_put;
141
}
142
143
ret = devm_snd_soc_register_card(&pdev->dev, card);
144
if (ret) {
145
dev_err_probe(&pdev->dev, ret, "%s snd_soc_register_card fail\n", __func__);
146
goto err_of_node_put;
147
}
148
149
err_of_node_put:
150
of_node_put(platform_dai_node);
151
of_node_put(codec_dai_node);
152
return ret;
153
}
154
155
static const struct of_device_id mt7986_wm8960_machine_dt_match[] = {
156
{.compatible = "mediatek,mt7986-wm8960-sound"},
157
{ /* sentinel */ }
158
};
159
MODULE_DEVICE_TABLE(of, mt7986_wm8960_machine_dt_match);
160
161
static struct platform_driver mt7986_wm8960_machine = {
162
.driver = {
163
.name = "mt7986-wm8960",
164
.of_match_table = mt7986_wm8960_machine_dt_match,
165
},
166
.probe = mt7986_wm8960_machine_probe,
167
};
168
169
module_platform_driver(mt7986_wm8960_machine);
170
171
/* Module information */
172
MODULE_DESCRIPTION("MT7986 WM8960 ALSA SoC machine driver");
173
MODULE_AUTHOR("Vic Wu <[email protected]>");
174
MODULE_LICENSE("GPL");
175
MODULE_ALIAS("mt7986 wm8960 soc card");
176
177