meson-codec-glue.c 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  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;
  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. snd_soc_dai_dma_data_set_playback(dai, data);
  34. }
  35. struct meson_codec_glue_input *
  36. meson_codec_glue_input_get_data(struct snd_soc_dai *dai)
  37. {
  38. return snd_soc_dai_dma_data_get_playback(dai);
  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 = snd_soc_substream_to_rtd(substream);
  82. struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget_capture(dai);
  83. struct meson_codec_glue_input *in_data = meson_codec_glue_output_get_input_data(w);
  84. if (!in_data)
  85. return -ENODEV;
  86. if (WARN_ON(!rtd->dai_link->c2c_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->c2c_params = &in_data->params;
  92. rtd->dai_link->num_c2c_params = 1;
  93. return snd_soc_runtime_set_dai_fmt(rtd, in_data->fmt);
  94. }
  95. EXPORT_SYMBOL_GPL(meson_codec_glue_output_startup);
  96. int meson_codec_glue_input_dai_probe(struct snd_soc_dai *dai)
  97. {
  98. struct meson_codec_glue_input *data;
  99. data = kzalloc(sizeof(*data), GFP_KERNEL);
  100. if (!data)
  101. return -ENOMEM;
  102. meson_codec_glue_input_set_data(dai, data);
  103. return 0;
  104. }
  105. EXPORT_SYMBOL_GPL(meson_codec_glue_input_dai_probe);
  106. int meson_codec_glue_input_dai_remove(struct snd_soc_dai *dai)
  107. {
  108. struct meson_codec_glue_input *data =
  109. meson_codec_glue_input_get_data(dai);
  110. kfree(data);
  111. return 0;
  112. }
  113. EXPORT_SYMBOL_GPL(meson_codec_glue_input_dai_remove);
  114. MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>");
  115. MODULE_DESCRIPTION("Amlogic Codec Glue Helpers");
  116. MODULE_LICENSE("GPL v2");