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 9 #include <linux/module.h> 10 #include <linux/dma-mapping.h> 11 #include <sound/soc.h> 12 13 #include "mtk-afe-platform-driver.h" 14 #include "mtk-base-afe.h" 15 16 int mtk_afe_combine_sub_dai(struct mtk_base_afe *afe) 17 { 18 struct mtk_base_afe_dai *dai; 19 size_t num_dai_drivers = 0, dai_idx = 0; 20 21 /* calcualte total dai driver size */ 22 list_for_each_entry(dai, &afe->sub_dais, list) { 23 num_dai_drivers += dai->num_dai_drivers; 24 } 25 26 dev_info(afe->dev, "%s(), num of dai %zd\n", __func__, num_dai_drivers); 27 28 /* combine sub_dais */ 29 afe->num_dai_drivers = num_dai_drivers; 30 afe->dai_drivers = devm_kcalloc(afe->dev, 31 num_dai_drivers, 32 sizeof(struct snd_soc_dai_driver), 33 GFP_KERNEL); 34 if (!afe->dai_drivers) 35 return -ENOMEM; 36 37 list_for_each_entry(dai, &afe->sub_dais, list) { 38 /* dai driver */ 39 memcpy(&afe->dai_drivers[dai_idx], 40 dai->dai_drivers, 41 dai->num_dai_drivers * 42 sizeof(struct snd_soc_dai_driver)); 43 dai_idx += dai->num_dai_drivers; 44 } 45 return 0; 46 } 47 EXPORT_SYMBOL_GPL(mtk_afe_combine_sub_dai); 48 49 int mtk_afe_add_sub_dai_control(struct snd_soc_component *component) 50 { 51 struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component); 52 struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component); 53 struct mtk_base_afe_dai *dai; 54 55 list_for_each_entry(dai, &afe->sub_dais, list) { 56 if (dai->controls) 57 snd_soc_add_component_controls(component, 58 dai->controls, 59 dai->num_controls); 60 61 if (dai->dapm_widgets) 62 snd_soc_dapm_new_controls(dapm, 63 dai->dapm_widgets, 64 dai->num_dapm_widgets); 65 } 66 /* add routes after all widgets are added */ 67 list_for_each_entry(dai, &afe->sub_dais, list) { 68 if (dai->dapm_routes) 69 snd_soc_dapm_add_routes(dapm, 70 dai->dapm_routes, 71 dai->num_dapm_routes); 72 } 73 74 snd_soc_dapm_new_widgets(component->card); 75 76 return 0; 77 78 } 79 EXPORT_SYMBOL_GPL(mtk_afe_add_sub_dai_control); 80 81 snd_pcm_uframes_t mtk_afe_pcm_pointer(struct snd_soc_component *component, 82 struct snd_pcm_substream *substream) 83 { 84 struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); 85 struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component); 86 struct mtk_base_afe_memif *memif = &afe->memif[snd_soc_rtd_to_cpu(rtd, 0)->id]; 87 const struct mtk_base_memif_data *memif_data = memif->data; 88 struct regmap *regmap = afe->regmap; 89 struct device *dev = afe->dev; 90 int reg_ofs_base = memif_data->reg_ofs_base; 91 int reg_ofs_cur = memif_data->reg_ofs_cur; 92 unsigned int hw_ptr = 0, hw_base = 0; 93 int ret, pcm_ptr_bytes; 94 95 ret = regmap_read(regmap, reg_ofs_cur, &hw_ptr); 96 if (ret || hw_ptr == 0) { 97 dev_err(dev, "%s hw_ptr err\n", __func__); 98 pcm_ptr_bytes = 0; 99 goto POINTER_RETURN_FRAMES; 100 } 101 102 ret = regmap_read(regmap, reg_ofs_base, &hw_base); 103 if (ret || hw_base == 0) { 104 dev_err(dev, "%s hw_ptr err\n", __func__); 105 pcm_ptr_bytes = 0; 106 goto POINTER_RETURN_FRAMES; 107 } 108 109 pcm_ptr_bytes = hw_ptr - hw_base; 110 111 POINTER_RETURN_FRAMES: 112 return bytes_to_frames(substream->runtime, pcm_ptr_bytes); 113 } 114 EXPORT_SYMBOL_GPL(mtk_afe_pcm_pointer); 115 116 int mtk_afe_pcm_new(struct snd_soc_component *component, 117 struct snd_soc_pcm_runtime *rtd) 118 { 119 size_t size; 120 struct snd_pcm *pcm = rtd->pcm; 121 struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component); 122 123 size = afe->mtk_afe_hardware->buffer_bytes_max; 124 snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV, afe->dev, 125 afe->preallocate_buffers ? size : 0, 126 size); 127 128 return 0; 129 } 130 EXPORT_SYMBOL_GPL(mtk_afe_pcm_new); 131 132 static int mtk_afe_component_probe(struct snd_soc_component *component) 133 { 134 struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component); 135 int ret; 136 137 snd_soc_component_init_regmap(component, afe->regmap); 138 139 /* If the list was never initialized there are no sub-DAIs */ 140 if (afe->sub_dais.next && afe->sub_dais.prev) { 141 ret = mtk_afe_add_sub_dai_control(component); 142 if (ret) 143 return ret; 144 } 145 146 return 0; 147 } 148 149 const struct snd_soc_component_driver mtk_afe_pcm_platform = { 150 .name = AFE_PCM_NAME, 151 .pointer = mtk_afe_pcm_pointer, 152 .pcm_construct = mtk_afe_pcm_new, 153 .probe = mtk_afe_component_probe, 154 }; 155 EXPORT_SYMBOL_GPL(mtk_afe_pcm_platform); 156 157 MODULE_DESCRIPTION("Mediatek simple platform driver"); 158 MODULE_AUTHOR("Garlic Tseng <garlic.tseng@mediatek.com>"); 159 MODULE_LICENSE("GPL v2"); 160 161