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 unsigned int hw_ptr_lower32 = 0, hw_ptr_upper32 = 0; 91 unsigned int hw_base_lower32 = 0, hw_base_upper32 = 0; 92 unsigned long long hw_ptr = 0, hw_base = 0; 93 int ret; 94 unsigned long long pcm_ptr_bytes = 0; 95 96 ret = regmap_read(regmap, memif_data->reg_ofs_cur, &hw_ptr_lower32); 97 if (ret) { 98 dev_err(dev, "%s hw_ptr_lower32 err\n", __func__); 99 return 0; 100 } 101 102 if (memif_data->reg_ofs_cur_msb) { 103 ret = regmap_read(regmap, memif_data->reg_ofs_cur_msb, &hw_ptr_upper32); 104 if (ret) { 105 dev_err(dev, "%s hw_ptr_upper32 err\n", __func__); 106 return 0; 107 } 108 } 109 110 ret = regmap_read(regmap, memif_data->reg_ofs_base, &hw_base_lower32); 111 if (ret) { 112 dev_err(dev, "%s hw_base_lower32 err\n", __func__); 113 return 0; 114 } 115 if (memif_data->reg_ofs_base_msb) { 116 ret = regmap_read(regmap, memif_data->reg_ofs_base_msb, &hw_base_upper32); 117 if (ret) { 118 dev_err(dev, "%s hw_base_upper32 err\n", __func__); 119 return 0; 120 } 121 } 122 123 hw_ptr = ((unsigned long long)hw_ptr_upper32 << 32) | hw_ptr_lower32; 124 hw_base = ((unsigned long long)hw_base_upper32 << 32) | hw_base_lower32; 125 126 if (!hw_ptr || !hw_base) { 127 dev_err(dev, "hw_ptr or hw_base = 0 err\n"); 128 return 0; 129 } 130 131 pcm_ptr_bytes = MTK_ALIGN_16BYTES(hw_ptr - hw_base); 132 return bytes_to_frames(substream->runtime, (ssize_t)pcm_ptr_bytes); 133 } 134 EXPORT_SYMBOL_GPL(mtk_afe_pcm_pointer); 135 136 int mtk_afe_pcm_new(struct snd_soc_component *component, 137 struct snd_soc_pcm_runtime *rtd) 138 { 139 size_t size; 140 struct snd_pcm *pcm = rtd->pcm; 141 struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component); 142 143 size = afe->mtk_afe_hardware->buffer_bytes_max; 144 snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV, afe->dev, 145 afe->preallocate_buffers ? size : 0, 146 size); 147 148 return 0; 149 } 150 EXPORT_SYMBOL_GPL(mtk_afe_pcm_new); 151 152 static int mtk_afe_component_probe(struct snd_soc_component *component) 153 { 154 struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component); 155 int ret; 156 157 snd_soc_component_init_regmap(component, afe->regmap); 158 159 /* If the list was never initialized there are no sub-DAIs */ 160 if (afe->sub_dais.next && afe->sub_dais.prev) { 161 ret = mtk_afe_add_sub_dai_control(component); 162 if (ret) 163 return ret; 164 } 165 166 return 0; 167 } 168 169 const struct snd_soc_component_driver mtk_afe_pcm_platform = { 170 .name = AFE_PCM_NAME, 171 .pointer = mtk_afe_pcm_pointer, 172 .pcm_new = mtk_afe_pcm_new, 173 .probe = mtk_afe_component_probe, 174 }; 175 EXPORT_SYMBOL_GPL(mtk_afe_pcm_platform); 176 177 MODULE_DESCRIPTION("Mediatek simple platform driver"); 178 MODULE_AUTHOR("Garlic Tseng <garlic.tseng@mediatek.com>"); 179 MODULE_LICENSE("GPL v2"); 180 181