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 snd_pcm_uframes_t mtk_afe_pcm_pointer(struct snd_soc_component *component, 81 struct snd_pcm_substream *substream) 82 { 83 struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); 84 struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component); 85 struct mtk_base_afe_memif *memif = &afe->memif[snd_soc_rtd_to_cpu(rtd, 0)->id]; 86 const struct mtk_base_memif_data *memif_data = memif->data; 87 struct regmap *regmap = afe->regmap; 88 struct device *dev = afe->dev; 89 int reg_ofs_base = memif_data->reg_ofs_base; 90 int reg_ofs_cur = memif_data->reg_ofs_cur; 91 unsigned int hw_ptr = 0, hw_base = 0; 92 int ret, pcm_ptr_bytes; 93 94 ret = regmap_read(regmap, reg_ofs_cur, &hw_ptr); 95 if (ret || hw_ptr == 0) { 96 dev_err(dev, "%s hw_ptr err\n", __func__); 97 pcm_ptr_bytes = 0; 98 goto POINTER_RETURN_FRAMES; 99 } 100 101 ret = regmap_read(regmap, reg_ofs_base, &hw_base); 102 if (ret || hw_base == 0) { 103 dev_err(dev, "%s hw_ptr err\n", __func__); 104 pcm_ptr_bytes = 0; 105 goto POINTER_RETURN_FRAMES; 106 } 107 108 pcm_ptr_bytes = hw_ptr - hw_base; 109 110 POINTER_RETURN_FRAMES: 111 return bytes_to_frames(substream->runtime, pcm_ptr_bytes); 112 } 113 EXPORT_SYMBOL_GPL(mtk_afe_pcm_pointer); 114 115 int mtk_afe_pcm_new(struct snd_soc_component *component, 116 struct snd_soc_pcm_runtime *rtd) 117 { 118 size_t size; 119 struct snd_pcm *pcm = rtd->pcm; 120 struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component); 121 122 size = afe->mtk_afe_hardware->buffer_bytes_max; 123 snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV, 124 afe->dev, size, size); 125 return 0; 126 } 127 EXPORT_SYMBOL_GPL(mtk_afe_pcm_new); 128 129 static int mtk_afe_component_probe(struct snd_soc_component *component) 130 { 131 struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component); 132 int ret; 133 134 snd_soc_component_init_regmap(component, afe->regmap); 135 136 /* If the list was never initialized there are no sub-DAIs */ 137 if (afe->sub_dais.next && afe->sub_dais.prev) { 138 ret = mtk_afe_add_sub_dai_control(component); 139 if (ret) 140 return ret; 141 } 142 143 return 0; 144 } 145 146 const struct snd_soc_component_driver mtk_afe_pcm_platform = { 147 .name = AFE_PCM_NAME, 148 .pointer = mtk_afe_pcm_pointer, 149 .pcm_construct = mtk_afe_pcm_new, 150 .probe = mtk_afe_component_probe, 151 }; 152 EXPORT_SYMBOL_GPL(mtk_afe_pcm_platform); 153 154 MODULE_DESCRIPTION("Mediatek simple platform driver"); 155 MODULE_AUTHOR("Garlic Tseng <garlic.tseng@mediatek.com>"); 156 MODULE_LICENSE("GPL v2"); 157 158