soc_sdw_rt711.c 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  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. * soc_sdw_rt711 - Helpers to handle RT711 from generic machine driver
  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 <sound/soc_sdw_utils.h>
  19. /*
  20. * Note this MUST be called before snd_soc_register_card(), so that the props
  21. * are in place before the codec component driver's probe function parses them.
  22. */
  23. static int rt711_add_codec_device_props(struct device *sdw_dev, unsigned long quirk)
  24. {
  25. struct property_entry props[SOC_SDW_MAX_NO_PROPS] = {};
  26. struct fwnode_handle *fwnode;
  27. int ret;
  28. if (!SOC_SDW_JACK_JDSRC(quirk))
  29. return 0;
  30. props[0] = PROPERTY_ENTRY_U32("realtek,jd-src", SOC_SDW_JACK_JDSRC(quirk));
  31. fwnode = fwnode_create_software_node(props, NULL);
  32. if (IS_ERR(fwnode))
  33. return PTR_ERR(fwnode);
  34. ret = device_add_software_node(sdw_dev, to_software_node(fwnode));
  35. fwnode_handle_put(fwnode);
  36. return ret;
  37. }
  38. static const struct snd_soc_dapm_route rt711_map[] = {
  39. /* Headphones */
  40. { "Headphone", NULL, "rt711 HP" },
  41. { "rt711 MIC2", NULL, "Headset Mic" },
  42. };
  43. static struct snd_soc_jack_pin rt711_jack_pins[] = {
  44. {
  45. .pin = "Headphone",
  46. .mask = SND_JACK_HEADPHONE,
  47. },
  48. {
  49. .pin = "Headset Mic",
  50. .mask = SND_JACK_MICROPHONE,
  51. },
  52. };
  53. int asoc_sdw_rt711_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai)
  54. {
  55. struct snd_soc_card *card = rtd->card;
  56. struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card);
  57. struct snd_soc_component *component;
  58. struct snd_soc_jack *jack;
  59. int ret;
  60. component = dai->component;
  61. card->components = devm_kasprintf(card->dev, GFP_KERNEL,
  62. "%s hs:rt711",
  63. card->components);
  64. if (!card->components)
  65. return -ENOMEM;
  66. ret = snd_soc_dapm_add_routes(&card->dapm, rt711_map,
  67. ARRAY_SIZE(rt711_map));
  68. if (ret) {
  69. dev_err(card->dev, "rt711 map addition failed: %d\n", ret);
  70. return ret;
  71. }
  72. ret = snd_soc_card_jack_new_pins(rtd->card, "Headset Jack",
  73. SND_JACK_HEADSET | SND_JACK_BTN_0 |
  74. SND_JACK_BTN_1 | SND_JACK_BTN_2 |
  75. SND_JACK_BTN_3,
  76. &ctx->sdw_headset,
  77. rt711_jack_pins,
  78. ARRAY_SIZE(rt711_jack_pins));
  79. if (ret) {
  80. dev_err(rtd->card->dev, "Headset Jack creation failed: %d\n",
  81. ret);
  82. return ret;
  83. }
  84. jack = &ctx->sdw_headset;
  85. snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
  86. snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOICECOMMAND);
  87. snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEUP);
  88. snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN);
  89. ret = snd_soc_component_set_jack(component, jack, NULL);
  90. if (ret)
  91. dev_err(rtd->card->dev, "Headset Jack call-back failed: %d\n",
  92. ret);
  93. return ret;
  94. }
  95. EXPORT_SYMBOL_NS(asoc_sdw_rt711_rtd_init, SND_SOC_SDW_UTILS);
  96. int asoc_sdw_rt711_exit(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link)
  97. {
  98. struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card);
  99. if (!ctx->headset_codec_dev)
  100. return 0;
  101. device_remove_software_node(ctx->headset_codec_dev);
  102. put_device(ctx->headset_codec_dev);
  103. return 0;
  104. }
  105. EXPORT_SYMBOL_NS(asoc_sdw_rt711_exit, SND_SOC_SDW_UTILS);
  106. int asoc_sdw_rt711_init(struct snd_soc_card *card,
  107. struct snd_soc_dai_link *dai_links,
  108. struct asoc_sdw_codec_info *info,
  109. bool playback)
  110. {
  111. struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card);
  112. struct device *sdw_dev;
  113. int ret;
  114. /*
  115. * headset should be initialized once.
  116. * Do it with dai link for playback.
  117. */
  118. if (!playback)
  119. return 0;
  120. sdw_dev = bus_find_device_by_name(&sdw_bus_type, NULL, dai_links->codecs[0].name);
  121. if (!sdw_dev)
  122. return -EPROBE_DEFER;
  123. ret = rt711_add_codec_device_props(sdw_dev, ctx->mc_quirk);
  124. if (ret < 0) {
  125. put_device(sdw_dev);
  126. return ret;
  127. }
  128. ctx->headset_codec_dev = sdw_dev;
  129. return 0;
  130. }
  131. EXPORT_SYMBOL_NS(asoc_sdw_rt711_init, SND_SOC_SDW_UTILS);