soc-link.c 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. // SPDX-License-Identifier: GPL-2.0
  2. //
  3. // soc-link.c
  4. //
  5. // Copyright (C) 2019 Renesas Electronics Corp.
  6. // Kuninori Morimoto <[email protected]>
  7. //
  8. #include <sound/soc.h>
  9. #include <sound/soc-link.h>
  10. #define soc_link_ret(rtd, ret) _soc_link_ret(rtd, __func__, ret)
  11. static inline int _soc_link_ret(struct snd_soc_pcm_runtime *rtd,
  12. const char *func, int ret)
  13. {
  14. /* Positive, Zero values are not errors */
  15. if (ret >= 0)
  16. return ret;
  17. /* Negative values might be errors */
  18. switch (ret) {
  19. case -EPROBE_DEFER:
  20. case -ENOTSUPP:
  21. break;
  22. default:
  23. dev_err(rtd->dev,
  24. "ASoC: error at %s on %s: %d\n",
  25. func, rtd->dai_link->name, ret);
  26. }
  27. return ret;
  28. }
  29. /*
  30. * We might want to check substream by using list.
  31. * In such case, we can update these macros.
  32. */
  33. #define soc_link_mark_push(rtd, substream, tgt) ((rtd)->mark_##tgt = substream)
  34. #define soc_link_mark_pop(rtd, substream, tgt) ((rtd)->mark_##tgt = NULL)
  35. #define soc_link_mark_match(rtd, substream, tgt) ((rtd)->mark_##tgt == substream)
  36. int snd_soc_link_init(struct snd_soc_pcm_runtime *rtd)
  37. {
  38. int ret = 0;
  39. if (rtd->dai_link->init)
  40. ret = rtd->dai_link->init(rtd);
  41. return soc_link_ret(rtd, ret);
  42. }
  43. void snd_soc_link_exit(struct snd_soc_pcm_runtime *rtd)
  44. {
  45. if (rtd->dai_link->exit)
  46. rtd->dai_link->exit(rtd);
  47. }
  48. int snd_soc_link_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
  49. struct snd_pcm_hw_params *params)
  50. {
  51. int ret = 0;
  52. if (rtd->dai_link->be_hw_params_fixup)
  53. ret = rtd->dai_link->be_hw_params_fixup(rtd, params);
  54. return soc_link_ret(rtd, ret);
  55. }
  56. int snd_soc_link_startup(struct snd_pcm_substream *substream)
  57. {
  58. struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
  59. int ret = 0;
  60. if (rtd->dai_link->ops &&
  61. rtd->dai_link->ops->startup)
  62. ret = rtd->dai_link->ops->startup(substream);
  63. /* mark substream if succeeded */
  64. if (ret == 0)
  65. soc_link_mark_push(rtd, substream, startup);
  66. return soc_link_ret(rtd, ret);
  67. }
  68. void snd_soc_link_shutdown(struct snd_pcm_substream *substream,
  69. int rollback)
  70. {
  71. struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
  72. if (rollback && !soc_link_mark_match(rtd, substream, startup))
  73. return;
  74. if (rtd->dai_link->ops &&
  75. rtd->dai_link->ops->shutdown)
  76. rtd->dai_link->ops->shutdown(substream);
  77. /* remove marked substream */
  78. soc_link_mark_pop(rtd, substream, startup);
  79. }
  80. int snd_soc_link_prepare(struct snd_pcm_substream *substream)
  81. {
  82. struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
  83. int ret = 0;
  84. if (rtd->dai_link->ops &&
  85. rtd->dai_link->ops->prepare)
  86. ret = rtd->dai_link->ops->prepare(substream);
  87. return soc_link_ret(rtd, ret);
  88. }
  89. int snd_soc_link_hw_params(struct snd_pcm_substream *substream,
  90. struct snd_pcm_hw_params *params)
  91. {
  92. struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
  93. int ret = 0;
  94. if (rtd->dai_link->ops &&
  95. rtd->dai_link->ops->hw_params)
  96. ret = rtd->dai_link->ops->hw_params(substream, params);
  97. /* mark substream if succeeded */
  98. if (ret == 0)
  99. soc_link_mark_push(rtd, substream, hw_params);
  100. return soc_link_ret(rtd, ret);
  101. }
  102. void snd_soc_link_hw_free(struct snd_pcm_substream *substream, int rollback)
  103. {
  104. struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
  105. if (rollback && !soc_link_mark_match(rtd, substream, hw_params))
  106. return;
  107. if (rtd->dai_link->ops &&
  108. rtd->dai_link->ops->hw_free)
  109. rtd->dai_link->ops->hw_free(substream);
  110. /* remove marked substream */
  111. soc_link_mark_pop(rtd, substream, hw_params);
  112. }
  113. static int soc_link_trigger(struct snd_pcm_substream *substream, int cmd)
  114. {
  115. struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
  116. int ret = 0;
  117. if (rtd->dai_link->ops &&
  118. rtd->dai_link->ops->trigger)
  119. ret = rtd->dai_link->ops->trigger(substream, cmd);
  120. return soc_link_ret(rtd, ret);
  121. }
  122. int snd_soc_link_trigger(struct snd_pcm_substream *substream, int cmd,
  123. int rollback)
  124. {
  125. struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
  126. int ret = 0;
  127. switch (cmd) {
  128. case SNDRV_PCM_TRIGGER_START:
  129. case SNDRV_PCM_TRIGGER_RESUME:
  130. case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
  131. ret = soc_link_trigger(substream, cmd);
  132. if (ret < 0)
  133. break;
  134. soc_link_mark_push(rtd, substream, trigger);
  135. break;
  136. case SNDRV_PCM_TRIGGER_STOP:
  137. case SNDRV_PCM_TRIGGER_SUSPEND:
  138. case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
  139. if (rollback && !soc_link_mark_match(rtd, substream, trigger))
  140. break;
  141. ret = soc_link_trigger(substream, cmd);
  142. soc_link_mark_pop(rtd, substream, startup);
  143. }
  144. return ret;
  145. }
  146. int snd_soc_link_compr_startup(struct snd_compr_stream *cstream)
  147. {
  148. struct snd_soc_pcm_runtime *rtd = cstream->private_data;
  149. int ret = 0;
  150. if (rtd->dai_link->compr_ops &&
  151. rtd->dai_link->compr_ops->startup)
  152. ret = rtd->dai_link->compr_ops->startup(cstream);
  153. if (ret == 0)
  154. soc_link_mark_push(rtd, cstream, compr_startup);
  155. return soc_link_ret(rtd, ret);
  156. }
  157. EXPORT_SYMBOL_GPL(snd_soc_link_compr_startup);
  158. void snd_soc_link_compr_shutdown(struct snd_compr_stream *cstream,
  159. int rollback)
  160. {
  161. struct snd_soc_pcm_runtime *rtd = cstream->private_data;
  162. if (rollback && !soc_link_mark_match(rtd, cstream, compr_startup))
  163. return;
  164. if (rtd->dai_link->compr_ops &&
  165. rtd->dai_link->compr_ops->shutdown)
  166. rtd->dai_link->compr_ops->shutdown(cstream);
  167. soc_link_mark_pop(rtd, cstream, compr_startup);
  168. }
  169. EXPORT_SYMBOL_GPL(snd_soc_link_compr_shutdown);
  170. int snd_soc_link_compr_set_params(struct snd_compr_stream *cstream)
  171. {
  172. struct snd_soc_pcm_runtime *rtd = cstream->private_data;
  173. int ret = 0;
  174. if (rtd->dai_link->compr_ops &&
  175. rtd->dai_link->compr_ops->set_params)
  176. ret = rtd->dai_link->compr_ops->set_params(cstream);
  177. return soc_link_ret(rtd, ret);
  178. }
  179. EXPORT_SYMBOL_GPL(snd_soc_link_compr_set_params);