1 // SPDX-License-Identifier: GPL-2.0
2 // Copyright (c) 2018, Linaro Limited.
3 // Copyright (c) 2018, The Linux Foundation. All rights reserved.
5 #include <dt-bindings/sound/qcom,q6afe.h>
6 #include <linux/module.h>
7 #include <sound/jack.h>
8 #include <linux/input-event-codes.h>
13 static const struct snd_soc_dapm_widget qcom_jack_snd_widgets
[] = {
14 SND_SOC_DAPM_HP("Headphone Jack", NULL
),
15 SND_SOC_DAPM_MIC("Mic Jack", NULL
),
16 SND_SOC_DAPM_SPK("DP0 Jack", NULL
),
17 SND_SOC_DAPM_SPK("DP1 Jack", NULL
),
18 SND_SOC_DAPM_SPK("DP2 Jack", NULL
),
19 SND_SOC_DAPM_SPK("DP3 Jack", NULL
),
20 SND_SOC_DAPM_SPK("DP4 Jack", NULL
),
21 SND_SOC_DAPM_SPK("DP5 Jack", NULL
),
22 SND_SOC_DAPM_SPK("DP6 Jack", NULL
),
23 SND_SOC_DAPM_SPK("DP7 Jack", NULL
),
26 int qcom_snd_parse_of(struct snd_soc_card
*card
)
28 struct device_node
*np
;
29 struct device_node
*codec
= NULL
;
30 struct device_node
*platform
= NULL
;
31 struct device_node
*cpu
= NULL
;
32 struct device
*dev
= card
->dev
;
33 struct snd_soc_dai_link
*link
;
34 struct of_phandle_args args
;
35 struct snd_soc_dai_link_component
*dlc
;
38 ret
= snd_soc_of_parse_card_name(card
, "model");
39 if (ret
== 0 && !card
->name
)
40 /* Deprecated, only for compatibility with old device trees */
41 ret
= snd_soc_of_parse_card_name(card
, "qcom,model");
43 dev_err(dev
, "Error parsing card name: %d\n", ret
);
47 if (of_property_read_bool(dev
->of_node
, "widgets")) {
48 ret
= snd_soc_of_parse_audio_simple_widgets(card
, "widgets");
54 if (of_property_read_bool(dev
->of_node
, "audio-routing")) {
55 ret
= snd_soc_of_parse_audio_routing(card
, "audio-routing");
59 /* Deprecated, only for compatibility with old device trees */
60 if (of_property_read_bool(dev
->of_node
, "qcom,audio-routing")) {
61 ret
= snd_soc_of_parse_audio_routing(card
, "qcom,audio-routing");
66 ret
= snd_soc_of_parse_pin_switches(card
, "pin-switches");
70 ret
= snd_soc_of_parse_aux_devs(card
, "aux-devs");
75 num_links
= of_get_available_child_count(dev
->of_node
);
77 /* Allocate the DAI link array */
78 card
->dai_link
= devm_kcalloc(dev
, num_links
, sizeof(*link
), GFP_KERNEL
);
82 card
->num_links
= num_links
;
83 link
= card
->dai_link
;
85 for_each_available_child_of_node(dev
->of_node
, np
) {
86 dlc
= devm_kcalloc(dev
, 2, sizeof(*dlc
), GFP_KERNEL
);
93 link
->platforms
= &dlc
[1];
96 link
->num_platforms
= 1;
98 ret
= of_property_read_string(np
, "link-name", &link
->name
);
100 dev_err(card
->dev
, "error getting codec dai_link name\n");
104 cpu
= of_get_child_by_name(np
, "cpu");
105 platform
= of_get_child_by_name(np
, "platform");
106 codec
= of_get_child_by_name(np
, "codec");
109 dev_err(dev
, "%s: Can't find cpu DT node\n", link
->name
);
114 ret
= snd_soc_of_get_dlc(cpu
, &args
, link
->cpus
, 0);
116 dev_err_probe(card
->dev
, ret
,
117 "%s: error getting cpu dai name\n", link
->name
);
121 link
->id
= args
.args
[0];
124 link
->platforms
->of_node
= of_parse_phandle(platform
,
127 if (!link
->platforms
->of_node
) {
128 dev_err(card
->dev
, "%s: platform dai not found\n", link
->name
);
133 link
->platforms
->of_node
= link
->cpus
->of_node
;
137 ret
= snd_soc_of_get_dai_link_codecs(dev
, codec
, link
);
139 dev_err_probe(card
->dev
, ret
,
140 "%s: codec dai not found\n", link
->name
);
147 link
->ignore_pmdown_time
= 1;
151 link
->codecs
= &snd_soc_dummy_dlc
;
152 link
->num_codecs
= 1;
156 if (platform
|| !codec
) {
158 link
->ignore_suspend
= 1;
162 link
->stream_name
= link
->name
;
167 of_node_put(platform
);
170 if (!card
->dapm_widgets
) {
171 card
->dapm_widgets
= qcom_jack_snd_widgets
;
172 card
->num_dapm_widgets
= ARRAY_SIZE(qcom_jack_snd_widgets
);
179 of_node_put(platform
);
184 EXPORT_SYMBOL_GPL(qcom_snd_parse_of
);
186 static struct snd_soc_jack_pin qcom_headset_jack_pins
[] = {
190 .mask
= SND_JACK_MICROPHONE
,
193 .pin
= "Headphone Jack",
194 .mask
= SND_JACK_HEADPHONE
,
198 int qcom_snd_wcd_jack_setup(struct snd_soc_pcm_runtime
*rtd
,
199 struct snd_soc_jack
*jack
, bool *jack_setup
)
201 struct snd_soc_dai
*cpu_dai
= snd_soc_rtd_to_cpu(rtd
, 0);
202 struct snd_soc_dai
*codec_dai
= snd_soc_rtd_to_codec(rtd
, 0);
203 struct snd_soc_card
*card
= rtd
->card
;
207 rval
= snd_soc_card_jack_new_pins(card
, "Headset Jack",
208 SND_JACK_HEADSET
| SND_JACK_LINEOUT
|
209 SND_JACK_MECHANICAL
|
210 SND_JACK_BTN_0
| SND_JACK_BTN_1
|
211 SND_JACK_BTN_2
| SND_JACK_BTN_3
|
212 SND_JACK_BTN_4
| SND_JACK_BTN_5
,
213 jack
, qcom_headset_jack_pins
,
214 ARRAY_SIZE(qcom_headset_jack_pins
));
217 dev_err(card
->dev
, "Unable to add Headphone Jack\n");
221 snd_jack_set_key(jack
->jack
, SND_JACK_BTN_0
, KEY_MEDIA
);
222 snd_jack_set_key(jack
->jack
, SND_JACK_BTN_1
, KEY_VOICECOMMAND
);
223 snd_jack_set_key(jack
->jack
, SND_JACK_BTN_2
, KEY_VOLUMEUP
);
224 snd_jack_set_key(jack
->jack
, SND_JACK_BTN_3
, KEY_VOLUMEDOWN
);
228 switch (cpu_dai
->id
) {
229 case TX_CODEC_DMA_TX_0
:
230 case TX_CODEC_DMA_TX_1
:
231 case TX_CODEC_DMA_TX_2
:
232 case TX_CODEC_DMA_TX_3
:
233 for_each_rtd_codec_dais(rtd
, i
, codec_dai
) {
234 rval
= snd_soc_component_set_jack(codec_dai
->component
,
236 if (rval
!= 0 && rval
!= -ENOTSUPP
) {
237 dev_warn(card
->dev
, "Failed to set jack: %d\n", rval
);
250 EXPORT_SYMBOL_GPL(qcom_snd_wcd_jack_setup
);
252 int qcom_snd_dp_jack_setup(struct snd_soc_pcm_runtime
*rtd
,
253 struct snd_soc_jack
*dp_jack
, int dp_pcm_id
)
255 struct snd_soc_dai
*codec_dai
= snd_soc_rtd_to_codec(rtd
, 0);
256 struct snd_soc_card
*card
= rtd
->card
;
257 char jack_name
[NAME_SIZE
];
260 snprintf(jack_name
, sizeof(jack_name
), "DP%d Jack", dp_pcm_id
);
261 rval
= snd_soc_card_jack_new(card
, jack_name
, SND_JACK_AVOUT
, dp_jack
);
265 for_each_rtd_codec_dais(rtd
, i
, codec_dai
) {
266 rval
= snd_soc_component_set_jack(codec_dai
->component
, dp_jack
, NULL
);
267 if (rval
!= 0 && rval
!= -ENOTSUPP
) {
268 dev_warn(card
->dev
, "Failed to set jack: %d\n", rval
);
275 EXPORT_SYMBOL_GPL(qcom_snd_dp_jack_setup
);
277 MODULE_DESCRIPTION("ASoC Qualcomm helper functions");
278 MODULE_LICENSE("GPL");