File Index
Files and directories
Sign in
FILE

mtk-afe-platform-driver.c

File preview with syntax highlighting.

linux-6.19.14/sound/soc/mediatek/common/mtk-afe-platform-driver.c C
  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
 16int 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}
 47EXPORT_SYMBOL_GPL(mtk_afe_combine_sub_dai);
 48
 49int mtk_afe_add_sub_dai_control(struct snd_soc_component *component)
 50{
 51	struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
 52	struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
 53	struct mtk_base_afe_dai *dai;
 54
 55	list_for_each_entry(dai, &afe->sub_dais, list) {
 56		if (dai->controls)
 57			snd_soc_add_component_controls(component,
 58						       dai->controls,
 59						       dai->num_controls);
 60
 61		if (dai->dapm_widgets)
 62			snd_soc_dapm_new_controls(dapm,
 63						  dai->dapm_widgets,
 64						  dai->num_dapm_widgets);
 65	}
 66	/* add routes after all widgets are added */
 67	list_for_each_entry(dai, &afe->sub_dais, list) {
 68		if (dai->dapm_routes)
 69			snd_soc_dapm_add_routes(dapm,
 70						dai->dapm_routes,
 71						dai->num_dapm_routes);
 72	}
 73
 74	snd_soc_dapm_new_widgets(component->card);
 75
 76	return 0;
 77
 78}
 79EXPORT_SYMBOL_GPL(mtk_afe_add_sub_dai_control);
 80
 81snd_pcm_uframes_t mtk_afe_pcm_pointer(struct snd_soc_component *component,
 82				      struct snd_pcm_substream *substream)
 83{
 84	struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
 85	struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
 86	struct mtk_base_afe_memif *memif = &afe->memif[snd_soc_rtd_to_cpu(rtd, 0)->id];
 87	const struct mtk_base_memif_data *memif_data = memif->data;
 88	struct regmap *regmap = afe->regmap;
 89	struct device *dev = afe->dev;
 90	int reg_ofs_base = memif_data->reg_ofs_base;
 91	int reg_ofs_cur = memif_data->reg_ofs_cur;
 92	unsigned int hw_ptr = 0, hw_base = 0;
 93	int ret, pcm_ptr_bytes;
 94
 95	ret = regmap_read(regmap, reg_ofs_cur, &hw_ptr);
 96	if (ret || hw_ptr == 0) {
 97		dev_err(dev, "%s hw_ptr err\n", __func__);
 98		pcm_ptr_bytes = 0;
 99		goto POINTER_RETURN_FRAMES;
100	}
101
102	ret = regmap_read(regmap, reg_ofs_base, &hw_base);
103	if (ret || hw_base == 0) {
104		dev_err(dev, "%s hw_ptr err\n", __func__);
105		pcm_ptr_bytes = 0;
106		goto POINTER_RETURN_FRAMES;
107	}
108
109	pcm_ptr_bytes = hw_ptr - hw_base;
110
111POINTER_RETURN_FRAMES:
112	return bytes_to_frames(substream->runtime, pcm_ptr_bytes);
113}
114EXPORT_SYMBOL_GPL(mtk_afe_pcm_pointer);
115
116int mtk_afe_pcm_new(struct snd_soc_component *component,
117		    struct snd_soc_pcm_runtime *rtd)
118{
119	size_t size;
120	struct snd_pcm *pcm = rtd->pcm;
121	struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
122
123	size = afe->mtk_afe_hardware->buffer_bytes_max;
124	snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV, afe->dev,
125				       afe->preallocate_buffers ? size : 0,
126				       size);
127
128	return 0;
129}
130EXPORT_SYMBOL_GPL(mtk_afe_pcm_new);
131
132static int mtk_afe_component_probe(struct snd_soc_component *component)
133{
134	struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
135	int ret;
136
137	snd_soc_component_init_regmap(component, afe->regmap);
138
139	/* If the list was never initialized there are no sub-DAIs */
140	if (afe->sub_dais.next && afe->sub_dais.prev) {
141		ret = mtk_afe_add_sub_dai_control(component);
142		if (ret)
143			return ret;
144	}
145
146	return 0;
147}
148
149const struct snd_soc_component_driver mtk_afe_pcm_platform = {
150	.name		= AFE_PCM_NAME,
151	.pointer	= mtk_afe_pcm_pointer,
152	.pcm_construct	= mtk_afe_pcm_new,
153	.probe		= mtk_afe_component_probe,
154};
155EXPORT_SYMBOL_GPL(mtk_afe_pcm_platform);
156
157MODULE_DESCRIPTION("Mediatek simple platform driver");
158MODULE_AUTHOR("Garlic Tseng <garlic.tseng@mediatek.com>");
159MODULE_LICENSE("GPL v2");
160
~/ Read-only file preview.