1 /*
2 * Copyright (c) 2019-2025 Allwinner Technology Co., Ltd. ALL rights reserved.
3 *
4 * Allwinner is a trademark of Allwinner Technology Co.,Ltd., registered in
5 * the the people's Republic of China and other countries.
6 * All Allwinner Technology Co.,Ltd. trademarks are used with permission.
7 *
8 * DISCLAIMER
9 * THIRD PARTY LICENCES MAY BE REQUIRED TO IMPLEMENT THE SOLUTION/PRODUCT.
10 * IF YOU NEED TO INTEGRATE THIRD PARTY’S TECHNOLOGY (SONY, DTS, DOLBY, AVS OR MPEGLA, ETC.)
11 * IN ALLWINNERS’SDK OR PRODUCTS, YOU SHALL BE SOLELY RESPONSIBLE TO OBTAIN
12 * ALL APPROPRIATELY REQUIRED THIRD PARTY LICENCES.
13 * ALLWINNER SHALL HAVE NO WARRANTY, INDEMNITY OR OTHER OBLIGATIONS WITH RESPECT TO MATTERS
14 * COVERED UNDER ANY REQUIRED THIRD PARTY LICENSE.
15 * YOU ARE SOLELY RESPONSIBLE FOR YOUR USAGE OF THIRD PARTY’S TECHNOLOGY.
16 *
17 *
18 * THIS SOFTWARE IS PROVIDED BY ALLWINNER"AS IS" AND TO THE MAXIMUM EXTENT
19 * PERMITTED BY LAW, ALLWINNER EXPRESSLY DISCLAIMS ALL WARRANTIES OF ANY KIND,
20 * WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING WITHOUT LIMITATION REGARDING
21 * THE TITLE, NON-INFRINGEMENT, ACCURACY, CONDITION, COMPLETENESS, PERFORMANCE
22 * OR MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
23 * IN NO EVENT SHALL ALLWINNER BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26 * LOSS OF USE, DATA, OR PROFITS, OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
28 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
30 * OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32 #include <hal_timer.h>
33 #include <stdio.h>
34 #include <sys/types.h>
35 #include <sys/stat.h>
36 #include <unistd.h>
37 #include <fcntl.h>
38 #include <errno.h>
39 #include <sound/snd_core.h>
40 #include <sound/snd_pcm.h>
41 #include <sound/snd_dma.h>
42 #include <sound/dma_wrap.h>
43 #include <hal_dma.h>
44 #include <hal_cmd.h>
45
46 #include "sunxi-pcm.h"
47 #include "sunxi-dmic.h"
48
49 static const struct dmic_rate dmic_rate_s[] = {
50 {44100, 0x0},
51 {48000, 0x0},
52 {22050, 0x2},
53 /* KNOT support */
54 {24000, 0x2},
55 {11025, 0x4},
56 {12000, 0x4},
57 {32000, 0x1},
58 {16000, 0x3},
59 {8000, 0x5},
60 };
61
62 /*
63 * Configure DMA , Chan enable & Global enable
64 */
sunxi_dmic_enable(struct snd_platform * platform,bool enable)65 static void sunxi_dmic_enable(struct snd_platform *platform, bool enable)
66 {
67 struct sunxi_dmic_info *sunxi_dmic = platform->private_data;
68
69 snd_print("\n");
70 if (enable) {
71 snd_platform_update_bits(platform, SUNXI_DMIC_INTC,
72 (0x1 << FIFO_DRQ_EN), (0x1 << FIFO_DRQ_EN));
73
74 snd_platform_update_bits(platform, SUNXI_DMIC_EN,
75 (0xFF<<DATA_CH_EN),
76 ((sunxi_dmic->chanmap)<<DATA_CH_EN));
77
78 snd_platform_update_bits(platform, SUNXI_DMIC_EN,
79 (0x1 << GLOBE_EN), (0x1 << GLOBE_EN));
80 } else {
81 snd_platform_update_bits(platform, SUNXI_DMIC_EN,
82 (0x1 << GLOBE_EN), (0x0 << GLOBE_EN));
83 snd_platform_update_bits(platform, SUNXI_DMIC_EN,
84 (0xFF << DATA_CH_EN),
85 (0x0 << DATA_CH_EN));
86 snd_platform_update_bits(platform, SUNXI_DMIC_INTC,
87 (0x1 << FIFO_DRQ_EN),
88 (0x0 << FIFO_DRQ_EN));
89 }
90 }
91
sunxi_dmic_init(struct snd_platform * platform)92 static void sunxi_dmic_init(struct snd_platform *platform)
93 {
94 snd_print("\n");
95 snd_platform_write(platform,
96 SUNXI_DMIC_CH_MAP, DMIC_CHANMAP_DEFAULT);
97 snd_platform_update_bits(platform, SUNXI_DMIC_CTR,
98 (0x7<<DMICDFEN), (0x7<<DMICDFEN));
99
100 /* set the vol */
101 snd_platform_write(platform, SUNXI_DMIC_DATA0_1_VOL, DMIC_DEFAULT_VOL);
102 snd_platform_write(platform, SUNXI_DMIC_DATA2_3_VOL, DMIC_DEFAULT_VOL);
103 }
104
sunxi_dmic_hw_params(struct snd_pcm_substream * substream,struct snd_pcm_hw_params * params,struct snd_dai * dai)105 static int sunxi_dmic_hw_params(struct snd_pcm_substream *substream,
106 struct snd_pcm_hw_params *params, struct snd_dai *dai)
107 {
108 struct snd_platform *platform = dai->component;
109 struct sunxi_dmic_info *sunxi_dmic = platform->private_data;
110 int i;
111
112 snd_print("\n");
113 /* if clk rst */
114 sunxi_dmic_init(platform);
115
116 /* sample resolution & sample fifo format */
117 switch (params_format(params)) {
118 case SNDRV_PCM_FORMAT_S16_LE:
119 snd_platform_update_bits(platform, SUNXI_DMIC_FIFO_CTR,
120 (0x1 << DMIC_SAMPLE_RESOLUTION),
121 (0x0 << DMIC_SAMPLE_RESOLUTION));
122 snd_platform_update_bits(platform, SUNXI_DMIC_FIFO_CTR,
123 (0x1 << DMIC_FIFO_MODE),
124 (0x1 << DMIC_FIFO_MODE));
125 break;
126 case SNDRV_PCM_FORMAT_S24_LE:
127 snd_platform_update_bits(platform, SUNXI_DMIC_FIFO_CTR,
128 (0x1 << DMIC_SAMPLE_RESOLUTION),
129 (0x1 << DMIC_SAMPLE_RESOLUTION));
130 snd_platform_update_bits(platform, SUNXI_DMIC_FIFO_CTR,
131 (0x1 << DMIC_FIFO_MODE),
132 (0x0 << DMIC_FIFO_MODE));
133 break;
134 default:
135 snd_err( "Invalid format set\n");
136 return -EINVAL;
137 }
138
139 for (i = 0; i < ARRAY_SIZE(dmic_rate_s); i++) {
140 if (dmic_rate_s[i].samplerate == params_rate(params)) {
141 snd_platform_update_bits(platform, SUNXI_DMIC_SR,
142 (7<<DMIC_SR), (dmic_rate_s[i].rate_bit<<DMIC_SR));
143 break;
144 }
145 }
146
147 /* oversamplerate adjust */
148 if (params_rate(params) >= 24000) {
149 snd_platform_update_bits(platform, SUNXI_DMIC_CTR,
150 (1<<DMIC_OVERSAMPLE_RATE), (1<<DMIC_OVERSAMPLE_RATE));
151 } else {
152 snd_platform_update_bits(platform, SUNXI_DMIC_CTR,
153 (1<<DMIC_OVERSAMPLE_RATE), (0<<DMIC_OVERSAMPLE_RATE));
154 }
155
156 sunxi_dmic->chanmap = (1<<params_channels(params)) - 1;
157
158 snd_platform_write(platform, SUNXI_DMIC_HPF_CTRL, sunxi_dmic->chanmap);
159
160 /* DMIC num is M+1 */
161 snd_platform_update_bits(platform, SUNXI_DMIC_CH_NUM,
162 (7<<DMIC_CH_NUM), ((params_channels(params)-1)<<DMIC_CH_NUM));
163
164 return 0;
165 }
166
sunxi_dmic_trigger(struct snd_pcm_substream * substream,int cmd,struct snd_dai * dai)167 static int sunxi_dmic_trigger(struct snd_pcm_substream *substream,
168 int cmd, struct snd_dai *dai)
169 {
170 int ret = 0;
171 struct snd_platform *platform = dai->component;
172
173 snd_print("\n");
174 switch (cmd) {
175 case SNDRV_PCM_TRIGGER_START:
176 case SNDRV_PCM_TRIGGER_RESUME:
177 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
178 sunxi_dmic_enable(platform, true);
179 break;
180 case SNDRV_PCM_TRIGGER_STOP:
181 case SNDRV_PCM_TRIGGER_SUSPEND:
182 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
183 sunxi_dmic_enable(platform, false);
184 break;
185 default:
186 ret = -EINVAL;
187 break;
188 }
189
190 return ret;
191 }
192
193 /*
194 * Reset & Flush FIFO
195 */
sunxi_dmic_prepare(struct snd_pcm_substream * substream,struct snd_dai * dai)196 static int sunxi_dmic_prepare(struct snd_pcm_substream *substream,
197 struct snd_dai *dai)
198 {
199 struct snd_platform *platform = dai->component;
200
201 snd_print("\n");
202 snd_platform_update_bits(platform, SUNXI_DMIC_FIFO_CTR,
203 (1<<DMIC_FIFO_FLUSH), (1<<DMIC_FIFO_FLUSH));
204
205 snd_platform_write(platform, SUNXI_DMIC_INTS,
206 (1<<FIFO_OVERRUN_IRQ_PENDING) | (1<<FIFO_DATA_IRQ_PENDING));
207
208 snd_platform_write(platform, SUNXI_DMIC_CNT, 0x0);
209
210 return 0;
211 }
212
sunxi_dmic_startup(struct snd_pcm_substream * substream,struct snd_dai * dai)213 static int sunxi_dmic_startup(struct snd_pcm_substream *substream,
214 struct snd_dai *dai)
215 {
216 struct snd_platform *platform = dai->component;
217 struct sunxi_dmic_info *sunxi_dmic = platform->private_data;
218
219 snd_print("\n");
220 dai->capture_dma_data = &sunxi_dmic->capture_dma_param;
221
222 return 0;
223 }
224
sunxi_dmic_shutdown(struct snd_pcm_substream * substream,struct snd_dai * dai)225 static void sunxi_dmic_shutdown(struct snd_pcm_substream *substream,
226 struct snd_dai *dai)
227 {
228 snd_print("\n");
229 }
230
sunxi_dmic_set_sysclk(struct snd_dai * dai,int clk_id,unsigned int freq,int dir)231 static int sunxi_dmic_set_sysclk(struct snd_dai *dai, int clk_id,
232 unsigned int freq, int dir)
233 {
234 struct snd_platform *platform = dai->component;
235 struct sunxi_dmic_info *sunxi_dmic = platform->private_data;
236
237 snd_print("\n");
238 if (hal_clk_set_rate(sunxi_dmic->pllclk, freq)) {
239 snd_err("set pllclk %u failed\n", freq);
240 return -EINVAL;
241 }
242
243 return 0;
244 }
245
246 /* Dmic module init status */
sunxi_dmic_dai_probe(struct snd_dai * dai)247 static int sunxi_dmic_dai_probe(struct snd_dai *dai)
248 {
249 struct snd_platform *platform = dai->component;
250
251 snd_print("\n");
252 dai->capture_dma_data = 0;
253 sunxi_dmic_init(platform);
254
255 return 0;
256 }
257
258 static struct snd_dai_ops sunxi_dmic_dai_ops = {
259 .startup = sunxi_dmic_startup,
260 .trigger = sunxi_dmic_trigger,
261 .prepare = sunxi_dmic_prepare,
262 .hw_params = sunxi_dmic_hw_params,
263 .set_sysclk = sunxi_dmic_set_sysclk,
264 .shutdown = sunxi_dmic_shutdown,
265 };
266
267 static struct snd_dai sunxi_dmic_dai = {
268 .id = 1,
269 .name = "sunxi-dmic-cpudai",
270 .capture = {
271 .stream_name = "Capture",
272 .channels_min = 1,
273 .channels_max = 8,
274 .rates = SUNXI_DMIC_RATES,
275 .formats = SNDRV_PCM_FMTBIT_S16_LE
276 | SNDRV_PCM_FMTBIT_S24_LE
277 | SNDRV_PCM_FMTBIT_S32_LE,
278 .rate_min = 8000,
279 .rate_max = 48000,
280 },
281 .probe = sunxi_dmic_dai_probe,
282 .ops = &sunxi_dmic_dai_ops,
283 };
284
sunxi_dmic_clk_init(struct snd_platform * platform)285 static int sunxi_dmic_clk_init(struct snd_platform *platform)
286 {
287 struct sunxi_dmic_info *sunxi_dmic = platform->private_data;
288 hal_reset_type_t reset_type = HAL_SUNXI_RESET;
289 hal_clk_type_t clk_type = HAL_SUNXI_CCU;
290 int ret;
291
292 snd_print("\n");
293 sunxi_dmic->pllclk = hal_clock_get(clk_type, SUNXI_DMIC_CLK_PLL_AUDIO);
294 sunxi_dmic->moduleclk = hal_clock_get(clk_type, SUNXI_DMIC_CLK_DMIC);
295 sunxi_dmic->busclk = hal_clock_get(clk_type, SUNXI_DMIC_CLK_BUS);
296 sunxi_dmic->rstclk = hal_reset_control_get(reset_type, SUNXI_DMIC_CLK_RST);
297
298 ret = hal_clk_set_parent(sunxi_dmic->moduleclk, sunxi_dmic->pllclk);
299 if (ret != HAL_CLK_STATUS_OK) {
300 snd_err("sunxi_dmic clk_set_parent failed.\n");
301 goto err_dmic_moduleclk_set_parent;
302 }
303
304 ret = hal_reset_control_deassert(sunxi_dmic->rstclk);
305 if (ret != HAL_CLK_STATUS_OK) {
306 snd_err("dmic clk_deassert rstclk failed.\n");
307 goto err_dmic_rstclk_deassert;
308 }
309
310 ret = hal_clock_enable(sunxi_dmic->busclk);
311 if (ret != HAL_CLK_STATUS_OK) {
312 snd_err("dmic clk_enable busclk failed.\n");
313 goto err_dmic_busclk_enable;
314 }
315 ret = hal_clock_enable(sunxi_dmic->pllclk);
316 if (ret != HAL_CLK_STATUS_OK) {
317 snd_err("dmic clk_enable pllclk failed.\n");
318 goto err_dmic_pllclk_enable;
319 }
320 ret = hal_clock_enable(sunxi_dmic->moduleclk);
321 if (ret != HAL_CLK_STATUS_OK) {
322 snd_err("dmic clk_enable moduleclk failed.\n");
323 goto err_dmic_moduleclk_enable;
324 }
325
326 return 0;
327
328 err_dmic_moduleclk_enable:
329 hal_clock_disable(sunxi_dmic->pllclk);
330 err_dmic_pllclk_enable:
331 err_dmic_busclk_enable:
332 err_dmic_rstclk_deassert:
333 err_dmic_moduleclk_set_parent:
334 snd_free(sunxi_dmic);
335 return ret;
336 }
337
sunxi_dmic_gpio_init(bool enable)338 static int sunxi_dmic_gpio_init(bool enable)
339 {
340 snd_print("\n");
341 if (enable) {
342 /*CLK*/
343 hal_gpio_pinmux_set_function(g_dmic_gpio.clk.gpio,
344 g_dmic_gpio.clk.mux);
345 /*DATA0*/
346 hal_gpio_pinmux_set_function(g_dmic_gpio.din0.gpio,
347 g_dmic_gpio.din0.mux);
348 /*DATA1*/
349 hal_gpio_pinmux_set_function(g_dmic_gpio.din1.gpio,
350 g_dmic_gpio.din1.mux);
351 /*DATA2*/
352 hal_gpio_pinmux_set_function(g_dmic_gpio.din2.gpio,
353 g_dmic_gpio.din2.mux);
354 /*DATA3*/
355 hal_gpio_pinmux_set_function(g_dmic_gpio.din3.gpio,
356 g_dmic_gpio.din3.mux);
357 } else {
358 /*CLK*/
359 hal_gpio_pinmux_set_function(g_dmic_gpio.clk.gpio,
360 GPIO_MUXSEL_DISABLED);
361 /*DATA0*/
362 hal_gpio_pinmux_set_function(g_dmic_gpio.din0.gpio,
363 GPIO_MUXSEL_DISABLED);
364 /*DATA1*/
365 hal_gpio_pinmux_set_function(g_dmic_gpio.din1.gpio,
366 GPIO_MUXSEL_DISABLED);
367 /*DATA2*/
368 hal_gpio_pinmux_set_function(g_dmic_gpio.din2.gpio,
369 GPIO_MUXSEL_DISABLED);
370 /*DATA3*/
371 hal_gpio_pinmux_set_function(g_dmic_gpio.din3.gpio,
372 GPIO_MUXSEL_DISABLED);
373 }
374
375 return 0;
376 }
377
sunxi_dmic_platform_probe(struct snd_platform * platform)378 static int sunxi_dmic_platform_probe(struct snd_platform *platform)
379 {
380 struct sunxi_dmic_info *sunxi_dmic;
381
382 snd_print("\n");
383 sunxi_dmic = snd_malloc(sizeof(struct sunxi_dmic_info));
384 if (!sunxi_dmic) {
385 snd_err("no memory\n");
386 return -ENOMEM;
387 }
388 platform->private_data = (void *)sunxi_dmic;
389 platform->cpu_dai->component = platform;
390
391 /* mem base */
392 platform->mem_base = (void *)SUNXI_DMIC_MEMBASE;
393
394 /* clk */
395 sunxi_dmic_clk_init(platform);
396
397 /* pinctrl */
398 sunxi_dmic_gpio_init(true);
399
400 /* dma config */
401 sunxi_dmic->capture_dma_param.src_maxburst = 8;
402 sunxi_dmic->capture_dma_param.dst_maxburst = 8;
403 sunxi_dmic->capture_dma_param.dma_addr =
404 (dma_addr_t)platform->mem_base + SUNXI_DMIC_DATA;
405 sunxi_dmic->capture_dma_param.dma_drq_type_num = DRQSRC_DMIC;
406
407 return 0;
408 }
409
sunxi_dmic_platform_remove(struct snd_platform * platform)410 static int sunxi_dmic_platform_remove(struct snd_platform *platform)
411 {
412 struct sunxi_dmic_info *sunxi_dmic;
413
414 snd_print("\n");
415 sunxi_dmic = platform->private_data;
416 if (!sunxi_dmic)
417 return 0;
418
419 hal_clock_disable(sunxi_dmic->busclk);
420 hal_clock_disable(sunxi_dmic->moduleclk);
421 hal_clock_disable(sunxi_dmic->pllclk);
422 hal_clock_put(sunxi_dmic->busclk);
423 hal_clock_put(sunxi_dmic->moduleclk);
424 hal_clock_put(sunxi_dmic->pllclk);
425
426 hal_reset_control_assert(sunxi_dmic->rstclk);
427 hal_reset_control_put(sunxi_dmic->rstclk);
428
429 sunxi_dmic_gpio_init(false);
430
431 snd_free(sunxi_dmic);
432 platform->private_data = NULL;
433
434 return 0;
435 }
436
snd_platform_dmic_register(struct snd_platform * platform,int unused)437 int snd_platform_dmic_register(struct snd_platform *platform, int unused)
438 {
439 int ret;
440
441 snd_print("\n");
442 platform->name = snd_malloc(DMIC_NAME_LEN);
443 if (!platform->name) {
444 snd_err("no memory\n");
445 return -ENOMEM;
446 }
447 snprintf(platform->name, DMIC_NAME_LEN, "dmic-cpudai");
448 platform->ops = &sunxi_pcm_ops;
449 platform->pcm_new = sunxi_pcm_new;
450 platform->pcm_free = sunxi_pcm_free;
451
452 platform->cpu_dai = snd_malloc(sizeof(struct snd_dai));
453 if (!platform->cpu_dai) {
454 snd_err("cpu_dai malloc failed.\n");
455 ret = -ENOMEM;
456 goto err_cpu_dai_malloc;
457 }
458 memcpy(platform->cpu_dai, &sunxi_dmic_dai, sizeof(struct snd_dai));
459
460 platform->probe = sunxi_dmic_platform_probe;
461 platform->remove = sunxi_dmic_platform_remove;
462
463 return 0;
464
465 err_cpu_dai_malloc:
466 snd_free(platform->name);
467 platform->name = NULL;
468 return ret;
469 }
470
471 #ifdef SUNXI_DMIC_DEBUG_REG
472 #define REG_LABEL(constant) {#constant, constant}
473 #define REG_LABEL_END {NULL, 0}
474 static struct dmic_label {
475 const char *name;
476 const unsigned int address;
477 /*int value;*/
478 } reg_labels[] = {
479 REG_LABEL(SUNXI_DMIC_EN),
480 REG_LABEL(SUNXI_DMIC_SR),
481 REG_LABEL(SUNXI_DMIC_CTR),
482 REG_LABEL(SUNXI_DMIC_INTC),
483 REG_LABEL(SUNXI_DMIC_INTS),
484 REG_LABEL(SUNXI_DMIC_FIFO_CTR),
485 REG_LABEL(SUNXI_DMIC_FIFO_STA),
486 REG_LABEL(SUNXI_DMIC_CH_NUM),
487 REG_LABEL(SUNXI_DMIC_CH_MAP),
488 REG_LABEL(SUNXI_DMIC_CNT),
489 REG_LABEL(SUNXI_DMIC_DATA0_1_VOL),
490 REG_LABEL(SUNXI_DMIC_DATA2_3_VOL),
491 REG_LABEL(SUNXI_DMIC_HPF_CTRL),
492 REG_LABEL(SUNXI_DMIC_HPF_COEF),
493 REG_LABEL(SUNXI_DMIC_HPF_GAIN),
494 REG_LABEL_END,
495 };
496
497 /* for debug */
498 #include <console.h>
cmd_dmic_dump(void)499 int cmd_dmic_dump(void)
500 {
501 int dmic_num = 0;
502 void *membase;
503 int i = 0;
504
505 membase = (void *)SUNXI_DMIC_MEMBASE ;
506
507 while (reg_labels[i].name != NULL) {
508 printf("%-20s[0x%03x]: 0x%-10x\n",
509 reg_labels[i].name,
510 reg_labels[i].address,
511 snd_readl(membase + reg_labels[i].address));
512 i++;
513 }
514 }
515 FINSH_FUNCTION_EXPORT_CMD(cmd_dmic_dump, dmic, dmic dump reg);
516 #endif /* SUNXI_DMIC_DEBUG_REG */
517