sdw.c 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. // SPDX-License-Identifier: GPL-2.0
  2. // Copyright (c) 2018-2023, Linaro Limited.
  3. // Copyright (c) 2018, The Linux Foundation. All rights reserved.
  4. #include <dt-bindings/sound/qcom,q6afe.h>
  5. #include <linux/module.h>
  6. #include <sound/soc.h>
  7. #include "sdw.h"
  8. /**
  9. * qcom_snd_sdw_startup() - Helper to start Soundwire stream for SoC audio card
  10. * @substream: The PCM substream from audio, as passed to snd_soc_ops->startup()
  11. *
  12. * Helper for the SoC audio card (snd_soc_ops->startup()) to allocate and set
  13. * Soundwire stream runtime to each codec DAI.
  14. *
  15. * The shutdown() callback should call sdw_release_stream() on the same
  16. * sdw_stream_runtime.
  17. *
  18. * Return: 0 or errno
  19. */
  20. int qcom_snd_sdw_startup(struct snd_pcm_substream *substream)
  21. {
  22. struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
  23. struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
  24. struct sdw_stream_runtime *sruntime;
  25. struct snd_soc_dai *codec_dai;
  26. int ret, i;
  27. sruntime = sdw_alloc_stream(cpu_dai->name);
  28. if (!sruntime)
  29. return -ENOMEM;
  30. for_each_rtd_codec_dais(rtd, i, codec_dai) {
  31. ret = snd_soc_dai_set_stream(codec_dai, sruntime,
  32. substream->stream);
  33. if (ret < 0 && ret != -ENOTSUPP) {
  34. dev_err(rtd->dev, "Failed to set sdw stream on %s\n",
  35. codec_dai->name);
  36. goto err_set_stream;
  37. }
  38. }
  39. return 0;
  40. err_set_stream:
  41. sdw_release_stream(sruntime);
  42. return ret;
  43. }
  44. EXPORT_SYMBOL_GPL(qcom_snd_sdw_startup);
  45. int qcom_snd_sdw_prepare(struct snd_pcm_substream *substream,
  46. struct sdw_stream_runtime *sruntime,
  47. bool *stream_prepared)
  48. {
  49. struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
  50. struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
  51. int ret;
  52. if (!sruntime)
  53. return 0;
  54. switch (cpu_dai->id) {
  55. case WSA_CODEC_DMA_RX_0:
  56. case WSA_CODEC_DMA_RX_1:
  57. case RX_CODEC_DMA_RX_0:
  58. case RX_CODEC_DMA_RX_1:
  59. case TX_CODEC_DMA_TX_0:
  60. case TX_CODEC_DMA_TX_1:
  61. case TX_CODEC_DMA_TX_2:
  62. case TX_CODEC_DMA_TX_3:
  63. break;
  64. default:
  65. return 0;
  66. }
  67. if (*stream_prepared)
  68. return 0;
  69. ret = sdw_prepare_stream(sruntime);
  70. if (ret)
  71. return ret;
  72. /**
  73. * NOTE: there is a strict hw requirement about the ordering of port
  74. * enables and actual WSA881x PA enable. PA enable should only happen
  75. * after soundwire ports are enabled if not DC on the line is
  76. * accumulated resulting in Click/Pop Noise
  77. * PA enable/mute are handled as part of codec DAPM and digital mute.
  78. */
  79. ret = sdw_enable_stream(sruntime);
  80. if (ret) {
  81. sdw_deprepare_stream(sruntime);
  82. return ret;
  83. }
  84. *stream_prepared = true;
  85. return ret;
  86. }
  87. EXPORT_SYMBOL_GPL(qcom_snd_sdw_prepare);
  88. int qcom_snd_sdw_hw_params(struct snd_pcm_substream *substream,
  89. struct snd_pcm_hw_params *params,
  90. struct sdw_stream_runtime **psruntime)
  91. {
  92. struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
  93. struct snd_soc_dai *codec_dai;
  94. struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
  95. struct sdw_stream_runtime *sruntime;
  96. int i;
  97. switch (cpu_dai->id) {
  98. case WSA_CODEC_DMA_RX_0:
  99. case RX_CODEC_DMA_RX_0:
  100. case RX_CODEC_DMA_RX_1:
  101. case TX_CODEC_DMA_TX_0:
  102. case TX_CODEC_DMA_TX_1:
  103. case TX_CODEC_DMA_TX_2:
  104. case TX_CODEC_DMA_TX_3:
  105. for_each_rtd_codec_dais(rtd, i, codec_dai) {
  106. sruntime = snd_soc_dai_get_stream(codec_dai, substream->stream);
  107. if (sruntime != ERR_PTR(-ENOTSUPP))
  108. *psruntime = sruntime;
  109. }
  110. break;
  111. }
  112. return 0;
  113. }
  114. EXPORT_SYMBOL_GPL(qcom_snd_sdw_hw_params);
  115. int qcom_snd_sdw_hw_free(struct snd_pcm_substream *substream,
  116. struct sdw_stream_runtime *sruntime, bool *stream_prepared)
  117. {
  118. struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
  119. struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
  120. switch (cpu_dai->id) {
  121. case WSA_CODEC_DMA_RX_0:
  122. case WSA_CODEC_DMA_RX_1:
  123. case RX_CODEC_DMA_RX_0:
  124. case RX_CODEC_DMA_RX_1:
  125. case TX_CODEC_DMA_TX_0:
  126. case TX_CODEC_DMA_TX_1:
  127. case TX_CODEC_DMA_TX_2:
  128. case TX_CODEC_DMA_TX_3:
  129. if (sruntime && *stream_prepared) {
  130. sdw_disable_stream(sruntime);
  131. sdw_deprepare_stream(sruntime);
  132. *stream_prepared = false;
  133. }
  134. break;
  135. default:
  136. break;
  137. }
  138. return 0;
  139. }
  140. EXPORT_SYMBOL_GPL(qcom_snd_sdw_hw_free);
  141. MODULE_DESCRIPTION("Qualcomm ASoC SoundWire helper functions");
  142. MODULE_LICENSE("GPL");