mtk-afe-platform-driver.c 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * mtk-afe-platform-driver.c -- Mediatek afe platform driver
  4. *
  5. * Copyright (c) 2016 MediaTek Inc.
  6. * Author: Garlic Tseng <garlic.tseng@mediatek.com>
  7. */
  8. #include <linux/module.h>
  9. #include <linux/dma-mapping.h>
  10. #include <sound/soc.h>
  11. #include "mtk-afe-platform-driver.h"
  12. #include "mtk-base-afe.h"
  13. int mtk_afe_combine_sub_dai(struct mtk_base_afe *afe)
  14. {
  15. struct mtk_base_afe_dai *dai;
  16. size_t num_dai_drivers = 0, dai_idx = 0;
  17. /* calcualte total dai driver size */
  18. list_for_each_entry(dai, &afe->sub_dais, list) {
  19. num_dai_drivers += dai->num_dai_drivers;
  20. }
  21. dev_info(afe->dev, "%s(), num of dai %zd\n", __func__, num_dai_drivers);
  22. /* combine sub_dais */
  23. afe->num_dai_drivers = num_dai_drivers;
  24. afe->dai_drivers = devm_kcalloc(afe->dev,
  25. num_dai_drivers,
  26. sizeof(struct snd_soc_dai_driver),
  27. GFP_KERNEL);
  28. if (!afe->dai_drivers)
  29. return -ENOMEM;
  30. list_for_each_entry(dai, &afe->sub_dais, list) {
  31. /* dai driver */
  32. memcpy(&afe->dai_drivers[dai_idx],
  33. dai->dai_drivers,
  34. dai->num_dai_drivers *
  35. sizeof(struct snd_soc_dai_driver));
  36. dai_idx += dai->num_dai_drivers;
  37. }
  38. return 0;
  39. }
  40. EXPORT_SYMBOL_GPL(mtk_afe_combine_sub_dai);
  41. int mtk_afe_add_sub_dai_control(struct snd_soc_component *component)
  42. {
  43. struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
  44. struct mtk_base_afe_dai *dai;
  45. list_for_each_entry(dai, &afe->sub_dais, list) {
  46. if (dai->controls)
  47. snd_soc_add_component_controls(component,
  48. dai->controls,
  49. dai->num_controls);
  50. if (dai->dapm_widgets)
  51. snd_soc_dapm_new_controls(&component->dapm,
  52. dai->dapm_widgets,
  53. dai->num_dapm_widgets);
  54. }
  55. /* add routes after all widgets are added */
  56. list_for_each_entry(dai, &afe->sub_dais, list) {
  57. if (dai->dapm_routes)
  58. snd_soc_dapm_add_routes(&component->dapm,
  59. dai->dapm_routes,
  60. dai->num_dapm_routes);
  61. }
  62. snd_soc_dapm_new_widgets(component->dapm.card);
  63. return 0;
  64. }
  65. EXPORT_SYMBOL_GPL(mtk_afe_add_sub_dai_control);
  66. static snd_pcm_uframes_t mtk_afe_pcm_pointer
  67. (struct snd_pcm_substream *substream)
  68. {
  69. struct snd_soc_pcm_runtime *rtd = substream->private_data;
  70. struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME);
  71. struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
  72. struct mtk_base_afe_memif *memif = &afe->memif[rtd->cpu_dai->id];
  73. const struct mtk_base_memif_data *memif_data = memif->data;
  74. struct regmap *regmap = afe->regmap;
  75. struct device *dev = afe->dev;
  76. int reg_ofs_base = memif_data->reg_ofs_base;
  77. int reg_ofs_cur = memif_data->reg_ofs_cur;
  78. unsigned int hw_ptr = 0, hw_base = 0;
  79. int ret, pcm_ptr_bytes;
  80. ret = regmap_read(regmap, reg_ofs_cur, &hw_ptr);
  81. if (ret || hw_ptr == 0) {
  82. dev_err(dev, "%s hw_ptr err\n", __func__);
  83. pcm_ptr_bytes = 0;
  84. goto POINTER_RETURN_FRAMES;
  85. }
  86. ret = regmap_read(regmap, reg_ofs_base, &hw_base);
  87. if (ret || hw_base == 0) {
  88. dev_err(dev, "%s hw_ptr err\n", __func__);
  89. pcm_ptr_bytes = 0;
  90. goto POINTER_RETURN_FRAMES;
  91. }
  92. pcm_ptr_bytes = hw_ptr - hw_base;
  93. POINTER_RETURN_FRAMES:
  94. return bytes_to_frames(substream->runtime, pcm_ptr_bytes);
  95. }
  96. const struct snd_pcm_ops mtk_afe_pcm_ops = {
  97. .ioctl = snd_pcm_lib_ioctl,
  98. .pointer = mtk_afe_pcm_pointer,
  99. };
  100. EXPORT_SYMBOL_GPL(mtk_afe_pcm_ops);
  101. int mtk_afe_pcm_new(struct snd_soc_pcm_runtime *rtd)
  102. {
  103. size_t size;
  104. struct snd_pcm *pcm = rtd->pcm;
  105. struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME);
  106. struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
  107. size = afe->mtk_afe_hardware->buffer_bytes_max;
  108. return snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
  109. afe->dev,
  110. size, size);
  111. }
  112. EXPORT_SYMBOL_GPL(mtk_afe_pcm_new);
  113. void mtk_afe_pcm_free(struct snd_pcm *pcm)
  114. {
  115. snd_pcm_lib_preallocate_free_for_all(pcm);
  116. }
  117. EXPORT_SYMBOL_GPL(mtk_afe_pcm_free);
  118. const struct snd_soc_component_driver mtk_afe_pcm_platform = {
  119. .name = AFE_PCM_NAME,
  120. .ops = &mtk_afe_pcm_ops,
  121. .pcm_new = mtk_afe_pcm_new,
  122. .pcm_free = mtk_afe_pcm_free,
  123. };
  124. EXPORT_SYMBOL_GPL(mtk_afe_pcm_platform);
  125. MODULE_DESCRIPTION("Mediatek simple platform driver");
  126. MODULE_AUTHOR("Garlic Tseng <garlic.tseng@mediatek.com>");
  127. MODULE_LICENSE("GPL v2");