Merge branch 'next' into for-linus
[sfrench/cifs-2.6.git] / sound / soc / mediatek / common / mtk-afe-fe-dai.c
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
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
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
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
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
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
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
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
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
245         /* set hd mode */
246         switch (substream->runtime->format) {
247         case SNDRV_PCM_FORMAT_S16_LE:
248                 hd_audio = 0;
249                 break;
250         case SNDRV_PCM_FORMAT_S32_LE:
251                 hd_audio = 1;
252                 break;
253         case SNDRV_PCM_FORMAT_S24_LE:
254                 hd_audio = 1;
255                 break;
256         default:
257                 dev_err(afe->dev, "%s() error: unsupported format %d\n",
258                         __func__, substream->runtime->format);
259                 break;
260         }
261
262         mtk_regmap_update_bits(afe->regmap, memif->data->hd_reg,
263                                1, hd_audio, memif->data->hd_shift);
264
265         return 0;
266 }
267 EXPORT_SYMBOL_GPL(mtk_afe_fe_prepare);
268
269 const struct snd_soc_dai_ops mtk_afe_fe_ops = {
270         .startup        = mtk_afe_fe_startup,
271         .shutdown       = mtk_afe_fe_shutdown,
272         .hw_params      = mtk_afe_fe_hw_params,
273         .hw_free        = mtk_afe_fe_hw_free,
274         .prepare        = mtk_afe_fe_prepare,
275         .trigger        = mtk_afe_fe_trigger,
276 };
277 EXPORT_SYMBOL_GPL(mtk_afe_fe_ops);
278
279 static DEFINE_MUTEX(irqs_lock);
280 int mtk_dynamic_irq_acquire(struct mtk_base_afe *afe)
281 {
282         int i;
283
284         mutex_lock(&afe->irq_alloc_lock);
285         for (i = 0; i < afe->irqs_size; ++i) {
286                 if (afe->irqs[i].irq_occupyed == 0) {
287                         afe->irqs[i].irq_occupyed = 1;
288                         mutex_unlock(&afe->irq_alloc_lock);
289                         return i;
290                 }
291         }
292         mutex_unlock(&afe->irq_alloc_lock);
293         return afe->irqs_size;
294 }
295 EXPORT_SYMBOL_GPL(mtk_dynamic_irq_acquire);
296
297 int mtk_dynamic_irq_release(struct mtk_base_afe *afe, int irq_id)
298 {
299         mutex_lock(&afe->irq_alloc_lock);
300         if (irq_id >= 0 && irq_id < afe->irqs_size) {
301                 afe->irqs[irq_id].irq_occupyed = 0;
302                 mutex_unlock(&afe->irq_alloc_lock);
303                 return 0;
304         }
305         mutex_unlock(&afe->irq_alloc_lock);
306         return -EINVAL;
307 }
308 EXPORT_SYMBOL_GPL(mtk_dynamic_irq_release);
309
310 int mtk_afe_dai_suspend(struct snd_soc_dai *dai)
311 {
312         struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
313         struct device *dev = afe->dev;
314         struct regmap *regmap = afe->regmap;
315         int i;
316
317         if (pm_runtime_status_suspended(dev) || afe->suspended)
318                 return 0;
319
320         if (!afe->reg_back_up)
321                 afe->reg_back_up =
322                         devm_kcalloc(dev, afe->reg_back_up_list_num,
323                                      sizeof(unsigned int), GFP_KERNEL);
324
325         for (i = 0; i < afe->reg_back_up_list_num; i++)
326                 regmap_read(regmap, afe->reg_back_up_list[i],
327                             &afe->reg_back_up[i]);
328
329         afe->suspended = true;
330         afe->runtime_suspend(dev);
331         return 0;
332 }
333 EXPORT_SYMBOL_GPL(mtk_afe_dai_suspend);
334
335 int mtk_afe_dai_resume(struct snd_soc_dai *dai)
336 {
337         struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
338         struct device *dev = afe->dev;
339         struct regmap *regmap = afe->regmap;
340         int i = 0;
341
342         if (pm_runtime_status_suspended(dev) || !afe->suspended)
343                 return 0;
344
345         afe->runtime_resume(dev);
346
347         if (!afe->reg_back_up)
348                 dev_dbg(dev, "%s no reg_backup\n", __func__);
349
350         for (i = 0; i < afe->reg_back_up_list_num; i++)
351                 mtk_regmap_write(regmap, afe->reg_back_up_list[i],
352                                  afe->reg_back_up[i]);
353
354         afe->suspended = false;
355         return 0;
356 }
357 EXPORT_SYMBOL_GPL(mtk_afe_dai_resume);
358
359 MODULE_DESCRIPTION("Mediatek simple fe dai operator");
360 MODULE_AUTHOR("Garlic Tseng <garlic.tseng@mediatek.com>");
361 MODULE_LICENSE("GPL v2");