2018-04-25 12:19:59 +08:00
|
|
|
// SPDX-License-Identifier: GPL-2.0
|
2016-06-17 15:43:53 +08:00
|
|
|
/*
|
|
|
|
* 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"
|
|
|
|
|
ASoC: mediatek: add sub dai to mtk_base_afe
In MediaTek SoC chip we have multiple DAI,
such as I2S, ADDA, PCM, etc.
Organize each DAI in to one sub dai,
with its dai driver, controls, widgets, routes.
add mtk_afe_combine_sub_dai() to combine
dai driver from each DAI.
add mtk_afe_add_sub_dai_control() to register
the control, widget, routes to component.
Signed-off-by: KaiChieh Chuang <kaichieh.chuang@mediatek.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
2018-05-25 11:48:16 +08:00
|
|
|
int mtk_afe_combine_sub_dai(struct mtk_base_afe *afe)
|
|
|
|
{
|
2018-06-29 20:29:44 +08:00
|
|
|
struct mtk_base_afe_dai *dai;
|
ASoC: mediatek: add sub dai to mtk_base_afe
In MediaTek SoC chip we have multiple DAI,
such as I2S, ADDA, PCM, etc.
Organize each DAI in to one sub dai,
with its dai driver, controls, widgets, routes.
add mtk_afe_combine_sub_dai() to combine
dai driver from each DAI.
add mtk_afe_add_sub_dai_control() to register
the control, widget, routes to component.
Signed-off-by: KaiChieh Chuang <kaichieh.chuang@mediatek.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
2018-05-25 11:48:16 +08:00
|
|
|
size_t num_dai_drivers = 0, dai_idx = 0;
|
|
|
|
|
|
|
|
/* calcualte total dai driver size */
|
2018-06-29 20:29:44 +08:00
|
|
|
list_for_each_entry(dai, &afe->sub_dais, list) {
|
|
|
|
num_dai_drivers += dai->num_dai_drivers;
|
ASoC: mediatek: add sub dai to mtk_base_afe
In MediaTek SoC chip we have multiple DAI,
such as I2S, ADDA, PCM, etc.
Organize each DAI in to one sub dai,
with its dai driver, controls, widgets, routes.
add mtk_afe_combine_sub_dai() to combine
dai driver from each DAI.
add mtk_afe_add_sub_dai_control() to register
the control, widget, routes to component.
Signed-off-by: KaiChieh Chuang <kaichieh.chuang@mediatek.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
2018-05-25 11:48:16 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
2018-06-29 20:29:44 +08:00
|
|
|
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;
|
ASoC: mediatek: add sub dai to mtk_base_afe
In MediaTek SoC chip we have multiple DAI,
such as I2S, ADDA, PCM, etc.
Organize each DAI in to one sub dai,
with its dai driver, controls, widgets, routes.
add mtk_afe_combine_sub_dai() to combine
dai driver from each DAI.
add mtk_afe_add_sub_dai_control() to register
the control, widget, routes to component.
Signed-off-by: KaiChieh Chuang <kaichieh.chuang@mediatek.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
2018-05-25 11:48:16 +08:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
2018-05-31 06:00:35 +08:00
|
|
|
EXPORT_SYMBOL_GPL(mtk_afe_combine_sub_dai);
|
ASoC: mediatek: add sub dai to mtk_base_afe
In MediaTek SoC chip we have multiple DAI,
such as I2S, ADDA, PCM, etc.
Organize each DAI in to one sub dai,
with its dai driver, controls, widgets, routes.
add mtk_afe_combine_sub_dai() to combine
dai driver from each DAI.
add mtk_afe_add_sub_dai_control() to register
the control, widget, routes to component.
Signed-off-by: KaiChieh Chuang <kaichieh.chuang@mediatek.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
2018-05-25 11:48:16 +08:00
|
|
|
|
|
|
|
int mtk_afe_add_sub_dai_control(struct snd_soc_component *component)
|
|
|
|
{
|
|
|
|
struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
|
2018-06-29 20:29:44 +08:00
|
|
|
struct mtk_base_afe_dai *dai;
|
ASoC: mediatek: add sub dai to mtk_base_afe
In MediaTek SoC chip we have multiple DAI,
such as I2S, ADDA, PCM, etc.
Organize each DAI in to one sub dai,
with its dai driver, controls, widgets, routes.
add mtk_afe_combine_sub_dai() to combine
dai driver from each DAI.
add mtk_afe_add_sub_dai_control() to register
the control, widget, routes to component.
Signed-off-by: KaiChieh Chuang <kaichieh.chuang@mediatek.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
2018-05-25 11:48:16 +08:00
|
|
|
|
2018-06-29 20:29:44 +08:00
|
|
|
list_for_each_entry(dai, &afe->sub_dais, list) {
|
|
|
|
if (dai->controls)
|
ASoC: mediatek: add sub dai to mtk_base_afe
In MediaTek SoC chip we have multiple DAI,
such as I2S, ADDA, PCM, etc.
Organize each DAI in to one sub dai,
with its dai driver, controls, widgets, routes.
add mtk_afe_combine_sub_dai() to combine
dai driver from each DAI.
add mtk_afe_add_sub_dai_control() to register
the control, widget, routes to component.
Signed-off-by: KaiChieh Chuang <kaichieh.chuang@mediatek.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
2018-05-25 11:48:16 +08:00
|
|
|
snd_soc_add_component_controls(component,
|
2018-06-29 20:29:44 +08:00
|
|
|
dai->controls,
|
|
|
|
dai->num_controls);
|
ASoC: mediatek: add sub dai to mtk_base_afe
In MediaTek SoC chip we have multiple DAI,
such as I2S, ADDA, PCM, etc.
Organize each DAI in to one sub dai,
with its dai driver, controls, widgets, routes.
add mtk_afe_combine_sub_dai() to combine
dai driver from each DAI.
add mtk_afe_add_sub_dai_control() to register
the control, widget, routes to component.
Signed-off-by: KaiChieh Chuang <kaichieh.chuang@mediatek.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
2018-05-25 11:48:16 +08:00
|
|
|
|
2018-06-29 20:29:44 +08:00
|
|
|
if (dai->dapm_widgets)
|
ASoC: mediatek: add sub dai to mtk_base_afe
In MediaTek SoC chip we have multiple DAI,
such as I2S, ADDA, PCM, etc.
Organize each DAI in to one sub dai,
with its dai driver, controls, widgets, routes.
add mtk_afe_combine_sub_dai() to combine
dai driver from each DAI.
add mtk_afe_add_sub_dai_control() to register
the control, widget, routes to component.
Signed-off-by: KaiChieh Chuang <kaichieh.chuang@mediatek.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
2018-05-25 11:48:16 +08:00
|
|
|
snd_soc_dapm_new_controls(&component->dapm,
|
2018-06-29 20:29:44 +08:00
|
|
|
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)
|
ASoC: mediatek: add sub dai to mtk_base_afe
In MediaTek SoC chip we have multiple DAI,
such as I2S, ADDA, PCM, etc.
Organize each DAI in to one sub dai,
with its dai driver, controls, widgets, routes.
add mtk_afe_combine_sub_dai() to combine
dai driver from each DAI.
add mtk_afe_add_sub_dai_control() to register
the control, widget, routes to component.
Signed-off-by: KaiChieh Chuang <kaichieh.chuang@mediatek.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
2018-05-25 11:48:16 +08:00
|
|
|
snd_soc_dapm_add_routes(&component->dapm,
|
2018-06-29 20:29:44 +08:00
|
|
|
dai->dapm_routes,
|
|
|
|
dai->num_dapm_routes);
|
ASoC: mediatek: add sub dai to mtk_base_afe
In MediaTek SoC chip we have multiple DAI,
such as I2S, ADDA, PCM, etc.
Organize each DAI in to one sub dai,
with its dai driver, controls, widgets, routes.
add mtk_afe_combine_sub_dai() to combine
dai driver from each DAI.
add mtk_afe_add_sub_dai_control() to register
the control, widget, routes to component.
Signed-off-by: KaiChieh Chuang <kaichieh.chuang@mediatek.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
2018-05-25 11:48:16 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
snd_soc_dapm_new_widgets(component->dapm.card);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
}
|
2018-05-31 06:00:35 +08:00
|
|
|
EXPORT_SYMBOL_GPL(mtk_afe_add_sub_dai_control);
|
ASoC: mediatek: add sub dai to mtk_base_afe
In MediaTek SoC chip we have multiple DAI,
such as I2S, ADDA, PCM, etc.
Organize each DAI in to one sub dai,
with its dai driver, controls, widgets, routes.
add mtk_afe_combine_sub_dai() to combine
dai driver from each DAI.
add mtk_afe_add_sub_dai_control() to register
the control, widget, routes to component.
Signed-off-by: KaiChieh Chuang <kaichieh.chuang@mediatek.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
2018-05-25 11:48:16 +08:00
|
|
|
|
2016-06-17 15:43:53 +08:00
|
|
|
static snd_pcm_uframes_t mtk_afe_pcm_pointer
|
|
|
|
(struct snd_pcm_substream *substream)
|
|
|
|
{
|
|
|
|
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
2018-01-29 10:51:42 +08:00
|
|
|
struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME);
|
|
|
|
struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
|
2016-06-17 15:43:53 +08:00
|
|
|
struct mtk_base_afe_memif *memif = &afe->memif[rtd->cpu_dai->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);
|
|
|
|
}
|
|
|
|
|
2018-05-25 11:48:18 +08:00
|
|
|
const struct snd_pcm_ops mtk_afe_pcm_ops = {
|
2016-06-17 15:43:53 +08:00
|
|
|
.ioctl = snd_pcm_lib_ioctl,
|
|
|
|
.pointer = mtk_afe_pcm_pointer,
|
|
|
|
};
|
2018-05-31 06:00:35 +08:00
|
|
|
EXPORT_SYMBOL_GPL(mtk_afe_pcm_ops);
|
2016-06-17 15:43:53 +08:00
|
|
|
|
2018-05-25 11:48:18 +08:00
|
|
|
int mtk_afe_pcm_new(struct snd_soc_pcm_runtime *rtd)
|
2016-06-17 15:43:53 +08:00
|
|
|
{
|
|
|
|
size_t size;
|
|
|
|
struct snd_pcm *pcm = rtd->pcm;
|
2018-01-29 10:51:42 +08:00
|
|
|
struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME);
|
|
|
|
struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
|
2016-06-17 15:43:53 +08:00
|
|
|
|
|
|
|
size = afe->mtk_afe_hardware->buffer_bytes_max;
|
2019-02-04 23:39:15 +08:00
|
|
|
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
|
|
|
|
afe->dev, size, size);
|
|
|
|
return 0;
|
2016-06-17 15:43:53 +08:00
|
|
|
}
|
2018-05-31 06:00:35 +08:00
|
|
|
EXPORT_SYMBOL_GPL(mtk_afe_pcm_new);
|
2016-06-17 15:43:53 +08:00
|
|
|
|
2018-05-25 11:48:18 +08:00
|
|
|
void mtk_afe_pcm_free(struct snd_pcm *pcm)
|
2016-06-17 15:43:53 +08:00
|
|
|
{
|
|
|
|
snd_pcm_lib_preallocate_free_for_all(pcm);
|
|
|
|
}
|
2018-05-31 06:00:35 +08:00
|
|
|
EXPORT_SYMBOL_GPL(mtk_afe_pcm_free);
|
2016-06-17 15:43:53 +08:00
|
|
|
|
2018-01-29 10:51:42 +08:00
|
|
|
const struct snd_soc_component_driver mtk_afe_pcm_platform = {
|
|
|
|
.name = AFE_PCM_NAME,
|
2016-06-17 15:43:53 +08:00
|
|
|
.ops = &mtk_afe_pcm_ops,
|
|
|
|
.pcm_new = mtk_afe_pcm_new,
|
|
|
|
.pcm_free = mtk_afe_pcm_free,
|
|
|
|
};
|
|
|
|
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");
|
|
|
|
|