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 mtk_base_afe *afe = snd_soc_component_get_drvdata(component); 52 struct mtk_base_afe_dai *dai; 53 54 list_for_each_entry(dai, &afe->sub_dais, list) { 55 if (dai->controls) 56 snd_soc_add_component_controls(component, 57 dai->controls, 58 dai->num_controls); 59 60 if (dai->dapm_widgets) 61 snd_soc_dapm_new_controls(&component->dapm, 62 dai->dapm_widgets, 63 dai->num_dapm_widgets); 64 } 65 /* add routes after all widgets are added */ 66 list_for_each_entry(dai, &afe->sub_dais, list) { 67 if (dai->dapm_routes) 68 snd_soc_dapm_add_routes(&component->dapm, 69 dai->dapm_routes, 70 dai->num_dapm_routes); 71 } 72 73 snd_soc_dapm_new_widgets(component->dapm.card); 74 75 return 0; 76 77 } 78 EXPORT_SYMBOL_GPL(mtk_afe_add_sub_dai_control); 79 80 static snd_pcm_uframes_t mtk_afe_pcm_pointer 81 (struct snd_pcm_substream *substream) 82 { 83 struct snd_soc_pcm_runtime *rtd = substream->private_data; 84 struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME); 85 struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component); 86 struct mtk_base_afe_memif *memif = &afe->memif[rtd->cpu_dai->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 115 const struct snd_pcm_ops mtk_afe_pcm_ops = { 116 .ioctl = snd_pcm_lib_ioctl, 117 .pointer = mtk_afe_pcm_pointer, 118 }; 119 EXPORT_SYMBOL_GPL(mtk_afe_pcm_ops); 120 121 int mtk_afe_pcm_new(struct snd_soc_pcm_runtime *rtd) 122 { 123 size_t size; 124 struct snd_pcm *pcm = rtd->pcm; 125 struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME); 126 struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component); 127 128 size = afe->mtk_afe_hardware->buffer_bytes_max; 129 return snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, 130 afe->dev, 131 size, size); 132 } 133 EXPORT_SYMBOL_GPL(mtk_afe_pcm_new); 134 135 void mtk_afe_pcm_free(struct snd_pcm *pcm) 136 { 137 snd_pcm_lib_preallocate_free_for_all(pcm); 138 } 139 EXPORT_SYMBOL_GPL(mtk_afe_pcm_free); 140 141 const struct snd_soc_component_driver mtk_afe_pcm_platform = { 142 .name = AFE_PCM_NAME, 143 .ops = &mtk_afe_pcm_ops, 144 .pcm_new = mtk_afe_pcm_new, 145 .pcm_free = mtk_afe_pcm_free, 146 }; 147 EXPORT_SYMBOL_GPL(mtk_afe_pcm_platform); 148 149 MODULE_DESCRIPTION("Mediatek simple platform driver"); 150 MODULE_AUTHOR("Garlic Tseng <garlic.tseng@mediatek.com>"); 151 MODULE_LICENSE("GPL v2"); 152 153