2 * mtk-afe-fe-dais.c -- Mediatek afe fe dai operator
4 * Copyright (c) 2016 MediaTek Inc.
5 * Author: Garlic Tseng <garlic.tseng@mediatek.com>
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 and
9 * only version 2 as published by the Free Software Foundation.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
17 #include <linux/module.h>
18 #include <linux/pm_runtime.h>
19 #include <linux/regmap.h>
20 #include <sound/soc.h>
21 #include "mtk-afe-fe-dai.h"
22 #include "mtk-base-afe.h"
24 #define AFE_BASE_END_OFFSET 8
26 int mtk_regmap_update_bits(struct regmap
*map
, int reg
, unsigned int mask
,
31 return regmap_update_bits(map
, reg
, mask
, val
);
34 int mtk_regmap_write(struct regmap
*map
, int reg
, unsigned int val
)
38 return regmap_write(map
, reg
, val
);
41 int mtk_afe_fe_startup(struct snd_pcm_substream
*substream
,
42 struct snd_soc_dai
*dai
)
44 struct snd_soc_pcm_runtime
*rtd
= substream
->private_data
;
45 struct mtk_base_afe
*afe
= snd_soc_platform_get_drvdata(rtd
->platform
);
46 struct snd_pcm_runtime
*runtime
= substream
->runtime
;
47 int memif_num
= rtd
->cpu_dai
->id
;
48 struct mtk_base_afe_memif
*memif
= &afe
->memif
[memif_num
];
49 const struct snd_pcm_hardware
*mtk_afe_hardware
= afe
->mtk_afe_hardware
;
52 memif
->substream
= substream
;
54 snd_pcm_hw_constraint_step(substream
->runtime
, 0,
55 SNDRV_PCM_HW_PARAM_BUFFER_BYTES
, 16);
57 mtk_regmap_update_bits(afe
->regmap
, memif
->data
->agent_disable_reg
,
58 1 << memif
->data
->agent_disable_shift
,
59 0 << memif
->data
->agent_disable_shift
);
61 snd_soc_set_runtime_hwparams(substream
, mtk_afe_hardware
);
64 * Capture cannot use ping-pong buffer since hw_ptr at IRQ may be
65 * smaller than period_size due to AFE's internal buffer.
66 * This easily leads to overrun when avail_min is period_size.
67 * One more period can hold the possible unread buffer.
69 if (substream
->stream
== SNDRV_PCM_STREAM_CAPTURE
) {
70 int periods_max
= mtk_afe_hardware
->periods_max
;
72 ret
= snd_pcm_hw_constraint_minmax(runtime
,
73 SNDRV_PCM_HW_PARAM_PERIODS
,
76 dev_err(afe
->dev
, "hw_constraint_minmax failed\n");
81 ret
= snd_pcm_hw_constraint_integer(runtime
,
82 SNDRV_PCM_HW_PARAM_PERIODS
);
84 dev_err(afe
->dev
, "snd_pcm_hw_constraint_integer failed\n");
86 /* dynamic allocate irq to memif */
87 if (memif
->irq_usage
< 0) {
88 int irq_id
= mtk_dynamic_irq_acquire(afe
);
90 if (irq_id
!= afe
->irqs_size
) {
92 memif
->irq_usage
= irq_id
;
94 dev_err(afe
->dev
, "%s() error: no more asys irq\n",
101 EXPORT_SYMBOL_GPL(mtk_afe_fe_startup
);
103 void mtk_afe_fe_shutdown(struct snd_pcm_substream
*substream
,
104 struct snd_soc_dai
*dai
)
106 struct snd_soc_pcm_runtime
*rtd
= substream
->private_data
;
107 struct mtk_base_afe
*afe
= snd_soc_platform_get_drvdata(rtd
->platform
);
108 struct mtk_base_afe_memif
*memif
= &afe
->memif
[rtd
->cpu_dai
->id
];
111 irq_id
= memif
->irq_usage
;
113 mtk_regmap_update_bits(afe
->regmap
, memif
->data
->agent_disable_reg
,
114 1 << memif
->data
->agent_disable_shift
,
115 1 << memif
->data
->agent_disable_shift
);
117 if (!memif
->const_irq
) {
118 mtk_dynamic_irq_release(afe
, irq_id
);
119 memif
->irq_usage
= -1;
120 memif
->substream
= NULL
;
123 EXPORT_SYMBOL_GPL(mtk_afe_fe_shutdown
);
125 int mtk_afe_fe_hw_params(struct snd_pcm_substream
*substream
,
126 struct snd_pcm_hw_params
*params
,
127 struct snd_soc_dai
*dai
)
129 struct snd_soc_pcm_runtime
*rtd
= substream
->private_data
;
130 struct mtk_base_afe
*afe
= snd_soc_platform_get_drvdata(rtd
->platform
);
131 struct mtk_base_afe_memif
*memif
= &afe
->memif
[rtd
->cpu_dai
->id
];
132 int msb_at_bit33
= 0;
135 ret
= snd_pcm_lib_malloc_pages(substream
, params_buffer_bytes(params
));
139 msb_at_bit33
= upper_32_bits(substream
->runtime
->dma_addr
) ? 1 : 0;
140 memif
->phys_buf_addr
= lower_32_bits(substream
->runtime
->dma_addr
);
141 memif
->buffer_size
= substream
->runtime
->dma_bytes
;
144 mtk_regmap_write(afe
->regmap
, memif
->data
->reg_ofs_base
,
145 memif
->phys_buf_addr
);
147 mtk_regmap_write(afe
->regmap
,
148 memif
->data
->reg_ofs_base
+ AFE_BASE_END_OFFSET
,
149 memif
->phys_buf_addr
+ memif
->buffer_size
- 1);
151 /* set MSB to 33-bit */
152 mtk_regmap_update_bits(afe
->regmap
, memif
->data
->msb_reg
,
153 1 << memif
->data
->msb_shift
,
154 msb_at_bit33
<< memif
->data
->msb_shift
);
157 if (memif
->data
->mono_shift
>= 0) {
158 unsigned int mono
= (params_channels(params
) == 1) ? 1 : 0;
160 mtk_regmap_update_bits(afe
->regmap
, memif
->data
->mono_reg
,
161 1 << memif
->data
->mono_shift
,
162 mono
<< memif
->data
->mono_shift
);
166 if (memif
->data
->fs_shift
< 0)
169 fs
= afe
->memif_fs(substream
, params_rate(params
));
174 mtk_regmap_update_bits(afe
->regmap
, memif
->data
->fs_reg
,
175 memif
->data
->fs_maskbit
<< memif
->data
->fs_shift
,
176 fs
<< memif
->data
->fs_shift
);
180 EXPORT_SYMBOL_GPL(mtk_afe_fe_hw_params
);
182 int mtk_afe_fe_hw_free(struct snd_pcm_substream
*substream
,
183 struct snd_soc_dai
*dai
)
185 return snd_pcm_lib_free_pages(substream
);
187 EXPORT_SYMBOL_GPL(mtk_afe_fe_hw_free
);
189 int mtk_afe_fe_trigger(struct snd_pcm_substream
*substream
, int cmd
,
190 struct snd_soc_dai
*dai
)
192 struct snd_soc_pcm_runtime
*rtd
= substream
->private_data
;
193 struct snd_pcm_runtime
* const runtime
= substream
->runtime
;
194 struct mtk_base_afe
*afe
= snd_soc_platform_get_drvdata(rtd
->platform
);
195 struct mtk_base_afe_memif
*memif
= &afe
->memif
[rtd
->cpu_dai
->id
];
196 struct mtk_base_afe_irq
*irqs
= &afe
->irqs
[memif
->irq_usage
];
197 const struct mtk_base_irq_data
*irq_data
= irqs
->irq_data
;
198 unsigned int counter
= runtime
->period_size
;
201 dev_dbg(afe
->dev
, "%s %s cmd=%d\n", __func__
, memif
->data
->name
, cmd
);
204 case SNDRV_PCM_TRIGGER_START
:
205 case SNDRV_PCM_TRIGGER_RESUME
:
206 if (memif
->data
->enable_shift
>= 0)
207 mtk_regmap_update_bits(afe
->regmap
,
208 memif
->data
->enable_reg
,
209 1 << memif
->data
->enable_shift
,
210 1 << memif
->data
->enable_shift
);
212 /* set irq counter */
213 mtk_regmap_update_bits(afe
->regmap
, irq_data
->irq_cnt_reg
,
214 irq_data
->irq_cnt_maskbit
215 << irq_data
->irq_cnt_shift
,
216 counter
<< irq_data
->irq_cnt_shift
);
219 fs
= afe
->irq_fs(substream
, runtime
->rate
);
224 mtk_regmap_update_bits(afe
->regmap
, irq_data
->irq_fs_reg
,
225 irq_data
->irq_fs_maskbit
226 << irq_data
->irq_fs_shift
,
227 fs
<< irq_data
->irq_fs_shift
);
229 /* enable interrupt */
230 mtk_regmap_update_bits(afe
->regmap
, irq_data
->irq_en_reg
,
231 1 << irq_data
->irq_en_shift
,
232 1 << irq_data
->irq_en_shift
);
235 case SNDRV_PCM_TRIGGER_STOP
:
236 case SNDRV_PCM_TRIGGER_SUSPEND
:
237 mtk_regmap_update_bits(afe
->regmap
, memif
->data
->enable_reg
,
238 1 << memif
->data
->enable_shift
, 0);
239 /* disable interrupt */
240 mtk_regmap_update_bits(afe
->regmap
, irq_data
->irq_en_reg
,
241 1 << irq_data
->irq_en_shift
,
242 0 << irq_data
->irq_en_shift
);
243 /* and clear pending IRQ */
244 mtk_regmap_write(afe
->regmap
, irq_data
->irq_clr_reg
,
245 1 << irq_data
->irq_clr_shift
);
251 EXPORT_SYMBOL_GPL(mtk_afe_fe_trigger
);
253 int mtk_afe_fe_prepare(struct snd_pcm_substream
*substream
,
254 struct snd_soc_dai
*dai
)
256 struct snd_soc_pcm_runtime
*rtd
= substream
->private_data
;
257 struct mtk_base_afe
*afe
= snd_soc_platform_get_drvdata(rtd
->platform
);
258 struct mtk_base_afe_memif
*memif
= &afe
->memif
[rtd
->cpu_dai
->id
];
262 switch (substream
->runtime
->format
) {
263 case SNDRV_PCM_FORMAT_S16_LE
:
266 case SNDRV_PCM_FORMAT_S32_LE
:
269 case SNDRV_PCM_FORMAT_S24_LE
:
273 dev_err(afe
->dev
, "%s() error: unsupported format %d\n",
274 __func__
, substream
->runtime
->format
);
278 mtk_regmap_update_bits(afe
->regmap
, memif
->data
->hd_reg
,
279 1 << memif
->data
->hd_shift
,
280 hd_audio
<< memif
->data
->hd_shift
);
284 EXPORT_SYMBOL_GPL(mtk_afe_fe_prepare
);
286 const struct snd_soc_dai_ops mtk_afe_fe_ops
= {
287 .startup
= mtk_afe_fe_startup
,
288 .shutdown
= mtk_afe_fe_shutdown
,
289 .hw_params
= mtk_afe_fe_hw_params
,
290 .hw_free
= mtk_afe_fe_hw_free
,
291 .prepare
= mtk_afe_fe_prepare
,
292 .trigger
= mtk_afe_fe_trigger
,
294 EXPORT_SYMBOL_GPL(mtk_afe_fe_ops
);
296 static DEFINE_MUTEX(irqs_lock
);
297 int mtk_dynamic_irq_acquire(struct mtk_base_afe
*afe
)
301 mutex_lock(&afe
->irq_alloc_lock
);
302 for (i
= 0; i
< afe
->irqs_size
; ++i
) {
303 if (afe
->irqs
[i
].irq_occupyed
== 0) {
304 afe
->irqs
[i
].irq_occupyed
= 1;
305 mutex_unlock(&afe
->irq_alloc_lock
);
309 mutex_unlock(&afe
->irq_alloc_lock
);
310 return afe
->irqs_size
;
312 EXPORT_SYMBOL_GPL(mtk_dynamic_irq_acquire
);
314 int mtk_dynamic_irq_release(struct mtk_base_afe
*afe
, int irq_id
)
316 mutex_lock(&afe
->irq_alloc_lock
);
317 if (irq_id
>= 0 && irq_id
< afe
->irqs_size
) {
318 afe
->irqs
[irq_id
].irq_occupyed
= 0;
319 mutex_unlock(&afe
->irq_alloc_lock
);
322 mutex_unlock(&afe
->irq_alloc_lock
);
325 EXPORT_SYMBOL_GPL(mtk_dynamic_irq_release
);
327 int mtk_afe_dai_suspend(struct snd_soc_dai
*dai
)
329 struct mtk_base_afe
*afe
= dev_get_drvdata(dai
->dev
);
330 struct device
*dev
= afe
->dev
;
331 struct regmap
*regmap
= afe
->regmap
;
334 if (pm_runtime_status_suspended(dev
) || afe
->suspended
)
337 if (!afe
->reg_back_up
)
339 devm_kcalloc(dev
, afe
->reg_back_up_list_num
,
340 sizeof(unsigned int), GFP_KERNEL
);
342 for (i
= 0; i
< afe
->reg_back_up_list_num
; i
++)
343 regmap_read(regmap
, afe
->reg_back_up_list
[i
],
344 &afe
->reg_back_up
[i
]);
346 afe
->suspended
= true;
347 afe
->runtime_suspend(dev
);
350 EXPORT_SYMBOL_GPL(mtk_afe_dai_suspend
);
352 int mtk_afe_dai_resume(struct snd_soc_dai
*dai
)
354 struct mtk_base_afe
*afe
= dev_get_drvdata(dai
->dev
);
355 struct device
*dev
= afe
->dev
;
356 struct regmap
*regmap
= afe
->regmap
;
359 if (pm_runtime_status_suspended(dev
) || !afe
->suspended
)
362 afe
->runtime_resume(dev
);
364 if (!afe
->reg_back_up
)
365 dev_dbg(dev
, "%s no reg_backup\n", __func__
);
367 for (i
= 0; i
< afe
->reg_back_up_list_num
; i
++)
368 mtk_regmap_write(regmap
, afe
->reg_back_up_list
[i
],
369 afe
->reg_back_up
[i
]);
371 afe
->suspended
= false;
374 EXPORT_SYMBOL_GPL(mtk_afe_dai_resume
);
376 MODULE_DESCRIPTION("Mediatek simple fe dai operator");
377 MODULE_AUTHOR("Garlic Tseng <garlic.tseng@mediatek.com>");
378 MODULE_LICENSE("GPL v2");