1 // SPDX-License-Identifier: GPL-2.0
3 * mtk-afe-fe-dais.c -- Mediatek afe fe dai operator
5 * Copyright (c) 2016 MediaTek Inc.
6 * Author: Garlic Tseng <garlic.tseng@mediatek.com>
9 #include <linux/module.h>
10 #include <linux/pm_runtime.h>
11 #include <linux/regmap.h>
12 #include <sound/soc.h>
13 #include "mtk-afe-platform-driver.h"
14 #include "mtk-afe-fe-dai.h"
15 #include "mtk-base-afe.h"
17 #define AFE_BASE_END_OFFSET 8
19 static int mtk_regmap_update_bits(struct regmap *map, int reg,
21 unsigned int val, int shift)
23 if (reg < 0 || WARN_ON_ONCE(shift < 0))
25 return regmap_update_bits(map, reg, mask << shift, val << shift);
28 static int mtk_regmap_write(struct regmap *map, int reg, unsigned int val)
32 return regmap_write(map, reg, val);
35 int mtk_afe_fe_startup(struct snd_pcm_substream *substream,
36 struct snd_soc_dai *dai)
38 struct snd_soc_pcm_runtime *rtd = substream->private_data;
39 struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
40 struct snd_pcm_runtime *runtime = substream->runtime;
41 int memif_num = rtd->cpu_dai->id;
42 struct mtk_base_afe_memif *memif = &afe->memif[memif_num];
43 const struct snd_pcm_hardware *mtk_afe_hardware = afe->mtk_afe_hardware;
46 memif->substream = substream;
48 snd_pcm_hw_constraint_step(substream->runtime, 0,
49 SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 16);
51 mtk_regmap_update_bits(afe->regmap, memif->data->agent_disable_reg,
52 1, 0, memif->data->agent_disable_shift);
54 snd_soc_set_runtime_hwparams(substream, mtk_afe_hardware);
57 * Capture cannot use ping-pong buffer since hw_ptr at IRQ may be
58 * smaller than period_size due to AFE's internal buffer.
59 * This easily leads to overrun when avail_min is period_size.
60 * One more period can hold the possible unread buffer.
62 if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
63 int periods_max = mtk_afe_hardware->periods_max;
65 ret = snd_pcm_hw_constraint_minmax(runtime,
66 SNDRV_PCM_HW_PARAM_PERIODS,
69 dev_err(afe->dev, "hw_constraint_minmax failed\n");
74 ret = snd_pcm_hw_constraint_integer(runtime,
75 SNDRV_PCM_HW_PARAM_PERIODS);
77 dev_err(afe->dev, "snd_pcm_hw_constraint_integer failed\n");
79 /* dynamic allocate irq to memif */
80 if (memif->irq_usage < 0) {
81 int irq_id = mtk_dynamic_irq_acquire(afe);
83 if (irq_id != afe->irqs_size) {
85 memif->irq_usage = irq_id;
87 dev_err(afe->dev, "%s() error: no more asys irq\n",
94 EXPORT_SYMBOL_GPL(mtk_afe_fe_startup);
96 void mtk_afe_fe_shutdown(struct snd_pcm_substream *substream,
97 struct snd_soc_dai *dai)
99 struct snd_soc_pcm_runtime *rtd = substream->private_data;
100 struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
101 struct mtk_base_afe_memif *memif = &afe->memif[rtd->cpu_dai->id];
104 irq_id = memif->irq_usage;
106 mtk_regmap_update_bits(afe->regmap, memif->data->agent_disable_reg,
107 1, 1, memif->data->agent_disable_shift);
109 if (!memif->const_irq) {
110 mtk_dynamic_irq_release(afe, irq_id);
111 memif->irq_usage = -1;
112 memif->substream = NULL;
115 EXPORT_SYMBOL_GPL(mtk_afe_fe_shutdown);
117 int mtk_afe_fe_hw_params(struct snd_pcm_substream *substream,
118 struct snd_pcm_hw_params *params,
119 struct snd_soc_dai *dai)
121 struct snd_soc_pcm_runtime *rtd = substream->private_data;
122 struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
123 struct mtk_base_afe_memif *memif = &afe->memif[rtd->cpu_dai->id];
124 int msb_at_bit33 = 0;
127 ret = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));
131 msb_at_bit33 = upper_32_bits(substream->runtime->dma_addr) ? 1 : 0;
132 memif->phys_buf_addr = lower_32_bits(substream->runtime->dma_addr);
133 memif->buffer_size = substream->runtime->dma_bytes;
136 mtk_regmap_write(afe->regmap, memif->data->reg_ofs_base,
137 memif->phys_buf_addr);
139 mtk_regmap_write(afe->regmap,
140 memif->data->reg_ofs_base + AFE_BASE_END_OFFSET,
141 memif->phys_buf_addr + memif->buffer_size - 1);
143 /* set MSB to 33-bit */
144 mtk_regmap_update_bits(afe->regmap, memif->data->msb_reg,
145 1, msb_at_bit33, memif->data->msb_shift);
148 if (memif->data->mono_shift >= 0) {
149 unsigned int mono = (params_channels(params) == 1) ? 1 : 0;
151 mtk_regmap_update_bits(afe->regmap, memif->data->mono_reg,
152 1, mono, memif->data->mono_shift);
156 if (memif->data->fs_shift < 0)
159 fs = afe->memif_fs(substream, params_rate(params));
164 mtk_regmap_update_bits(afe->regmap, memif->data->fs_reg,
165 memif->data->fs_maskbit, fs,
166 memif->data->fs_shift);
170 EXPORT_SYMBOL_GPL(mtk_afe_fe_hw_params);
172 int mtk_afe_fe_hw_free(struct snd_pcm_substream *substream,
173 struct snd_soc_dai *dai)
175 return snd_pcm_lib_free_pages(substream);
177 EXPORT_SYMBOL_GPL(mtk_afe_fe_hw_free);
179 int mtk_afe_fe_trigger(struct snd_pcm_substream *substream, int cmd,
180 struct snd_soc_dai *dai)
182 struct snd_soc_pcm_runtime *rtd = substream->private_data;
183 struct snd_pcm_runtime * const runtime = substream->runtime;
184 struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
185 struct mtk_base_afe_memif *memif = &afe->memif[rtd->cpu_dai->id];
186 struct mtk_base_afe_irq *irqs = &afe->irqs[memif->irq_usage];
187 const struct mtk_base_irq_data *irq_data = irqs->irq_data;
188 unsigned int counter = runtime->period_size;
191 dev_dbg(afe->dev, "%s %s cmd=%d\n", __func__, memif->data->name, cmd);
194 case SNDRV_PCM_TRIGGER_START:
195 case SNDRV_PCM_TRIGGER_RESUME:
196 mtk_regmap_update_bits(afe->regmap,
197 memif->data->enable_reg,
198 1, 1, memif->data->enable_shift);
200 /* set irq counter */
201 mtk_regmap_update_bits(afe->regmap, irq_data->irq_cnt_reg,
202 irq_data->irq_cnt_maskbit, counter,
203 irq_data->irq_cnt_shift);
206 fs = afe->irq_fs(substream, runtime->rate);
211 mtk_regmap_update_bits(afe->regmap, irq_data->irq_fs_reg,
212 irq_data->irq_fs_maskbit, fs,
213 irq_data->irq_fs_shift);
215 /* enable interrupt */
216 mtk_regmap_update_bits(afe->regmap, irq_data->irq_en_reg,
217 1, 1, irq_data->irq_en_shift);
220 case SNDRV_PCM_TRIGGER_STOP:
221 case SNDRV_PCM_TRIGGER_SUSPEND:
222 mtk_regmap_update_bits(afe->regmap, memif->data->enable_reg,
223 1, 0, memif->data->enable_shift);
224 /* disable interrupt */
225 mtk_regmap_update_bits(afe->regmap, irq_data->irq_en_reg,
226 1, 0, irq_data->irq_en_shift);
227 /* and clear pending IRQ */
228 mtk_regmap_write(afe->regmap, irq_data->irq_clr_reg,
229 1 << irq_data->irq_clr_shift);
235 EXPORT_SYMBOL_GPL(mtk_afe_fe_trigger);
237 int mtk_afe_fe_prepare(struct snd_pcm_substream *substream,
238 struct snd_soc_dai *dai)
240 struct snd_soc_pcm_runtime *rtd = substream->private_data;
241 struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
242 struct mtk_base_afe_memif *memif = &afe->memif[rtd->cpu_dai->id];
247 switch (substream->runtime->format) {
248 case SNDRV_PCM_FORMAT_S16_LE:
251 case SNDRV_PCM_FORMAT_S32_LE:
255 case SNDRV_PCM_FORMAT_S24_LE:
259 dev_err(afe->dev, "%s() error: unsupported format %d\n",
260 __func__, substream->runtime->format);
264 mtk_regmap_update_bits(afe->regmap, memif->data->hd_reg,
265 1, hd_audio, memif->data->hd_shift);
267 mtk_regmap_update_bits(afe->regmap, memif->data->hd_align_reg,
268 1, hd_align, memif->data->hd_align_mshift);
272 EXPORT_SYMBOL_GPL(mtk_afe_fe_prepare);
274 const struct snd_soc_dai_ops mtk_afe_fe_ops = {
275 .startup = mtk_afe_fe_startup,
276 .shutdown = mtk_afe_fe_shutdown,
277 .hw_params = mtk_afe_fe_hw_params,
278 .hw_free = mtk_afe_fe_hw_free,
279 .prepare = mtk_afe_fe_prepare,
280 .trigger = mtk_afe_fe_trigger,
282 EXPORT_SYMBOL_GPL(mtk_afe_fe_ops);
284 static DEFINE_MUTEX(irqs_lock);
285 int mtk_dynamic_irq_acquire(struct mtk_base_afe *afe)
289 mutex_lock(&afe->irq_alloc_lock);
290 for (i = 0; i < afe->irqs_size; ++i) {
291 if (afe->irqs[i].irq_occupyed == 0) {
292 afe->irqs[i].irq_occupyed = 1;
293 mutex_unlock(&afe->irq_alloc_lock);
297 mutex_unlock(&afe->irq_alloc_lock);
298 return afe->irqs_size;
300 EXPORT_SYMBOL_GPL(mtk_dynamic_irq_acquire);
302 int mtk_dynamic_irq_release(struct mtk_base_afe *afe, int irq_id)
304 mutex_lock(&afe->irq_alloc_lock);
305 if (irq_id >= 0 && irq_id < afe->irqs_size) {
306 afe->irqs[irq_id].irq_occupyed = 0;
307 mutex_unlock(&afe->irq_alloc_lock);
310 mutex_unlock(&afe->irq_alloc_lock);
313 EXPORT_SYMBOL_GPL(mtk_dynamic_irq_release);
315 int mtk_afe_dai_suspend(struct snd_soc_dai *dai)
317 struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
318 struct device *dev = afe->dev;
319 struct regmap *regmap = afe->regmap;
322 if (pm_runtime_status_suspended(dev) || afe->suspended)
325 if (!afe->reg_back_up)
327 devm_kcalloc(dev, afe->reg_back_up_list_num,
328 sizeof(unsigned int), GFP_KERNEL);
330 for (i = 0; i < afe->reg_back_up_list_num; i++)
331 regmap_read(regmap, afe->reg_back_up_list[i],
332 &afe->reg_back_up[i]);
334 afe->suspended = true;
335 afe->runtime_suspend(dev);
338 EXPORT_SYMBOL_GPL(mtk_afe_dai_suspend);
340 int mtk_afe_dai_resume(struct snd_soc_dai *dai)
342 struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
343 struct device *dev = afe->dev;
344 struct regmap *regmap = afe->regmap;
347 if (pm_runtime_status_suspended(dev) || !afe->suspended)
350 afe->runtime_resume(dev);
352 if (!afe->reg_back_up)
353 dev_dbg(dev, "%s no reg_backup\n", __func__);
355 for (i = 0; i < afe->reg_back_up_list_num; i++)
356 mtk_regmap_write(regmap, afe->reg_back_up_list[i],
357 afe->reg_back_up[i]);
359 afe->suspended = false;
362 EXPORT_SYMBOL_GPL(mtk_afe_dai_resume);
364 MODULE_DESCRIPTION("Mediatek simple fe dai operator");
365 MODULE_AUTHOR("Garlic Tseng <garlic.tseng@mediatek.com>");
366 MODULE_LICENSE("GPL v2");