meson-codec-glue.c 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. // SPDX-License-Identifier: GPL-2.0
  2. //
  3. // Copyright (c) 2019 BayLibre, SAS.
  4. // Author: Jerome Brunet <jbrunet@baylibre.com>
  5. #include <linux/module.h>
  6. #include <sound/pcm_params.h>
  7. #include <sound/soc.h>
  8. #include <sound/soc-dai.h>
  9. #include "meson-codec-glue.h"
  10. static struct snd_soc_dapm_widget *
  11. meson_codec_glue_get_input(struct snd_soc_dapm_widget *w)
  12. {
  13. struct snd_soc_dapm_path *p = NULL;
  14. struct snd_soc_dapm_widget *in;
  15. snd_soc_dapm_widget_for_each_source_path(w, p) {
  16. if (!p->connect)
  17. continue;
  18. /* Check that we still are in the same component */
  19. if (snd_soc_dapm_to_component(w->dapm) !=
  20. snd_soc_dapm_to_component(p->source->dapm))
  21. continue;
  22. if (p->source->id == snd_soc_dapm_dai_in)
  23. return p->source;
  24. in = meson_codec_glue_get_input(p->source);
  25. if (in)
  26. return in;
  27. }
  28. return NULL;
  29. }
  30. static void meson_codec_glue_input_set_data(struct snd_soc_dai *dai,
  31. struct meson_codec_glue_input *data)
  32. {
  33. dai->playback_dma_data = data;
  34. }
  35. struct meson_codec_glue_input *
  36. meson_codec_glue_input_get_data(struct snd_soc_dai *dai)
  37. {
  38. return dai->playback_dma_data;
  39. }
  40. EXPORT_SYMBOL_GPL(meson_codec_glue_input_get_data);
  41. static struct meson_codec_glue_input *
  42. meson_codec_glue_output_get_input_data(struct snd_soc_dapm_widget *w)
  43. {
  44. struct snd_soc_dapm_widget *in =
  45. meson_codec_glue_get_input(w);
  46. struct snd_soc_dai *dai;
  47. if (WARN_ON(!in))
  48. return NULL;
  49. dai = in->priv;
  50. return meson_codec_glue_input_get_data(dai);
  51. }
  52. int meson_codec_glue_input_hw_params(struct snd_pcm_substream *substream,
  53. struct snd_pcm_hw_params *params,
  54. struct snd_soc_dai *dai)
  55. {
  56. struct meson_codec_glue_input *data =
  57. meson_codec_glue_input_get_data(dai);
  58. data->params.rates = snd_pcm_rate_to_rate_bit(params_rate(params));
  59. data->params.rate_min = params_rate(params);
  60. data->params.rate_max = params_rate(params);
  61. data->params.formats = 1ULL << (__force int) params_format(params);
  62. data->params.channels_min = params_channels(params);
  63. data->params.channels_max = params_channels(params);
  64. data->params.sig_bits = dai->driver->playback.sig_bits;
  65. return 0;
  66. }
  67. EXPORT_SYMBOL_GPL(meson_codec_glue_input_hw_params);
  68. int meson_codec_glue_input_set_fmt(struct snd_soc_dai *dai,
  69. unsigned int fmt)
  70. {
  71. struct meson_codec_glue_input *data =
  72. meson_codec_glue_input_get_data(dai);
  73. /* Save the source stream format for the downstream link */
  74. data->fmt = fmt;
  75. return 0;
  76. }
  77. EXPORT_SYMBOL_GPL(meson_codec_glue_input_set_fmt);
  78. int meson_codec_glue_output_startup(struct snd_pcm_substream *substream,
  79. struct snd_soc_dai *dai)
  80. {
  81. struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
  82. struct meson_codec_glue_input *in_data =
  83. meson_codec_glue_output_get_input_data(dai->capture_widget);
  84. if (!in_data)
  85. return -ENODEV;
  86. if (WARN_ON(!rtd->dai_link->params)) {
  87. dev_warn(dai->dev, "codec2codec link expected\n");
  88. return -EINVAL;
  89. }
  90. /* Replace link params with the input params */
  91. rtd->dai_link->params = &in_data->params;
  92. if (!in_data->fmt)
  93. return 0;
  94. return snd_soc_runtime_set_dai_fmt(rtd, in_data->fmt);
  95. }
  96. EXPORT_SYMBOL_GPL(meson_codec_glue_output_startup);
  97. int meson_codec_glue_input_dai_probe(struct snd_soc_dai *dai)
  98. {
  99. struct meson_codec_glue_input *data;
  100. data = kzalloc(sizeof(*data), GFP_KERNEL);
  101. if (!data)
  102. return -ENOMEM;
  103. meson_codec_glue_input_set_data(dai, data);
  104. return 0;
  105. }
  106. EXPORT_SYMBOL_GPL(meson_codec_glue_input_dai_probe);
  107. int meson_codec_glue_input_dai_remove(struct snd_soc_dai *dai)
  108. {
  109. struct meson_codec_glue_input *data =
  110. meson_codec_glue_input_get_data(dai);
  111. kfree(data);
  112. return 0;
  113. }
  114. EXPORT_SYMBOL_GPL(meson_codec_glue_input_dai_remove);
  115. MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>");
  116. MODULE_DESCRIPTION("Amlogic Codec Glue Helpers");
  117. MODULE_LICENSE("GPL v2");