1 // SPDX-License-Identifier: GPL-2.0-only 2 // Copyright (c) 2020 Intel Corporation 3 4 /* 5 * sof_sdw_rt711_sdca - Helpers to handle RT711-SDCA from generic machine driver 6 */ 7 8 #include <linux/device.h> 9 #include <linux/errno.h> 10 #include <linux/input.h> 11 #include <linux/soundwire/sdw.h> 12 #include <linux/soundwire/sdw_type.h> 13 #include <sound/control.h> 14 #include <sound/soc.h> 15 #include <sound/soc-acpi.h> 16 #include <sound/soc-dapm.h> 17 #include <sound/jack.h> 18 #include "sof_sdw_common.h" 19 20 /* 21 * Note this MUST be called before snd_soc_register_card(), so that the props 22 * are in place before the codec component driver's probe function parses them. 23 */ 24 static int rt_sdca_jack_add_codec_device_props(struct device *sdw_dev) 25 { 26 struct property_entry props[MAX_NO_PROPS] = {}; 27 struct fwnode_handle *fwnode; 28 int ret; 29 30 if (!SOF_JACK_JDSRC(sof_sdw_quirk)) 31 return 0; 32 33 props[0] = PROPERTY_ENTRY_U32("realtek,jd-src", SOF_JACK_JDSRC(sof_sdw_quirk)); 34 35 fwnode = fwnode_create_software_node(props, NULL); 36 if (IS_ERR(fwnode)) 37 return PTR_ERR(fwnode); 38 39 ret = device_add_software_node(sdw_dev, to_software_node(fwnode)); 40 41 fwnode_handle_put(fwnode); 42 43 return ret; 44 } 45 46 static const struct snd_soc_dapm_widget rt_sdca_jack_widgets[] = { 47 SND_SOC_DAPM_HP("Headphone", NULL), 48 SND_SOC_DAPM_MIC("Headset Mic", NULL), 49 }; 50 51 static const struct snd_soc_dapm_route rt711_sdca_map[] = { 52 { "Headphone", NULL, "rt711 HP" }, 53 { "rt711 MIC2", NULL, "Headset Mic" }, 54 }; 55 56 static const struct snd_soc_dapm_route rt712_sdca_map[] = { 57 { "Headphone", NULL, "rt712 HP" }, 58 { "rt712 MIC2", NULL, "Headset Mic" }, 59 }; 60 61 static const struct snd_soc_dapm_route rt713_sdca_map[] = { 62 { "Headphone", NULL, "rt713 HP" }, 63 { "rt713 MIC2", NULL, "Headset Mic" }, 64 }; 65 66 static const struct snd_kcontrol_new rt_sdca_jack_controls[] = { 67 SOC_DAPM_PIN_SWITCH("Headphone"), 68 SOC_DAPM_PIN_SWITCH("Headset Mic"), 69 }; 70 71 static struct snd_soc_jack_pin rt_sdca_jack_pins[] = { 72 { 73 .pin = "Headphone", 74 .mask = SND_JACK_HEADPHONE, 75 }, 76 { 77 .pin = "Headset Mic", 78 .mask = SND_JACK_MICROPHONE, 79 }, 80 }; 81 82 static int rt_sdca_jack_rtd_init(struct snd_soc_pcm_runtime *rtd) 83 { 84 struct snd_soc_card *card = rtd->card; 85 struct mc_private *ctx = snd_soc_card_get_drvdata(card); 86 struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0); 87 struct snd_soc_component *component = codec_dai->component; 88 struct snd_soc_jack *jack; 89 int ret; 90 91 card->components = devm_kasprintf(card->dev, GFP_KERNEL, 92 "%s hs:%s-sdca", 93 card->components, component->name_prefix); 94 if (!card->components) 95 return -ENOMEM; 96 97 ret = snd_soc_add_card_controls(card, rt_sdca_jack_controls, 98 ARRAY_SIZE(rt_sdca_jack_controls)); 99 if (ret) { 100 dev_err(card->dev, "rt sdca jack controls addition failed: %d\n", ret); 101 return ret; 102 } 103 104 ret = snd_soc_dapm_new_controls(&card->dapm, rt_sdca_jack_widgets, 105 ARRAY_SIZE(rt_sdca_jack_widgets)); 106 if (ret) { 107 dev_err(card->dev, "rt sdca jack widgets addition failed: %d\n", ret); 108 return ret; 109 } 110 111 if (strstr(component->name_prefix, "rt711")) { 112 ret = snd_soc_dapm_add_routes(&card->dapm, rt711_sdca_map, 113 ARRAY_SIZE(rt711_sdca_map)); 114 } else if (strstr(component->name_prefix, "rt712")) { 115 ret = snd_soc_dapm_add_routes(&card->dapm, rt712_sdca_map, 116 ARRAY_SIZE(rt712_sdca_map)); 117 } else if (strstr(component->name_prefix, "rt713")) { 118 ret = snd_soc_dapm_add_routes(&card->dapm, rt713_sdca_map, 119 ARRAY_SIZE(rt713_sdca_map)); 120 } else { 121 dev_err(card->dev, "%s is not supported\n", component->name_prefix); 122 return -EINVAL; 123 } 124 125 if (ret) { 126 dev_err(card->dev, "rt sdca jack map addition failed: %d\n", ret); 127 return ret; 128 } 129 130 ret = snd_soc_card_jack_new_pins(rtd->card, "Headset Jack", 131 SND_JACK_HEADSET | SND_JACK_BTN_0 | 132 SND_JACK_BTN_1 | SND_JACK_BTN_2 | 133 SND_JACK_BTN_3, 134 &ctx->sdw_headset, 135 rt_sdca_jack_pins, 136 ARRAY_SIZE(rt_sdca_jack_pins)); 137 if (ret) { 138 dev_err(rtd->card->dev, "Headset Jack creation failed: %d\n", 139 ret); 140 return ret; 141 } 142 143 jack = &ctx->sdw_headset; 144 145 snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); 146 snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOICECOMMAND); 147 snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEUP); 148 snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN); 149 150 ret = snd_soc_component_set_jack(component, jack, NULL); 151 152 if (ret) 153 dev_err(rtd->card->dev, "Headset Jack call-back failed: %d\n", 154 ret); 155 156 return ret; 157 } 158 159 int sof_sdw_rt_sdca_jack_exit(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link) 160 { 161 struct mc_private *ctx = snd_soc_card_get_drvdata(card); 162 163 if (!ctx->headset_codec_dev) 164 return 0; 165 166 if (!SOF_JACK_JDSRC(sof_sdw_quirk)) 167 return 0; 168 169 device_remove_software_node(ctx->headset_codec_dev); 170 put_device(ctx->headset_codec_dev); 171 172 return 0; 173 } 174 175 int sof_sdw_rt_sdca_jack_init(struct snd_soc_card *card, 176 const struct snd_soc_acpi_link_adr *link, 177 struct snd_soc_dai_link *dai_links, 178 struct sof_sdw_codec_info *info, 179 bool playback) 180 { 181 struct mc_private *ctx = snd_soc_card_get_drvdata(card); 182 struct device *sdw_dev; 183 int ret; 184 185 /* 186 * headset should be initialized once. 187 * Do it with dai link for playback. 188 */ 189 if (!playback) 190 return 0; 191 192 sdw_dev = bus_find_device_by_name(&sdw_bus_type, NULL, dai_links->codecs[0].name); 193 if (!sdw_dev) 194 return -EPROBE_DEFER; 195 196 ret = rt_sdca_jack_add_codec_device_props(sdw_dev); 197 if (ret < 0) { 198 put_device(sdw_dev); 199 return ret; 200 } 201 ctx->headset_codec_dev = sdw_dev; 202 203 dai_links->init = rt_sdca_jack_rtd_init; 204 205 return 0; 206 } 207