1 // SPDX-License-Identifier: GPL-2.0 2 // Copyright (c) 2018, Linaro Limited. 3 // Copyright (c) 2018, The Linux Foundation. All rights reserved. 4 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> 9 #include "common.h" 10 11 #define NAME_SIZE 32 12 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), 24 }; 25 26 static struct device_node *qcom_snd_get_link_node(struct snd_soc_pcm_runtime *rtd) 27 { 28 struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); 29 struct snd_soc_card *card = rtd->card; 30 struct of_phandle_args args; 31 int ret; 32 33 if (!card->dev || !card->dev->of_node) 34 return NULL; 35 36 for_each_available_child_of_node_scoped(card->dev->of_node, np) { 37 struct device_node *cpu_np __free(device_node) = 38 of_get_child_by_name(np, "cpu"); 39 40 if (!cpu_np) 41 continue; 42 43 ret = of_parse_phandle_with_args(cpu_np, "sound-dai", "#sound-dai-cells", 0, 44 &args); 45 if (ret) 46 continue; 47 48 if (args.np == rtd->dai_link->cpus[0].of_node && 49 args.args_count == 1 && args.args[0] == cpu_dai->id) { 50 of_node_put(args.np); 51 return of_node_get(np); 52 } 53 54 of_node_put(args.np); 55 } 56 57 return NULL; 58 } 59 60 static int qcom_snd_parse_tdm_slot(struct device_node *np, 61 struct qcom_snd_tdm_slot_cfg *cfg) 62 { 63 memset(cfg, 0, sizeof(*cfg)); 64 65 return snd_soc_of_parse_tdm_slot(np, &cfg->tx_mask, &cfg->rx_mask, 66 &cfg->slots, &cfg->slot_width); 67 } 68 69 static int qcom_snd_normalize_tdm_slots(struct qcom_snd_tdm_slot_cfg *cpu_cfg, 70 struct qcom_snd_tdm_slot_cfg *codec_cfg) 71 { 72 unsigned int slots; 73 unsigned int slot_width; 74 75 if (cpu_cfg->slots && codec_cfg->slots && cpu_cfg->slots != codec_cfg->slots) 76 return -EINVAL; 77 78 if (cpu_cfg->slot_width && codec_cfg->slot_width && 79 cpu_cfg->slot_width != codec_cfg->slot_width) 80 return -EINVAL; 81 82 slots = cpu_cfg->slots ?: codec_cfg->slots; 83 if (!slots) 84 return 0; 85 86 slot_width = cpu_cfg->slot_width ?: codec_cfg->slot_width; 87 if (!slot_width) 88 return -EINVAL; 89 90 cpu_cfg->slots = slots; 91 codec_cfg->slots = slots; 92 cpu_cfg->slot_width = slot_width; 93 codec_cfg->slot_width = slot_width; 94 95 return 0; 96 } 97 98 static int qcom_snd_parse_dai_tdm_slots(struct snd_soc_pcm_runtime *rtd, 99 struct qcom_snd_tdm_slot_cfg *cpu_cfg, 100 struct qcom_snd_tdm_slot_cfg *codec_cfg) 101 { 102 struct device_node *link_np __free(device_node) = qcom_snd_get_link_node(rtd); 103 int ret; 104 105 if (!link_np) 106 return -EINVAL; 107 108 struct device_node *cpu_np __free(device_node) = 109 of_get_child_by_name(link_np, "cpu"); 110 struct device_node *codec_np __free(device_node) = 111 of_get_child_by_name(link_np, "codec"); 112 if (!cpu_np || !codec_np) 113 return -EINVAL; 114 115 ret = qcom_snd_parse_tdm_slot(cpu_np, cpu_cfg); 116 if (ret) 117 return ret; 118 119 return qcom_snd_parse_tdm_slot(codec_np, codec_cfg); 120 } 121 122 int qcom_snd_get_dai_tdm_slots(struct snd_soc_pcm_runtime *rtd, 123 struct qcom_snd_tdm_slot_cfg *cpu_cfg, 124 struct qcom_snd_tdm_slot_cfg *codec_cfg) 125 { 126 int ret; 127 128 ret = qcom_snd_parse_dai_tdm_slots(rtd, cpu_cfg, codec_cfg); 129 if (ret) 130 return ret; 131 132 return qcom_snd_normalize_tdm_slots(cpu_cfg, codec_cfg); 133 } 134 EXPORT_SYMBOL_GPL(qcom_snd_get_dai_tdm_slots); 135 136 int qcom_snd_apply_dai_tdm_slots_cfg(struct snd_soc_pcm_runtime *rtd, 137 const struct qcom_snd_tdm_slot_cfg *cpu_cfg, 138 const struct qcom_snd_tdm_slot_cfg *codec_cfg) 139 { 140 struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); 141 struct snd_soc_dai *codec_dai; 142 int i; 143 int ret; 144 145 if (!cpu_cfg->slots) 146 return 0; 147 148 ret = snd_soc_dai_set_tdm_slot(cpu_dai, cpu_cfg->tx_mask, cpu_cfg->rx_mask, 149 cpu_cfg->slots, cpu_cfg->slot_width); 150 if (ret) 151 return ret; 152 153 for_each_rtd_codec_dais(rtd, i, codec_dai) { 154 ret = snd_soc_dai_set_tdm_slot(codec_dai, 155 codec_cfg->tx_mask, 156 codec_cfg->rx_mask, 157 codec_cfg->slots, 158 codec_cfg->slot_width); 159 if (ret) 160 return ret; 161 } 162 163 return 0; 164 } 165 EXPORT_SYMBOL_GPL(qcom_snd_apply_dai_tdm_slots_cfg); 166 167 int qcom_snd_apply_dai_tdm_slots(struct snd_soc_pcm_runtime *rtd) 168 { 169 struct qcom_snd_tdm_slot_cfg cpu_cfg; 170 struct qcom_snd_tdm_slot_cfg codec_cfg; 171 int ret; 172 173 ret = qcom_snd_get_dai_tdm_slots(rtd, &cpu_cfg, &codec_cfg); 174 if (ret) 175 return ret == -EINVAL ? 0 : ret; 176 177 return qcom_snd_apply_dai_tdm_slots_cfg(rtd, &cpu_cfg, &codec_cfg); 178 } 179 EXPORT_SYMBOL_GPL(qcom_snd_apply_dai_tdm_slots); 180 181 int qcom_snd_parse_of(struct snd_soc_card *card) 182 { 183 struct device *dev = card->dev; 184 struct snd_soc_dai_link *link; 185 struct of_phandle_args args; 186 struct snd_soc_dai_link_component *dlc; 187 int ret, num_links; 188 189 ret = snd_soc_of_parse_card_name(card, "model"); 190 if (ret == 0 && !card->name) 191 /* Deprecated, only for compatibility with old device trees */ 192 ret = snd_soc_of_parse_card_name(card, "qcom,model"); 193 if (ret) { 194 dev_err(dev, "Error parsing card name: %d\n", ret); 195 return ret; 196 } 197 198 if (of_property_present(dev->of_node, "widgets")) { 199 ret = snd_soc_of_parse_audio_simple_widgets(card, "widgets"); 200 if (ret) 201 return ret; 202 } 203 204 /* DAPM routes */ 205 if (of_property_present(dev->of_node, "audio-routing")) { 206 ret = snd_soc_of_parse_audio_routing(card, "audio-routing"); 207 if (ret) 208 return ret; 209 } 210 /* Deprecated, only for compatibility with old device trees */ 211 if (of_property_present(dev->of_node, "qcom,audio-routing")) { 212 ret = snd_soc_of_parse_audio_routing(card, "qcom,audio-routing"); 213 if (ret) 214 return ret; 215 } 216 217 ret = snd_soc_of_parse_pin_switches(card, "pin-switches"); 218 if (ret) 219 return ret; 220 221 ret = snd_soc_of_parse_aux_devs(card, "aux-devs"); 222 if (ret) 223 return ret; 224 225 /* Populate links */ 226 num_links = of_get_available_child_count(dev->of_node); 227 228 /* Allocate the DAI link array */ 229 card->dai_link = devm_kcalloc(dev, num_links, sizeof(*link), GFP_KERNEL); 230 if (!card->dai_link) 231 return -ENOMEM; 232 233 card->num_links = num_links; 234 link = card->dai_link; 235 236 for_each_available_child_of_node_scoped(dev->of_node, np) { 237 dlc = devm_kcalloc(dev, 2, sizeof(*dlc), GFP_KERNEL); 238 if (!dlc) 239 return -ENOMEM; 240 241 link->cpus = &dlc[0]; 242 link->platforms = &dlc[1]; 243 244 link->num_cpus = 1; 245 link->num_platforms = 1; 246 247 ret = of_property_read_string(np, "link-name", &link->name); 248 if (ret) { 249 dev_err(dev, "error getting codec dai_link name\n"); 250 return ret; 251 } 252 253 struct device_node *cpu __free(device_node) = 254 of_get_child_by_name(np, "cpu"); 255 struct device_node *platform __free(device_node) = 256 of_get_child_by_name(np, "platform"); 257 struct device_node *codec __free(device_node) = 258 of_get_child_by_name(np, "codec"); 259 260 if (!cpu) { 261 dev_err(dev, "%s: Can't find cpu DT node\n", link->name); 262 return -EINVAL; 263 } 264 265 ret = snd_soc_of_get_dlc(cpu, &args, link->cpus, 0); 266 if (ret) { 267 dev_err_probe(dev, ret, 268 "%s: error getting cpu dai name\n", link->name); 269 return ret; 270 } 271 272 link->id = args.args[0]; 273 274 if (link->id >= LPASS_MAX_PORT) { 275 dev_err(dev, "%s: Invalid cpu dai id %d\n", link->name, link->id); 276 return -EINVAL; 277 } 278 279 if (platform) { 280 link->platforms->of_node = of_parse_phandle(platform, 281 "sound-dai", 282 0); 283 if (!link->platforms->of_node) { 284 dev_err(dev, "%s: platform dai not found\n", link->name); 285 return -EINVAL; 286 } 287 } else { 288 link->platforms->of_node = link->cpus->of_node; 289 } 290 291 if (codec) { 292 ret = snd_soc_of_get_dai_link_codecs(dev, codec, link); 293 if (ret < 0) { 294 dev_err_probe(dev, ret, 295 "%s: codec dai not found\n", link->name); 296 return ret; 297 } 298 299 if (platform) { 300 /* DPCM backend */ 301 link->no_pcm = 1; 302 link->ignore_pmdown_time = 1; 303 } 304 } else { 305 /* DPCM frontend */ 306 link->codecs = &snd_soc_dummy_dlc; 307 link->num_codecs = 1; 308 link->dynamic = 1; 309 } 310 311 if (platform || !codec) { 312 /* DPCM */ 313 link->ignore_suspend = 1; 314 link->nonatomic = 1; 315 } 316 317 link->stream_name = link->name; 318 link++; 319 } 320 321 if (!card->dapm_widgets) { 322 card->dapm_widgets = qcom_jack_snd_widgets; 323 card->num_dapm_widgets = ARRAY_SIZE(qcom_jack_snd_widgets); 324 } 325 326 return 0; 327 } 328 EXPORT_SYMBOL_GPL(qcom_snd_parse_of); 329 330 static struct snd_soc_jack_pin qcom_headset_jack_pins[] = { 331 /* Headset */ 332 { 333 .pin = "Mic Jack", 334 .mask = SND_JACK_MICROPHONE, 335 }, 336 { 337 .pin = "Headphone Jack", 338 .mask = SND_JACK_HEADPHONE, 339 }, 340 }; 341 342 int qcom_snd_wcd_jack_setup(struct snd_soc_pcm_runtime *rtd, 343 struct snd_soc_jack *jack, bool *jack_setup) 344 { 345 struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); 346 struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0); 347 struct snd_soc_card *card = rtd->card; 348 int rval, i; 349 350 if (!*jack_setup) { 351 rval = snd_soc_card_jack_new_pins(card, "Headset Jack", 352 SND_JACK_HEADSET | SND_JACK_LINEOUT | 353 SND_JACK_MECHANICAL | 354 SND_JACK_BTN_0 | SND_JACK_BTN_1 | 355 SND_JACK_BTN_2 | SND_JACK_BTN_3 | 356 SND_JACK_BTN_4 | SND_JACK_BTN_5, 357 jack, qcom_headset_jack_pins, 358 ARRAY_SIZE(qcom_headset_jack_pins)); 359 360 if (rval < 0) { 361 dev_err(card->dev, "Unable to add Headphone Jack\n"); 362 return rval; 363 } 364 365 snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_MEDIA); 366 snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOICECOMMAND); 367 snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEUP); 368 snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN); 369 *jack_setup = true; 370 } 371 372 switch (cpu_dai->id) { 373 case LPI_MI2S_RX_0: 374 case TX_CODEC_DMA_TX_0: 375 case TX_CODEC_DMA_TX_1: 376 case TX_CODEC_DMA_TX_2: 377 case TX_CODEC_DMA_TX_3: 378 for_each_rtd_codec_dais(rtd, i, codec_dai) { 379 rval = snd_soc_component_set_jack(codec_dai->component, 380 jack, NULL); 381 if (rval != 0 && rval != -ENOTSUPP) { 382 dev_warn(card->dev, "Failed to set jack: %d\n", rval); 383 return rval; 384 } 385 } 386 387 break; 388 default: 389 break; 390 } 391 392 393 return 0; 394 } 395 EXPORT_SYMBOL_GPL(qcom_snd_wcd_jack_setup); 396 397 int qcom_snd_dp_jack_setup(struct snd_soc_pcm_runtime *rtd, 398 struct snd_soc_jack *dp_jack, int dp_pcm_id) 399 { 400 struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0); 401 struct snd_soc_card *card = rtd->card; 402 char jack_name[NAME_SIZE]; 403 int rval, i; 404 405 snprintf(jack_name, sizeof(jack_name), "DP%d Jack", dp_pcm_id); 406 rval = snd_soc_card_jack_new(card, jack_name, SND_JACK_AVOUT, dp_jack); 407 if (rval) 408 return rval; 409 410 for_each_rtd_codec_dais(rtd, i, codec_dai) { 411 rval = snd_soc_component_set_jack(codec_dai->component, dp_jack, NULL); 412 if (rval != 0 && rval != -ENOTSUPP) { 413 dev_warn(card->dev, "Failed to set jack: %d\n", rval); 414 return rval; 415 } 416 } 417 418 return 0; 419 } 420 EXPORT_SYMBOL_GPL(qcom_snd_dp_jack_setup); 421 422 MODULE_DESCRIPTION("ASoC Qualcomm helper functions"); 423 MODULE_LICENSE("GPL"); 424