1 // SPDX-License-Identifier: GPL-2.0-only
2 // This file incorporates work covered by the following copyright notice:
3 // Copyright (c) 2020 Intel Corporation
4 // Copyright (c) 2024 Advanced Micro Devices, Inc.
7 * soc_sdw_rt711_sdca - Helpers to handle RT711-SDCA from generic machine driver
10 #include <linux/device.h>
11 #include <linux/errno.h>
12 #include <linux/input.h>
13 #include <linux/soundwire/sdw.h>
14 #include <linux/soundwire/sdw_type.h>
15 #include <sound/control.h>
16 #include <sound/soc.h>
17 #include <sound/soc-acpi.h>
18 #include <sound/soc-dapm.h>
19 #include <sound/jack.h>
20 #include <sound/soc_sdw_utils.h>
23 * Note this MUST be called before snd_soc_register_card(), so that the props
24 * are in place before the codec component driver's probe function parses them.
26 static int rt_sdca_jack_add_codec_device_props(struct device
*sdw_dev
, unsigned long quirk
)
28 struct property_entry props
[SOC_SDW_MAX_NO_PROPS
] = {};
29 struct fwnode_handle
*fwnode
;
32 if (!SOC_SDW_JACK_JDSRC(quirk
))
35 props
[0] = PROPERTY_ENTRY_U32("realtek,jd-src", SOC_SDW_JACK_JDSRC(quirk
));
37 fwnode
= fwnode_create_software_node(props
, NULL
);
39 return PTR_ERR(fwnode
);
41 ret
= device_add_software_node(sdw_dev
, to_software_node(fwnode
));
43 fwnode_handle_put(fwnode
);
48 static const struct snd_soc_dapm_route rt711_sdca_map
[] = {
49 { "Headphone", NULL
, "rt711 HP" },
50 { "rt711 MIC2", NULL
, "Headset Mic" },
53 static const struct snd_soc_dapm_route rt712_sdca_map
[] = {
54 { "Headphone", NULL
, "rt712 HP" },
55 { "rt712 MIC2", NULL
, "Headset Mic" },
58 static const struct snd_soc_dapm_route rt713_sdca_map
[] = {
59 { "Headphone", NULL
, "rt713 HP" },
60 { "rt713 MIC2", NULL
, "Headset Mic" },
63 static const struct snd_soc_dapm_route rt721_sdca_map
[] = {
64 { "Headphone", NULL
, "rt721 HP" },
65 { "rt721 MIC2", NULL
, "Headset Mic" },
68 static const struct snd_soc_dapm_route rt722_sdca_map
[] = {
69 { "Headphone", NULL
, "rt722 HP" },
70 { "rt722 MIC2", NULL
, "Headset Mic" },
73 static struct snd_soc_jack_pin rt_sdca_jack_pins
[] = {
76 .mask
= SND_JACK_HEADPHONE
,
80 .mask
= SND_JACK_MICROPHONE
,
85 * The sdca suffix is required for rt711 since there are two generations of the same chip.
86 * RT713 is an SDCA device but the sdca suffix is required for backwards-compatibility with
87 * previous UCM definitions.
89 static const char * const need_sdca_suffix
[] = {
93 int asoc_sdw_rt_sdca_jack_rtd_init(struct snd_soc_pcm_runtime
*rtd
, struct snd_soc_dai
*dai
)
95 struct snd_soc_card
*card
= rtd
->card
;
96 struct asoc_sdw_mc_private
*ctx
= snd_soc_card_get_drvdata(card
);
97 struct snd_soc_component
*component
;
98 struct snd_soc_jack
*jack
;
102 component
= dai
->component
;
103 card
->components
= devm_kasprintf(card
->dev
, GFP_KERNEL
,
105 card
->components
, component
->name_prefix
);
106 if (!card
->components
)
109 for (i
= 0; i
< ARRAY_SIZE(need_sdca_suffix
); i
++) {
110 if (strstr(component
->name_prefix
, need_sdca_suffix
[i
])) {
111 /* Add -sdca suffix for existing UCMs */
112 card
->components
= devm_kasprintf(card
->dev
, GFP_KERNEL
,
113 "%s-sdca", card
->components
);
114 if (!card
->components
)
120 if (strstr(component
->name_prefix
, "rt711")) {
121 ret
= snd_soc_dapm_add_routes(&card
->dapm
, rt711_sdca_map
,
122 ARRAY_SIZE(rt711_sdca_map
));
123 } else if (strstr(component
->name_prefix
, "rt712")) {
124 ret
= snd_soc_dapm_add_routes(&card
->dapm
, rt712_sdca_map
,
125 ARRAY_SIZE(rt712_sdca_map
));
126 } else if (strstr(component
->name_prefix
, "rt713")) {
127 ret
= snd_soc_dapm_add_routes(&card
->dapm
, rt713_sdca_map
,
128 ARRAY_SIZE(rt713_sdca_map
));
129 } else if (strstr(component
->name_prefix
, "rt721")) {
130 ret
= snd_soc_dapm_add_routes(&card
->dapm
, rt721_sdca_map
,
131 ARRAY_SIZE(rt721_sdca_map
));
132 } else if (strstr(component
->name_prefix
, "rt722")) {
133 ret
= snd_soc_dapm_add_routes(&card
->dapm
, rt722_sdca_map
,
134 ARRAY_SIZE(rt722_sdca_map
));
136 dev_err(card
->dev
, "%s is not supported\n", component
->name_prefix
);
141 dev_err(card
->dev
, "rt sdca jack map addition failed: %d\n", ret
);
145 ret
= snd_soc_card_jack_new_pins(rtd
->card
, "Headset Jack",
146 SND_JACK_HEADSET
| SND_JACK_BTN_0
|
147 SND_JACK_BTN_1
| SND_JACK_BTN_2
|
151 ARRAY_SIZE(rt_sdca_jack_pins
));
153 dev_err(rtd
->card
->dev
, "Headset Jack creation failed: %d\n",
158 jack
= &ctx
->sdw_headset
;
160 snd_jack_set_key(jack
->jack
, SND_JACK_BTN_0
, KEY_PLAYPAUSE
);
161 snd_jack_set_key(jack
->jack
, SND_JACK_BTN_1
, KEY_VOICECOMMAND
);
162 snd_jack_set_key(jack
->jack
, SND_JACK_BTN_2
, KEY_VOLUMEUP
);
163 snd_jack_set_key(jack
->jack
, SND_JACK_BTN_3
, KEY_VOLUMEDOWN
);
165 ret
= snd_soc_component_set_jack(component
, jack
, NULL
);
168 dev_err(rtd
->card
->dev
, "Headset Jack call-back failed: %d\n",
173 EXPORT_SYMBOL_NS(asoc_sdw_rt_sdca_jack_rtd_init
, "SND_SOC_SDW_UTILS");
175 int asoc_sdw_rt_sdca_jack_exit(struct snd_soc_card
*card
, struct snd_soc_dai_link
*dai_link
)
177 struct asoc_sdw_mc_private
*ctx
= snd_soc_card_get_drvdata(card
);
179 if (!ctx
->headset_codec_dev
)
182 if (!SOC_SDW_JACK_JDSRC(ctx
->mc_quirk
))
185 device_remove_software_node(ctx
->headset_codec_dev
);
186 put_device(ctx
->headset_codec_dev
);
187 ctx
->headset_codec_dev
= NULL
;
191 EXPORT_SYMBOL_NS(asoc_sdw_rt_sdca_jack_exit
, "SND_SOC_SDW_UTILS");
193 int asoc_sdw_rt_sdca_jack_init(struct snd_soc_card
*card
,
194 struct snd_soc_dai_link
*dai_links
,
195 struct asoc_sdw_codec_info
*info
,
198 struct asoc_sdw_mc_private
*ctx
= snd_soc_card_get_drvdata(card
);
199 struct device
*sdw_dev
;
203 * Jack detection should be only initialized once for headsets since
204 * the playback/capture is sharing the same jack
206 if (ctx
->headset_codec_dev
)
209 sdw_dev
= bus_find_device_by_name(&sdw_bus_type
, NULL
, dai_links
->codecs
[0].name
);
211 return -EPROBE_DEFER
;
213 ret
= rt_sdca_jack_add_codec_device_props(sdw_dev
, ctx
->mc_quirk
);
218 ctx
->headset_codec_dev
= sdw_dev
;
222 EXPORT_SYMBOL_NS(asoc_sdw_rt_sdca_jack_init
, "SND_SOC_SDW_UTILS");