mirror of
https://git.proxmox.com/git/mirror_ubuntu-kernels.git
synced 2025-11-21 18:30:29 +00:00
Multiple MediaTek AFE PCM component drivers are using their own .probe() callback, but most of those are simply duplicated functions as they are doing exactly the same thing over and over. Add a common probe callback for this component to reduce duplication. Reviewed-by: Alexandre Mergnat <amergnat@baylibre.com> Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com> Link: https://lore.kernel.org/r/20240416071410.75620-12-angelogioacchino.delregno@collabora.com Signed-off-by: Mark Brown <broonie@kernel.org>
158 lines
4.3 KiB
C
158 lines
4.3 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
/*
|
|
* mtk-afe-platform-driver.c -- Mediatek afe platform driver
|
|
*
|
|
* Copyright (c) 2016 MediaTek Inc.
|
|
* Author: Garlic Tseng <garlic.tseng@mediatek.com>
|
|
*/
|
|
|
|
#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 = snd_soc_substream_to_rtd(substream);
|
|
struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
|
|
struct mtk_base_afe_memif *memif = &afe->memif[snd_soc_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);
|
|
|
|
static int mtk_afe_component_probe(struct snd_soc_component *component)
|
|
{
|
|
struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
|
|
int ret;
|
|
|
|
snd_soc_component_init_regmap(component, afe->regmap);
|
|
|
|
/* If the list was never initialized there are no sub-DAIs */
|
|
if (afe->sub_dais.next && afe->sub_dais.prev) {
|
|
ret = mtk_afe_add_sub_dai_control(component);
|
|
if (ret)
|
|
return ret;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
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,
|
|
.probe = mtk_afe_component_probe,
|
|
};
|
|
EXPORT_SYMBOL_GPL(mtk_afe_pcm_platform);
|
|
|
|
MODULE_DESCRIPTION("Mediatek simple platform driver");
|
|
MODULE_AUTHOR("Garlic Tseng <garlic.tseng@mediatek.com>");
|
|
MODULE_LICENSE("GPL v2");
|
|
|