forked from Qortal/Brooklyn
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
139 lines
3.8 KiB
139 lines
3.8 KiB
// SPDX-License-Identifier: GPL-2.0 |
|
/* |
|
* mtk-afe-platform-driver.c -- Mediatek afe platform driver |
|
* |
|
* Copyright (c) 2016 MediaTek Inc. |
|
* Author: Garlic Tseng <[email protected]> |
|
*/ |
|
|
|
#include <linux/module.h> |
|
#include <linux/dma-mapping.h> |
|
#include <sound/soc.h> |
|
|
|
#include "mtk-afe-platform-driver.h" |
|
#include "mtk-base-afe.h" |
|
|
|
int mtk_afe_combine_sub_dai(struct mtk_base_afe *afe) |
|
{ |
|
struct mtk_base_afe_dai *dai; |
|
size_t num_dai_drivers = 0, dai_idx = 0; |
|
|
|
/* calcualte total dai driver size */ |
|
list_for_each_entry(dai, &afe->sub_dais, list) { |
|
num_dai_drivers += dai->num_dai_drivers; |
|
} |
|
|
|
dev_info(afe->dev, "%s(), num of dai %zd\n", __func__, num_dai_drivers); |
|
|
|
/* combine sub_dais */ |
|
afe->num_dai_drivers = num_dai_drivers; |
|
afe->dai_drivers = devm_kcalloc(afe->dev, |
|
num_dai_drivers, |
|
sizeof(struct snd_soc_dai_driver), |
|
GFP_KERNEL); |
|
if (!afe->dai_drivers) |
|
return -ENOMEM; |
|
|
|
list_for_each_entry(dai, &afe->sub_dais, list) { |
|
/* dai driver */ |
|
memcpy(&afe->dai_drivers[dai_idx], |
|
dai->dai_drivers, |
|
dai->num_dai_drivers * |
|
sizeof(struct snd_soc_dai_driver)); |
|
dai_idx += dai->num_dai_drivers; |
|
} |
|
return 0; |
|
} |
|
EXPORT_SYMBOL_GPL(mtk_afe_combine_sub_dai); |
|
|
|
int mtk_afe_add_sub_dai_control(struct snd_soc_component *component) |
|
{ |
|
struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component); |
|
struct mtk_base_afe_dai *dai; |
|
|
|
list_for_each_entry(dai, &afe->sub_dais, list) { |
|
if (dai->controls) |
|
snd_soc_add_component_controls(component, |
|
dai->controls, |
|
dai->num_controls); |
|
|
|
if (dai->dapm_widgets) |
|
snd_soc_dapm_new_controls(&component->dapm, |
|
dai->dapm_widgets, |
|
dai->num_dapm_widgets); |
|
} |
|
/* add routes after all widgets are added */ |
|
list_for_each_entry(dai, &afe->sub_dais, list) { |
|
if (dai->dapm_routes) |
|
snd_soc_dapm_add_routes(&component->dapm, |
|
dai->dapm_routes, |
|
dai->num_dapm_routes); |
|
} |
|
|
|
snd_soc_dapm_new_widgets(component->dapm.card); |
|
|
|
return 0; |
|
|
|
} |
|
EXPORT_SYMBOL_GPL(mtk_afe_add_sub_dai_control); |
|
|
|
snd_pcm_uframes_t mtk_afe_pcm_pointer(struct snd_soc_component *component, |
|
struct snd_pcm_substream *substream) |
|
{ |
|
struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); |
|
struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component); |
|
struct mtk_base_afe_memif *memif = &afe->memif[asoc_rtd_to_cpu(rtd, 0)->id]; |
|
const struct mtk_base_memif_data *memif_data = memif->data; |
|
struct regmap *regmap = afe->regmap; |
|
struct device *dev = afe->dev; |
|
int reg_ofs_base = memif_data->reg_ofs_base; |
|
int reg_ofs_cur = memif_data->reg_ofs_cur; |
|
unsigned int hw_ptr = 0, hw_base = 0; |
|
int ret, pcm_ptr_bytes; |
|
|
|
ret = regmap_read(regmap, reg_ofs_cur, &hw_ptr); |
|
if (ret || hw_ptr == 0) { |
|
dev_err(dev, "%s hw_ptr err\n", __func__); |
|
pcm_ptr_bytes = 0; |
|
goto POINTER_RETURN_FRAMES; |
|
} |
|
|
|
ret = regmap_read(regmap, reg_ofs_base, &hw_base); |
|
if (ret || hw_base == 0) { |
|
dev_err(dev, "%s hw_ptr err\n", __func__); |
|
pcm_ptr_bytes = 0; |
|
goto POINTER_RETURN_FRAMES; |
|
} |
|
|
|
pcm_ptr_bytes = hw_ptr - hw_base; |
|
|
|
POINTER_RETURN_FRAMES: |
|
return bytes_to_frames(substream->runtime, pcm_ptr_bytes); |
|
} |
|
EXPORT_SYMBOL_GPL(mtk_afe_pcm_pointer); |
|
|
|
int mtk_afe_pcm_new(struct snd_soc_component *component, |
|
struct snd_soc_pcm_runtime *rtd) |
|
{ |
|
size_t size; |
|
struct snd_pcm *pcm = rtd->pcm; |
|
struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component); |
|
|
|
size = afe->mtk_afe_hardware->buffer_bytes_max; |
|
snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV, |
|
afe->dev, size, size); |
|
return 0; |
|
} |
|
EXPORT_SYMBOL_GPL(mtk_afe_pcm_new); |
|
|
|
const struct snd_soc_component_driver mtk_afe_pcm_platform = { |
|
.name = AFE_PCM_NAME, |
|
.pointer = mtk_afe_pcm_pointer, |
|
.pcm_construct = mtk_afe_pcm_new, |
|
}; |
|
EXPORT_SYMBOL_GPL(mtk_afe_pcm_platform); |
|
|
|
MODULE_DESCRIPTION("Mediatek simple platform driver"); |
|
MODULE_AUTHOR("Garlic Tseng <[email protected]>"); |
|
MODULE_LICENSE("GPL v2"); |
|
|
|
|