18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * mtk-afe-platform-driver.c -- Mediatek afe platform driver 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (c) 2016 MediaTek Inc. 68c2ecf20Sopenharmony_ci * Author: Garlic Tseng <garlic.tseng@mediatek.com> 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include <linux/module.h> 108c2ecf20Sopenharmony_ci#include <linux/dma-mapping.h> 118c2ecf20Sopenharmony_ci#include <sound/soc.h> 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#include "mtk-afe-platform-driver.h" 148c2ecf20Sopenharmony_ci#include "mtk-base-afe.h" 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ciint mtk_afe_combine_sub_dai(struct mtk_base_afe *afe) 178c2ecf20Sopenharmony_ci{ 188c2ecf20Sopenharmony_ci struct mtk_base_afe_dai *dai; 198c2ecf20Sopenharmony_ci size_t num_dai_drivers = 0, dai_idx = 0; 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci /* calcualte total dai driver size */ 228c2ecf20Sopenharmony_ci list_for_each_entry(dai, &afe->sub_dais, list) { 238c2ecf20Sopenharmony_ci num_dai_drivers += dai->num_dai_drivers; 248c2ecf20Sopenharmony_ci } 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci dev_info(afe->dev, "%s(), num of dai %zd\n", __func__, num_dai_drivers); 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci /* combine sub_dais */ 298c2ecf20Sopenharmony_ci afe->num_dai_drivers = num_dai_drivers; 308c2ecf20Sopenharmony_ci afe->dai_drivers = devm_kcalloc(afe->dev, 318c2ecf20Sopenharmony_ci num_dai_drivers, 328c2ecf20Sopenharmony_ci sizeof(struct snd_soc_dai_driver), 338c2ecf20Sopenharmony_ci GFP_KERNEL); 348c2ecf20Sopenharmony_ci if (!afe->dai_drivers) 358c2ecf20Sopenharmony_ci return -ENOMEM; 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci list_for_each_entry(dai, &afe->sub_dais, list) { 388c2ecf20Sopenharmony_ci /* dai driver */ 398c2ecf20Sopenharmony_ci memcpy(&afe->dai_drivers[dai_idx], 408c2ecf20Sopenharmony_ci dai->dai_drivers, 418c2ecf20Sopenharmony_ci dai->num_dai_drivers * 428c2ecf20Sopenharmony_ci sizeof(struct snd_soc_dai_driver)); 438c2ecf20Sopenharmony_ci dai_idx += dai->num_dai_drivers; 448c2ecf20Sopenharmony_ci } 458c2ecf20Sopenharmony_ci return 0; 468c2ecf20Sopenharmony_ci} 478c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mtk_afe_combine_sub_dai); 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ciint mtk_afe_add_sub_dai_control(struct snd_soc_component *component) 508c2ecf20Sopenharmony_ci{ 518c2ecf20Sopenharmony_ci struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component); 528c2ecf20Sopenharmony_ci struct mtk_base_afe_dai *dai; 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci list_for_each_entry(dai, &afe->sub_dais, list) { 558c2ecf20Sopenharmony_ci if (dai->controls) 568c2ecf20Sopenharmony_ci snd_soc_add_component_controls(component, 578c2ecf20Sopenharmony_ci dai->controls, 588c2ecf20Sopenharmony_ci dai->num_controls); 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci if (dai->dapm_widgets) 618c2ecf20Sopenharmony_ci snd_soc_dapm_new_controls(&component->dapm, 628c2ecf20Sopenharmony_ci dai->dapm_widgets, 638c2ecf20Sopenharmony_ci dai->num_dapm_widgets); 648c2ecf20Sopenharmony_ci } 658c2ecf20Sopenharmony_ci /* add routes after all widgets are added */ 668c2ecf20Sopenharmony_ci list_for_each_entry(dai, &afe->sub_dais, list) { 678c2ecf20Sopenharmony_ci if (dai->dapm_routes) 688c2ecf20Sopenharmony_ci snd_soc_dapm_add_routes(&component->dapm, 698c2ecf20Sopenharmony_ci dai->dapm_routes, 708c2ecf20Sopenharmony_ci dai->num_dapm_routes); 718c2ecf20Sopenharmony_ci } 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci snd_soc_dapm_new_widgets(component->dapm.card); 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci return 0; 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci} 788c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mtk_afe_add_sub_dai_control); 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_cisnd_pcm_uframes_t mtk_afe_pcm_pointer(struct snd_soc_component *component, 818c2ecf20Sopenharmony_ci struct snd_pcm_substream *substream) 828c2ecf20Sopenharmony_ci{ 838c2ecf20Sopenharmony_ci struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 848c2ecf20Sopenharmony_ci struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component); 858c2ecf20Sopenharmony_ci struct mtk_base_afe_memif *memif = &afe->memif[asoc_rtd_to_cpu(rtd, 0)->id]; 868c2ecf20Sopenharmony_ci const struct mtk_base_memif_data *memif_data = memif->data; 878c2ecf20Sopenharmony_ci struct regmap *regmap = afe->regmap; 888c2ecf20Sopenharmony_ci struct device *dev = afe->dev; 898c2ecf20Sopenharmony_ci int reg_ofs_base = memif_data->reg_ofs_base; 908c2ecf20Sopenharmony_ci int reg_ofs_cur = memif_data->reg_ofs_cur; 918c2ecf20Sopenharmony_ci unsigned int hw_ptr = 0, hw_base = 0; 928c2ecf20Sopenharmony_ci int ret, pcm_ptr_bytes; 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci ret = regmap_read(regmap, reg_ofs_cur, &hw_ptr); 958c2ecf20Sopenharmony_ci if (ret || hw_ptr == 0) { 968c2ecf20Sopenharmony_ci dev_err(dev, "%s hw_ptr err\n", __func__); 978c2ecf20Sopenharmony_ci pcm_ptr_bytes = 0; 988c2ecf20Sopenharmony_ci goto POINTER_RETURN_FRAMES; 998c2ecf20Sopenharmony_ci } 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci ret = regmap_read(regmap, reg_ofs_base, &hw_base); 1028c2ecf20Sopenharmony_ci if (ret || hw_base == 0) { 1038c2ecf20Sopenharmony_ci dev_err(dev, "%s hw_ptr err\n", __func__); 1048c2ecf20Sopenharmony_ci pcm_ptr_bytes = 0; 1058c2ecf20Sopenharmony_ci goto POINTER_RETURN_FRAMES; 1068c2ecf20Sopenharmony_ci } 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci pcm_ptr_bytes = hw_ptr - hw_base; 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ciPOINTER_RETURN_FRAMES: 1118c2ecf20Sopenharmony_ci return bytes_to_frames(substream->runtime, pcm_ptr_bytes); 1128c2ecf20Sopenharmony_ci} 1138c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mtk_afe_pcm_pointer); 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ciint mtk_afe_pcm_new(struct snd_soc_component *component, 1168c2ecf20Sopenharmony_ci struct snd_soc_pcm_runtime *rtd) 1178c2ecf20Sopenharmony_ci{ 1188c2ecf20Sopenharmony_ci size_t size; 1198c2ecf20Sopenharmony_ci struct snd_pcm *pcm = rtd->pcm; 1208c2ecf20Sopenharmony_ci struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component); 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci size = afe->mtk_afe_hardware->buffer_bytes_max; 1238c2ecf20Sopenharmony_ci snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV, 1248c2ecf20Sopenharmony_ci afe->dev, size, size); 1258c2ecf20Sopenharmony_ci return 0; 1268c2ecf20Sopenharmony_ci} 1278c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mtk_afe_pcm_new); 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ciconst struct snd_soc_component_driver mtk_afe_pcm_platform = { 1308c2ecf20Sopenharmony_ci .name = AFE_PCM_NAME, 1318c2ecf20Sopenharmony_ci .pointer = mtk_afe_pcm_pointer, 1328c2ecf20Sopenharmony_ci .pcm_construct = mtk_afe_pcm_new, 1338c2ecf20Sopenharmony_ci}; 1348c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mtk_afe_pcm_platform); 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Mediatek simple platform driver"); 1378c2ecf20Sopenharmony_ciMODULE_AUTHOR("Garlic Tseng <garlic.tseng@mediatek.com>"); 1388c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 1398c2ecf20Sopenharmony_ci 140