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. 5 6 /* 7 * soc_sdw_rt711_sdca - Helpers to handle RT711-SDCA from generic machine driver 8 */ 9 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> 21 22 /* 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. 25 */ 26 static int rt_sdca_jack_add_codec_device_props(struct device *sdw_dev, unsigned long quirk) 27 { 28 struct property_entry props[SOC_SDW_MAX_NO_PROPS] = {}; 29 struct fwnode_handle *fwnode; 30 int ret; 31 32 if (!SOC_SDW_JACK_JDSRC(quirk)) 33 return 0; 34 35 props[0] = PROPERTY_ENTRY_U32("realtek,jd-src", SOC_SDW_JACK_JDSRC(quirk)); 36 37 fwnode = fwnode_create_software_node(props, NULL); 38 if (IS_ERR(fwnode)) 39 return PTR_ERR(fwnode); 40 41 ret = device_add_software_node(sdw_dev, to_software_node(fwnode)); 42 43 fwnode_handle_put(fwnode); 44 45 return ret; 46 } 47 48 static const struct snd_soc_dapm_route rt711_sdca_map[] = { 49 { "Headphone", NULL, "rt711 HP" }, 50 { "rt711 MIC2", NULL, "Headset Mic" }, 51 }; 52 53 static const struct snd_soc_dapm_route rt712_sdca_map[] = { 54 { "Headphone", NULL, "rt712 HP" }, 55 { "rt712 MIC2", NULL, "Headset Mic" }, 56 }; 57 58 static const struct snd_soc_dapm_route rt713_sdca_map[] = { 59 { "Headphone", NULL, "rt713 HP" }, 60 { "rt713 MIC2", NULL, "Headset Mic" }, 61 }; 62 63 static const struct snd_soc_dapm_route rt721_sdca_map[] = { 64 { "Headphone", NULL, "rt721 HP" }, 65 { "rt721 MIC2", NULL, "Headset Mic" }, 66 }; 67 68 static const struct snd_soc_dapm_route rt722_sdca_map[] = { 69 { "Headphone", NULL, "rt722 HP" }, 70 { "rt722 MIC2", NULL, "Headset Mic" }, 71 }; 72 73 static struct snd_soc_jack_pin rt_sdca_jack_pins[] = { 74 { 75 .pin = "Headphone", 76 .mask = SND_JACK_HEADPHONE, 77 }, 78 { 79 .pin = "Headset Mic", 80 .mask = SND_JACK_MICROPHONE, 81 }, 82 }; 83 84 /* 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. 88 */ 89 static const char * const need_sdca_suffix[] = { 90 "rt711", "rt713" 91 }; 92 93 int asoc_sdw_rt_sdca_jack_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai) 94 { 95 struct snd_soc_card *card = rtd->card; 96 struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(card); 97 struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card); 98 struct snd_soc_component *component; 99 struct snd_soc_jack *jack; 100 int ret; 101 int i; 102 103 component = dai->component; 104 card->components = devm_kasprintf(card->dev, GFP_KERNEL, 105 "%s hs:%s", 106 card->components, component->name_prefix); 107 if (!card->components) 108 return -ENOMEM; 109 110 for (i = 0; i < ARRAY_SIZE(need_sdca_suffix); i++) { 111 if (strstr(component->name_prefix, need_sdca_suffix[i])) { 112 /* Add -sdca suffix for existing UCMs */ 113 card->components = devm_kasprintf(card->dev, GFP_KERNEL, 114 "%s-sdca", card->components); 115 if (!card->components) 116 return -ENOMEM; 117 break; 118 } 119 } 120 121 if (strstr(component->name_prefix, "rt711")) { 122 ret = snd_soc_dapm_add_routes(dapm, rt711_sdca_map, 123 ARRAY_SIZE(rt711_sdca_map)); 124 } else if (strstr(component->name_prefix, "rt712")) { 125 ret = snd_soc_dapm_add_routes(dapm, rt712_sdca_map, 126 ARRAY_SIZE(rt712_sdca_map)); 127 } else if (strstr(component->name_prefix, "rt713")) { 128 ret = snd_soc_dapm_add_routes(dapm, rt713_sdca_map, 129 ARRAY_SIZE(rt713_sdca_map)); 130 } else if (strstr(component->name_prefix, "rt721")) { 131 ret = snd_soc_dapm_add_routes(dapm, rt721_sdca_map, 132 ARRAY_SIZE(rt721_sdca_map)); 133 } else if (strstr(component->name_prefix, "rt722")) { 134 ret = snd_soc_dapm_add_routes(dapm, rt722_sdca_map, 135 ARRAY_SIZE(rt722_sdca_map)); 136 } else { 137 dev_err(card->dev, "%s is not supported\n", component->name_prefix); 138 return -EINVAL; 139 } 140 141 if (ret) { 142 dev_err(card->dev, "rt sdca jack map addition failed: %d\n", ret); 143 return ret; 144 } 145 146 ret = snd_soc_card_jack_new_pins(rtd->card, "Headset Jack", 147 SND_JACK_HEADSET | SND_JACK_BTN_0 | 148 SND_JACK_BTN_1 | SND_JACK_BTN_2 | 149 SND_JACK_BTN_3, 150 &ctx->sdw_headset, 151 rt_sdca_jack_pins, 152 ARRAY_SIZE(rt_sdca_jack_pins)); 153 if (ret) { 154 dev_err(rtd->card->dev, "Headset Jack creation failed: %d\n", 155 ret); 156 return ret; 157 } 158 159 jack = &ctx->sdw_headset; 160 161 snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); 162 snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOICECOMMAND); 163 snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEUP); 164 snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN); 165 166 ret = snd_soc_component_set_jack(component, jack, NULL); 167 168 if (ret) 169 dev_err(rtd->card->dev, "Headset Jack call-back failed: %d\n", 170 ret); 171 172 return ret; 173 } 174 EXPORT_SYMBOL_NS(asoc_sdw_rt_sdca_jack_rtd_init, "SND_SOC_SDW_UTILS"); 175 176 int asoc_sdw_rt_sdca_jack_exit(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link) 177 { 178 struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card); 179 180 if (!ctx->headset_codec_dev) 181 return 0; 182 183 if (!SOC_SDW_JACK_JDSRC(ctx->mc_quirk)) 184 return 0; 185 186 device_remove_software_node(ctx->headset_codec_dev); 187 put_device(ctx->headset_codec_dev); 188 ctx->headset_codec_dev = NULL; 189 190 return 0; 191 } 192 EXPORT_SYMBOL_NS(asoc_sdw_rt_sdca_jack_exit, "SND_SOC_SDW_UTILS"); 193 194 int asoc_sdw_rt_sdca_jack_init(struct snd_soc_card *card, 195 struct snd_soc_dai_link *dai_links, 196 struct asoc_sdw_codec_info *info, 197 bool playback) 198 { 199 struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card); 200 struct device *sdw_dev; 201 int ret; 202 203 /* 204 * Jack detection should be only initialized once for headsets since 205 * the playback/capture is sharing the same jack 206 */ 207 if (ctx->headset_codec_dev) 208 return 0; 209 210 sdw_dev = bus_find_device_by_name(&sdw_bus_type, NULL, dai_links->codecs[0].name); 211 if (!sdw_dev) 212 return -EPROBE_DEFER; 213 214 ret = rt_sdca_jack_add_codec_device_props(sdw_dev, ctx->mc_quirk); 215 if (ret < 0) { 216 put_device(sdw_dev); 217 return ret; 218 } 219 ctx->headset_codec_dev = sdw_dev; 220 221 return 0; 222 } 223 EXPORT_SYMBOL_NS(asoc_sdw_rt_sdca_jack_init, "SND_SOC_SDW_UTILS"); 224