1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * mtk-afe-fe-dais.c -- Mediatek afe fe dai operator
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/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"
16
17 #define AFE_BASE_END_OFFSET 8
18
mtk_regmap_update_bits(struct regmap * map,int reg,unsigned int mask,unsigned int val,int shift)19 static int mtk_regmap_update_bits(struct regmap *map, int reg,
20 unsigned int mask,
21 unsigned int val, int shift)
22 {
23 if (reg < 0 || WARN_ON_ONCE(shift < 0))
24 return 0;
25 return regmap_update_bits(map, reg, mask << shift, val << shift);
26 }
27
mtk_regmap_write(struct regmap * map,int reg,unsigned int val)28 static int mtk_regmap_write(struct regmap *map, int reg, unsigned int val)
29 {
30 if (reg < 0)
31 return 0;
32 return regmap_write(map, reg, val);
33 }
34
mtk_afe_fe_startup(struct snd_pcm_substream * substream,struct snd_soc_dai * dai)35 int mtk_afe_fe_startup(struct snd_pcm_substream *substream,
36 struct snd_soc_dai *dai)
37 {
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;
44 int ret;
45
46 memif->substream = substream;
47
48 snd_pcm_hw_constraint_step(substream->runtime, 0,
49 SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 16);
50 /* enable agent */
51 mtk_regmap_update_bits(afe->regmap, memif->data->agent_disable_reg,
52 1, 0, memif->data->agent_disable_shift);
53
54 snd_soc_set_runtime_hwparams(substream, mtk_afe_hardware);
55
56 /*
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.
61 */
62 if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
63 int periods_max = mtk_afe_hardware->periods_max;
64
65 ret = snd_pcm_hw_constraint_minmax(runtime,
66 SNDRV_PCM_HW_PARAM_PERIODS,
67 3, periods_max);
68 if (ret < 0) {
69 dev_err(afe->dev, "hw_constraint_minmax failed\n");
70 return ret;
71 }
72 }
73
74 ret = snd_pcm_hw_constraint_integer(runtime,
75 SNDRV_PCM_HW_PARAM_PERIODS);
76 if (ret < 0)
77 dev_err(afe->dev, "snd_pcm_hw_constraint_integer failed\n");
78
79 /* dynamic allocate irq to memif */
80 if (memif->irq_usage < 0) {
81 int irq_id = mtk_dynamic_irq_acquire(afe);
82
83 if (irq_id != afe->irqs_size) {
84 /* link */
85 memif->irq_usage = irq_id;
86 } else {
87 dev_err(afe->dev, "%s() error: no more asys irq\n",
88 __func__);
89 ret = -EBUSY;
90 }
91 }
92 return ret;
93 }
94 EXPORT_SYMBOL_GPL(mtk_afe_fe_startup);
95
mtk_afe_fe_shutdown(struct snd_pcm_substream * substream,struct snd_soc_dai * dai)96 void mtk_afe_fe_shutdown(struct snd_pcm_substream *substream,
97 struct snd_soc_dai *dai)
98 {
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];
102 int irq_id;
103
104 irq_id = memif->irq_usage;
105
106 mtk_regmap_update_bits(afe->regmap, memif->data->agent_disable_reg,
107 1, 1, memif->data->agent_disable_shift);
108
109 if (!memif->const_irq) {
110 mtk_dynamic_irq_release(afe, irq_id);
111 memif->irq_usage = -1;
112 memif->substream = NULL;
113 }
114 }
115 EXPORT_SYMBOL_GPL(mtk_afe_fe_shutdown);
116
mtk_afe_fe_hw_params(struct snd_pcm_substream * substream,struct snd_pcm_hw_params * params,struct snd_soc_dai * dai)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)
120 {
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;
125 int ret, fs = 0;
126
127 ret = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));
128 if (ret < 0)
129 return ret;
130
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;
134
135 /* start */
136 mtk_regmap_write(afe->regmap, memif->data->reg_ofs_base,
137 memif->phys_buf_addr);
138 /* end */
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);
142
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);
146
147 /* set channel */
148 if (memif->data->mono_shift >= 0) {
149 unsigned int mono = (params_channels(params) == 1) ? 1 : 0;
150
151 mtk_regmap_update_bits(afe->regmap, memif->data->mono_reg,
152 1, mono, memif->data->mono_shift);
153 }
154
155 /* set rate */
156 if (memif->data->fs_shift < 0)
157 return 0;
158
159 fs = afe->memif_fs(substream, params_rate(params));
160
161 if (fs < 0)
162 return -EINVAL;
163
164 mtk_regmap_update_bits(afe->regmap, memif->data->fs_reg,
165 memif->data->fs_maskbit, fs,
166 memif->data->fs_shift);
167
168 return 0;
169 }
170 EXPORT_SYMBOL_GPL(mtk_afe_fe_hw_params);
171
mtk_afe_fe_hw_free(struct snd_pcm_substream * substream,struct snd_soc_dai * dai)172 int mtk_afe_fe_hw_free(struct snd_pcm_substream *substream,
173 struct snd_soc_dai *dai)
174 {
175 return snd_pcm_lib_free_pages(substream);
176 }
177 EXPORT_SYMBOL_GPL(mtk_afe_fe_hw_free);
178
mtk_afe_fe_trigger(struct snd_pcm_substream * substream,int cmd,struct snd_soc_dai * dai)179 int mtk_afe_fe_trigger(struct snd_pcm_substream *substream, int cmd,
180 struct snd_soc_dai *dai)
181 {
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;
189 int fs;
190
191 dev_dbg(afe->dev, "%s %s cmd=%d\n", __func__, memif->data->name, cmd);
192
193 switch (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);
199
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);
204
205 /* set irq fs */
206 fs = afe->irq_fs(substream, runtime->rate);
207
208 if (fs < 0)
209 return -EINVAL;
210
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);
214
215 /* enable interrupt */
216 mtk_regmap_update_bits(afe->regmap, irq_data->irq_en_reg,
217 1, 1, irq_data->irq_en_shift);
218
219 return 0;
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);
230 return 0;
231 default:
232 return -EINVAL;
233 }
234 }
235 EXPORT_SYMBOL_GPL(mtk_afe_fe_trigger);
236
mtk_afe_fe_prepare(struct snd_pcm_substream * substream,struct snd_soc_dai * dai)237 int mtk_afe_fe_prepare(struct snd_pcm_substream *substream,
238 struct snd_soc_dai *dai)
239 {
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];
243 int hd_audio = 0;
244 int hd_align = 0;
245
246 /* set hd mode */
247 switch (substream->runtime->format) {
248 case SNDRV_PCM_FORMAT_S16_LE:
249 hd_audio = 0;
250 break;
251 case SNDRV_PCM_FORMAT_S32_LE:
252 hd_audio = 1;
253 hd_align = 1;
254 break;
255 case SNDRV_PCM_FORMAT_S24_LE:
256 hd_audio = 1;
257 break;
258 default:
259 dev_err(afe->dev, "%s() error: unsupported format %d\n",
260 __func__, substream->runtime->format);
261 break;
262 }
263
264 mtk_regmap_update_bits(afe->regmap, memif->data->hd_reg,
265 1, hd_audio, memif->data->hd_shift);
266
267 mtk_regmap_update_bits(afe->regmap, memif->data->hd_align_reg,
268 1, hd_align, memif->data->hd_align_mshift);
269
270 return 0;
271 }
272 EXPORT_SYMBOL_GPL(mtk_afe_fe_prepare);
273
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,
281 };
282 EXPORT_SYMBOL_GPL(mtk_afe_fe_ops);
283
284 static DEFINE_MUTEX(irqs_lock);
mtk_dynamic_irq_acquire(struct mtk_base_afe * afe)285 int mtk_dynamic_irq_acquire(struct mtk_base_afe *afe)
286 {
287 int i;
288
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);
294 return i;
295 }
296 }
297 mutex_unlock(&afe->irq_alloc_lock);
298 return afe->irqs_size;
299 }
300 EXPORT_SYMBOL_GPL(mtk_dynamic_irq_acquire);
301
mtk_dynamic_irq_release(struct mtk_base_afe * afe,int irq_id)302 int mtk_dynamic_irq_release(struct mtk_base_afe *afe, int irq_id)
303 {
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);
308 return 0;
309 }
310 mutex_unlock(&afe->irq_alloc_lock);
311 return -EINVAL;
312 }
313 EXPORT_SYMBOL_GPL(mtk_dynamic_irq_release);
314
mtk_afe_dai_suspend(struct snd_soc_dai * dai)315 int mtk_afe_dai_suspend(struct snd_soc_dai *dai)
316 {
317 struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
318 struct device *dev = afe->dev;
319 struct regmap *regmap = afe->regmap;
320 int i;
321
322 if (pm_runtime_status_suspended(dev) || afe->suspended)
323 return 0;
324
325 if (!afe->reg_back_up)
326 afe->reg_back_up =
327 devm_kcalloc(dev, afe->reg_back_up_list_num,
328 sizeof(unsigned int), GFP_KERNEL);
329
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]);
333
334 afe->suspended = true;
335 afe->runtime_suspend(dev);
336 return 0;
337 }
338 EXPORT_SYMBOL_GPL(mtk_afe_dai_suspend);
339
mtk_afe_dai_resume(struct snd_soc_dai * dai)340 int mtk_afe_dai_resume(struct snd_soc_dai *dai)
341 {
342 struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
343 struct device *dev = afe->dev;
344 struct regmap *regmap = afe->regmap;
345 int i = 0;
346
347 if (pm_runtime_status_suspended(dev) || !afe->suspended)
348 return 0;
349
350 afe->runtime_resume(dev);
351
352 if (!afe->reg_back_up)
353 dev_dbg(dev, "%s no reg_backup\n", __func__);
354
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]);
358
359 afe->suspended = false;
360 return 0;
361 }
362 EXPORT_SYMBOL_GPL(mtk_afe_dai_resume);
363
364 MODULE_DESCRIPTION("Mediatek simple fe dai operator");
365 MODULE_AUTHOR("Garlic Tseng <garlic.tseng@mediatek.com>");
366 MODULE_LICENSE("GPL v2");
367