2 * rk29_pcm.c -- ALSA SoC ROCKCHIP PCM Audio Layer Platform driver
4 * Driver for rockchip pcm audio
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2 of the License, or (at your
10 * option) any later version.
13 #include <linux/module.h>
14 #include <linux/init.h>
16 #include <linux/platform_device.h>
17 #include <linux/slab.h>
18 #include <linux/dma-mapping.h>
20 #include <sound/core.h>
21 #include <sound/pcm.h>
22 #include <sound/pcm_params.h>
23 #include <sound/soc.h>
26 #include <mach/hardware.h>
27 #include <mach/dma-pl330.h>
31 #define PCM_DMA_DEBUG 0
34 #define DBG(x...) printk(KERN_INFO x)
36 #define DBG(x...) do { } while (0)
41 #define DMA_INFIN_LOOP() rk29_dma_has_infiniteloop()
43 #define DMA_INFIN_LOOP() 0
46 static const struct snd_pcm_hardware rockchip_pcm_hardware = {
47 .info = SNDRV_PCM_INFO_INTERLEAVED |
48 SNDRV_PCM_INFO_BLOCK_TRANSFER |
50 SNDRV_PCM_INFO_MMAP_VALID |
51 SNDRV_PCM_INFO_PAUSE |
52 SNDRV_PCM_INFO_RESUME,
53 .formats = SNDRV_PCM_FMTBIT_S24_LE |
54 SNDRV_PCM_FMTBIT_S20_3LE |
55 SNDRV_PCM_FMTBIT_S16_LE,
58 #ifdef CONFIG_RK_SRAM_DMA
59 .buffer_bytes_max = 24*1024,//period_bytes_max * periods_max
61 .buffer_bytes_max = 128*1024,
63 .period_bytes_min = 64, ///PAGE_SIZE,
64 #ifdef CONFIG_RK_SRAM_DMA
65 .period_bytes_max = 8*1024,
67 .period_bytes_max = 2048*4,///PAGE_SIZE*2,
69 .periods_min = 3,///2,
75 struct rockchip_dma_buf_set {
76 struct rockchip_dma_buf_set *next;
77 struct scatterlist sg;
80 struct rockchip_runtime_data {
84 unsigned int dma_loaded;
85 unsigned int dma_limit;
86 unsigned int dma_period;
90 struct rockchip_pcm_dma_params *params;
91 struct rockchip_dma_buf_set *curr; /* current dma buffer set */
92 struct rockchip_dma_buf_set *next; /* next buffer set to load */
93 struct rockchip_dma_buf_set *end; /* end of queue set*/
97 /* rockchip_pcm_enqueue
99 * place a dma buffer onto the queue for the dma system
102 static void rockchip_pcm_enqueue(struct snd_pcm_substream *substream)
104 struct rockchip_runtime_data *prtd = substream->runtime->private_data;
105 dma_addr_t pos = prtd->dma_pos;
109 DBG("Enter::%s----%d prtd->dma_period = %d prtd->dma_limit = %d\n",__FUNCTION__,__LINE__,prtd->dma_period,prtd->dma_limit);
111 if (rk29_dma_has_circular())
112 limit = (prtd->dma_end - prtd->dma_start) / prtd->dma_period;
114 limit = prtd->dma_limit;
116 if (DMA_INFIN_LOOP()) {
117 if(prtd->dma_period % (prtd->params->dma_size*16)){
118 printk("dma_period(%d) is not an integer multiple of dma_size(%d)",prtd->dma_period,prtd->params->dma_size*16);
119 rk29_dma_config(prtd->params->channel,
120 prtd->params->dma_size, 1);
123 rk29_dma_config(prtd->params->channel,
124 prtd->params->dma_size, 16);
125 ret = rk29_dma_enqueue_ring(prtd->params->channel,
126 substream, pos, prtd->dma_period, limit ,true);
128 pos = prtd->dma_start;
130 while (prtd->dma_loaded < prtd->dma_limit) {
131 unsigned long len = prtd->dma_period;
132 // DBG("dma_loaded: %d\n", prtd->dma_loaded);
133 if ((pos + len) > prtd->dma_end) {
134 len = prtd->dma_end - pos;
137 if((len%(prtd->params->dma_size*16) == 0) && (prtd->params->flag == 1))
139 ret = rk29_dma_config(prtd->params->channel,
140 prtd->params->dma_size, 16);
141 prtd->params->flag = 0;
142 DBG("size = 16, channel = %d, flag = %d\n",prtd->params->channel,prtd->params->flag);
144 else if((len%(prtd->params->dma_size*16) != 0) && (prtd->params->flag == 0))
146 ret = rk29_dma_config(prtd->params->channel,
147 prtd->params->dma_size, 1);
148 prtd->params->flag = 1;
149 DBG("size = 1, channel = %d, flag = %d\n",prtd->params->channel,prtd->params->flag);
153 ret = rk29_dma_enqueue(prtd->params->channel,substream, pos, len);
154 // if(prtd->params->channel == 2)
155 DBG("Enter::%s, %d, ret=%d, Channel=%d, Addr=0x%X, Len=%lu\n",
156 __FUNCTION__,__LINE__, ret, prtd->params->channel, pos, len);
159 pos += prtd->dma_period;
160 if (pos >= prtd->dma_end)
161 pos = prtd->dma_start;
169 void rk29_audio_buffdone(void *dev_id, int size,
170 enum rk29_dma_buffresult result)
172 struct snd_pcm_substream *substream = dev_id;
173 struct rockchip_runtime_data *prtd;
175 static ktime_t before = {0},after = {0};
179 t = ktime_to_us(ktime_sub(after, before));
180 if(result == RK29_RES_OK)
182 if(t > prtd->dma_period/4/44100 +73 && t != ktime_to_us(after)) // (23220)4096/4/44100 + 32/44100
184 printk(KERN_DEBUG "Time out:: Audio DMA buffdone time out!!! the time = %lld!\n", t);
186 printk(KERN_DEBUG "audio DMA callback time = %lld\n", t);
188 // printk(KERN_DEBUG "a %d %d\n", size, result);
190 DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
193 DBG("substream is free\n");
196 if (!substream->runtime){
197 DBG("substream->runtime is free\n");
206 DBG("Enter::%s dma about or error result = %d \n",__FUNCTION__,result);
210 prtd = substream->runtime->private_data;
212 // if(prtd->params->channel == 2)
213 DBG("Enter::%s----%d channel =%d \n",__FUNCTION__,__LINE__,prtd->params->channel);
214 if(!(prtd->state & ST_RUNNING))
217 snd_pcm_period_elapsed(substream);
219 spin_lock(&prtd->lock);
220 if (!DMA_INFIN_LOOP() && prtd->state & ST_RUNNING) {
222 rockchip_pcm_enqueue(substream);
224 spin_unlock(&prtd->lock);
227 static int rockchip_pcm_hw_params(struct snd_pcm_substream *substream,
228 struct snd_pcm_hw_params *params)
230 struct snd_pcm_runtime *runtime = substream->runtime;
231 struct rockchip_runtime_data *prtd = runtime->private_data;
232 struct snd_soc_pcm_runtime *rtd = substream->private_data;
233 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37))
234 struct rockchip_pcm_dma_params *dma = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
235 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35))
236 struct rockchip_pcm_dma_params *dma = snd_soc_dai_get_dma_data(rtd->dai->cpu_dai, substream);
238 struct rockchip_pcm_dma_params *dma = rtd->dai->cpu_dai->dma_data;
240 unsigned long totbytes = params_buffer_bytes(params);
243 DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
244 /* return if this is a bufferless transfer e.g.
245 * codec <--> BT codec or GSM modem -- lg FIXME */
249 /* this may get called several times by oss emulation
250 * with different params -HW */
251 if (prtd->params == NULL) {
254 #ifdef CONFIG_SND_I2S_DMA_EVENT_DYNAMIC
255 DBG("params %p, client %p, channel %d\n", prtd->params,prtd->params->client, prtd->params->channel);
256 ret = rk29_dma_request(prtd->params->channel, prtd->params->client, NULL);
257 DBG("Enter::%s, %d, ret=%d, Channel=%d\n", __FUNCTION__, __LINE__, ret, prtd->params->channel);
259 DBG(KERN_ERR "failed to get dma channel\n");
265 ret = rk29_dma_set_buffdone_fn(prtd->params->channel, rk29_audio_buffdone);
267 DBG(KERN_ERR "failed to rk29_dma_set_buffdone_fn\n");
270 snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
272 runtime->dma_bytes = totbytes;
274 spin_lock_irq(&prtd->lock);
275 prtd->dma_loaded = 0;
276 prtd->dma_limit = params_periods(params);//runtime->hw.periods_min;
277 prtd->dma_period = params_period_bytes(params);
278 prtd->dma_start = runtime->dma_addr;
279 prtd->dma_pos = prtd->dma_start;
280 prtd->dma_end = prtd->dma_start + totbytes;
281 prtd->transfer_first = 1;
285 spin_unlock_irq(&prtd->lock);
289 static int rockchip_pcm_hw_free(struct snd_pcm_substream *substream)
291 struct rockchip_runtime_data *prtd = substream->runtime->private_data;
293 DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
294 /* TODO - do we need to ensure DMA flushed */
295 snd_pcm_set_runtime_buffer(substream, NULL);
298 #ifdef CONFIG_SND_I2S_DMA_EVENT_DYNAMIC
299 rk29_dma_free(prtd->params->channel, prtd->params->client);
307 static int rockchip_pcm_prepare(struct snd_pcm_substream *substream)
309 struct rockchip_runtime_data *prtd = substream->runtime->private_data;
312 DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
314 /* return if this is a bufferless transfer e.g.
315 * codec <--> BT codec or GSM modem -- lg FIXME */
319 if(substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
320 ret = rk29_dma_devconfig(prtd->params->channel,
322 prtd->params->dma_addr);
324 ret = rk29_dma_devconfig(prtd->params->channel,
326 prtd->params->dma_addr);
328 DBG("Enter::%s, %d, ret=%d, Channel=%d, Addr=0x%X\n", __FUNCTION__, __LINE__, ret, prtd->params->channel, prtd->params->dma_addr);
329 ret = rk29_dma_config(prtd->params->channel,
330 prtd->params->dma_size, 1);
331 prtd->params->flag = 1;
333 DBG("Enter:%s, %d, ret = %d, Channel=%d, Size=%d\n",
334 __FUNCTION__, __LINE__, ret, prtd->params->channel,
335 prtd->params->dma_size);
337 ret= rk29_dma_ctrl(prtd->params->channel, RK29_DMAOP_FLUSH);
338 DBG("Enter:%s, %d, ret = %d, Channel=%d\n",
339 __FUNCTION__, __LINE__, ret, prtd->params->channel);
341 prtd->dma_loaded = 0;
342 prtd->dma_pos = prtd->dma_start;
344 /* enqueue dma buffers */
345 rockchip_pcm_enqueue(substream);
349 static int rockchip_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
351 struct rockchip_runtime_data *prtd = substream->runtime->private_data;
353 /**************add by qiuen for volume*****/
354 struct snd_soc_pcm_runtime *rtd = substream->private_data;
355 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37))
356 struct snd_soc_dai *pCodec_dai = rtd->codec_dai;
358 struct snd_soc_dai *pCodec_dai = rtd->dai->codec_dai;
363 DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
365 if(cmd==SNDRV_PCM_TRIGGER_VOLUME){
366 vol = substream->number % 100;
367 streamType = (substream->number / 100) % 100;
368 DBG("enter:vol=%d,streamType=%d\n",vol,streamType);
369 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37))
370 if(pCodec_dai->driver->ops->set_volume)
371 pCodec_dai->driver->ops->set_volume(streamType, vol);
373 if(pCodec_dai->ops->set_volume)
374 pCodec_dai->ops->set_volume(streamType, vol);
377 /****************************************************/
378 spin_lock(&prtd->lock);
381 case SNDRV_PCM_TRIGGER_START:
383 prtd->state |= ST_RUNNING;
384 rk29_dma_ctrl(prtd->params->channel, RK29_DMAOP_START);
386 case SNDRV_PCM_TRIGGER_RESUME:
389 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
393 case SNDRV_PCM_TRIGGER_STOP:
394 case SNDRV_PCM_TRIGGER_SUSPEND:
395 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
397 prtd->state &= ~ST_RUNNING;
398 rk29_dma_ctrl(prtd->params->channel, RK29_DMAOP_STOP);
405 spin_unlock(&prtd->lock);
410 static snd_pcm_uframes_t
411 rockchip_pcm_pointer(struct snd_pcm_substream *substream)
413 struct snd_pcm_runtime *runtime = substream->runtime;
414 struct rockchip_runtime_data *prtd = runtime->private_data;
417 snd_pcm_uframes_t ret;
420 spin_lock(&prtd->lock);
422 rk29_dma_getposition(prtd->params->channel, &src, &dst);
424 if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
425 res = dst - prtd->dma_start;
427 res = src - prtd->dma_start;
429 spin_unlock(&prtd->lock);
431 ret = bytes_to_frames(runtime, res);
432 if (ret == runtime->buffer_size)
435 if(prtd->params->channel == 2)
436 DBG("Enter:%s src = %x res = %x ret = %d\n",__FUNCTION__,src,res,ret);
442 static int rockchip_pcm_open(struct snd_pcm_substream *substream)
444 struct snd_pcm_runtime *runtime = substream->runtime;
445 struct rockchip_runtime_data *prtd;
447 DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
449 snd_soc_set_runtime_hwparams(substream, &rockchip_pcm_hardware);
451 prtd = kzalloc(sizeof(struct rockchip_runtime_data), GFP_KERNEL);
455 spin_lock_init(&prtd->lock);
457 runtime->private_data = prtd;
461 static int rockchip_pcm_close(struct snd_pcm_substream *substream)
463 struct snd_pcm_runtime *runtime = substream->runtime;
464 struct rockchip_runtime_data *prtd = runtime->private_data;
465 struct rockchip_dma_buf_set *sg_buf = NULL;
466 DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
469 DBG("rockchip_pcm_close called with prtd == NULL\n");
474 rk29_dma_set_buffdone_fn(prtd->params->channel, NULL);
477 while (sg_buf != NULL) {
478 prtd->curr = sg_buf->next;
479 prtd->next = sg_buf->next;
490 static int rockchip_pcm_mmap(struct snd_pcm_substream *substream,
491 struct vm_area_struct *vma)
493 struct snd_pcm_runtime *runtime = substream->runtime;
495 DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
497 #ifdef CONFIG_RK_SRAM_DMA
498 vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
499 return remap_pfn_range(vma, vma->vm_start,
500 substream->dma_buffer.addr >> PAGE_SHIFT,
501 vma->vm_end - vma->vm_start, vma->vm_page_prot);
503 return dma_mmap_writecombine(substream->pcm->card->dev, vma,
510 static struct snd_pcm_ops rockchip_pcm_ops = {
511 .open = rockchip_pcm_open,
512 .close = rockchip_pcm_close,
513 .ioctl = snd_pcm_lib_ioctl,
514 .hw_params = rockchip_pcm_hw_params,
515 .hw_free = rockchip_pcm_hw_free,
516 .prepare = rockchip_pcm_prepare,
517 .trigger = rockchip_pcm_trigger,
518 .pointer = rockchip_pcm_pointer,
519 .mmap = rockchip_pcm_mmap,
522 #if defined(CONFIG_ARCH_RK3066B)
523 #elif defined(CONFIG_ARCH_RK30)
524 #define SRAM_DMA_PHYS_PLAYBACK (dma_addr_t)(RK30_IMEM_PHYS + 16*1024)
525 #define SRAM_DMA_START_PLAYBACK (RK30_IMEM_NONCACHED + 16*1024)
526 #define SRAM_DMA_PHYS_CAPTURE (dma_addr_t)(SRAM_DMA_PHYS_PLAYBACK + 24*1024)
527 #define SRAM_DMA_START_CAPTURE (SRAM_DMA_START_PLAYBACK + 24*1024)
530 static int rockchip_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
532 struct snd_pcm_substream *substream = pcm->streams[stream].substream;
533 struct snd_dma_buffer *buf = &substream->dma_buffer;
534 size_t size = rockchip_pcm_hardware.buffer_bytes_max;
536 DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
538 buf->dev.type = SNDRV_DMA_TYPE_DEV;
539 buf->dev.dev = pcm->card->dev;
540 buf->private_data = NULL;
541 #ifdef CONFIG_RK_SRAM_DMA
542 if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
543 buf->area = SRAM_DMA_START_PLAYBACK;
544 buf->addr = SRAM_DMA_PHYS_PLAYBACK;
546 buf->area = SRAM_DMA_START_CAPTURE;
547 buf->addr = SRAM_DMA_PHYS_CAPTURE;
550 buf->area = dma_alloc_writecombine(pcm->card->dev, size,
551 &buf->addr, GFP_KERNEL);
556 DBG("%s: size %d\n",__FUNCTION__, size);
560 static void rockchip_pcm_free_dma_buffers(struct snd_pcm *pcm)
562 struct snd_pcm_substream *substream;
563 struct snd_dma_buffer *buf;
566 DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
568 for (stream = 0; stream < 2; stream++) {
569 substream = pcm->streams[stream].substream;
573 buf = &substream->dma_buffer;
577 dma_free_writecombine(pcm->card->dev, buf->bytes,
578 buf->area, buf->addr);
583 static u64 rockchip_pcm_dmamask = DMA_BIT_MASK(32);
585 static int rockchip_pcm_new(struct snd_card *card,
586 struct snd_soc_dai *dai, struct snd_pcm *pcm)
590 DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
592 if (!card->dev->dma_mask)
593 card->dev->dma_mask = &rockchip_pcm_dmamask;
594 if (!card->dev->coherent_dma_mask)
595 card->dev->coherent_dma_mask = 0xffffffff;
597 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37))
598 if (dai->driver->playback.channels_min) {
600 if (dai->playback.channels_min) {
602 ret = rockchip_pcm_preallocate_dma_buffer(pcm,
603 SNDRV_PCM_STREAM_PLAYBACK);
608 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37))
609 if (dai->driver->capture.channels_min) {
611 if (dai->capture.channels_min) {
613 ret = rockchip_pcm_preallocate_dma_buffer(pcm,
614 SNDRV_PCM_STREAM_CAPTURE);
622 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37))
623 static struct snd_soc_platform_driver rockchip_pcm_platform = {
624 .ops = &rockchip_pcm_ops,
625 .pcm_new = rockchip_pcm_new,
626 .pcm_free = rockchip_pcm_free_dma_buffers,
629 static int __devinit rockchip_pcm_platform_probe(struct platform_device *pdev)
631 DBG("Enter::%s, %d\n", __FUNCTION__, __LINE__);
632 return snd_soc_register_platform(&pdev->dev, &rockchip_pcm_platform);
635 static int __devexit rockchip_pcm_platform_remove(struct platform_device *pdev)
637 snd_soc_unregister_platform(&pdev->dev);
641 static struct platform_driver rockchip_pcm_driver = {
643 .name = "rockchip-audio",
644 .owner = THIS_MODULE,
646 .probe = rockchip_pcm_platform_probe,
647 .remove = __devexit_p(rockchip_pcm_platform_remove),
650 static int __init snd_rockchip_pcm_init(void)
652 DBG("Enter::%s, %d\n", __FUNCTION__, __LINE__);
653 return platform_driver_register(&rockchip_pcm_driver);
655 module_init(snd_rockchip_pcm_init);
657 static void __exit snd_rockchip_pcm_exit(void)
659 platform_driver_unregister(&rockchip_pcm_driver);
661 module_exit(snd_rockchip_pcm_exit);
663 struct snd_soc_platform rk29_soc_platform = {
664 .name = "rockchip-audio",
665 .pcm_ops = &rockchip_pcm_ops,
666 .pcm_new = rockchip_pcm_new,
667 .pcm_free = rockchip_pcm_free_dma_buffers,
669 EXPORT_SYMBOL_GPL(rk29_soc_platform);
671 static int __init rockchip_soc_platform_init(void)
673 DBG("Enter::%s, %d\n", __FUNCTION__, __LINE__);
674 return snd_soc_register_platform(&rk29_soc_platform);
676 module_init(rockchip_soc_platform_init);
678 static void __exit rockchip_soc_platform_exit(void)
680 snd_soc_unregister_platform(&rk29_soc_platform);
682 module_exit(rockchip_soc_platform_exit);
685 /* Module information */
686 MODULE_AUTHOR("rockchip");
687 MODULE_DESCRIPTION("ROCKCHIP PCM ASoC Interface");
688 MODULE_LICENSE("GPL");