69b871a3bd98968be85cd78c30930c9da3422a00
[firefly-linux-kernel-4.4.55.git] / sound / soc / rk29 / rk29_pcm.c
1 /*
2  * rk29_pcm.c  --  ALSA SoC ROCKCHIP PCM Audio Layer Platform driver
3  *
4  * Driver for rockchip pcm audio
5  *
6  *
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.
11  *
12  */
13 #include <linux/module.h>
14 #include <linux/init.h>
15 #include <linux/io.h>
16 #include <linux/platform_device.h>
17 #include <linux/slab.h>
18 #include <linux/dma-mapping.h>
19
20 #include <sound/core.h>
21 #include <sound/pcm.h>
22 #include <sound/pcm_params.h>
23 #include <sound/soc.h>
24
25 #include <asm/dma.h>
26 #include <mach/hardware.h>
27 #include <mach/dma-pl330.h>
28
29 #include "rk29_pcm.h"
30
31 #define PCM_DMA_DEBUG 0
32
33 #if 0
34 #define DBG(x...) printk(KERN_INFO x)
35 #else
36 #define DBG(x...) do { } while (0)
37 #endif
38
39 #define INFIN_LOOP
40 #ifdef INFIN_LOOP
41 #define DMA_INFIN_LOOP() rk29_dma_has_infiniteloop()
42 #else
43 #define DMA_INFIN_LOOP() 0
44 #endif
45
46 static const struct snd_pcm_hardware rockchip_pcm_hardware = {
47         .info                   = SNDRV_PCM_INFO_INTERLEAVED |
48                                     SNDRV_PCM_INFO_BLOCK_TRANSFER |
49                                     SNDRV_PCM_INFO_MMAP |
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,
56         .channels_min           = 2,
57         .channels_max           = 8,
58 #ifdef CONFIG_RK_SRAM_DMA
59         .buffer_bytes_max       = 24*1024,//period_bytes_max * periods_max
60 #else
61         .buffer_bytes_max       = 128*1024,
62 #endif
63         .period_bytes_min       = 64,  ///PAGE_SIZE,
64 #ifdef CONFIG_RK_SRAM_DMA
65         .period_bytes_max       = 8*1024,
66 #else
67         .period_bytes_max       = 2048*4,///PAGE_SIZE*2,
68 #endif
69         .periods_min            = 3,///2,
70         .periods_max            = 128,
71         .fifo_size              = 16,
72 };
73
74
75 struct rockchip_dma_buf_set {
76         struct rockchip_dma_buf_set     *next;
77         struct scatterlist sg;
78 };
79
80 struct rockchip_runtime_data {
81         spinlock_t lock;
82         int state;
83         int transfer_first;
84         unsigned int dma_loaded;
85         unsigned int dma_limit;
86         unsigned int dma_period;
87         dma_addr_t dma_start;
88         dma_addr_t dma_pos;
89         dma_addr_t dma_end;
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*/
94 };
95
96
97 /* rockchip_pcm_enqueue
98  *
99  * place a dma buffer onto the queue for the dma system
100  * to handle.
101 */
102 static void rockchip_pcm_enqueue(struct snd_pcm_substream *substream)
103 {
104         struct rockchip_runtime_data *prtd = substream->runtime->private_data;  
105         dma_addr_t pos = prtd->dma_pos;
106         unsigned int limit;
107         int ret;
108
109         DBG("Enter::%s----%d prtd->dma_period = %d prtd->dma_limit = %d\n",__FUNCTION__,__LINE__,prtd->dma_period,prtd->dma_limit);
110
111         if (rk29_dma_has_circular())
112                 limit = (prtd->dma_end - prtd->dma_start) / prtd->dma_period;
113         else
114                 limit = prtd->dma_limit;
115
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);
121                 }                                                       
122                 else
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);
127                 if (ret == 0) 
128                         pos = prtd->dma_start;
129         } else {
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;
135                         }
136
137                         if((len%(prtd->params->dma_size*16) == 0) && (prtd->params->flag == 1))
138                         {
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);
143                         }
144                         else if((len%(prtd->params->dma_size*16) != 0) && (prtd->params->flag == 0))
145                         {
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);
150                         }
151
152
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);
157                         if (ret == 0) {
158                                 prtd->dma_loaded++;
159                                 pos += prtd->dma_period;
160                                 if (pos >= prtd->dma_end)
161                                         pos = prtd->dma_start;
162                         } else
163                                 break;
164                 }
165         }
166         prtd->dma_pos = pos;
167 }
168
169 void rk29_audio_buffdone(void *dev_id, int size,
170                                    enum rk29_dma_buffresult result)
171 {
172         struct snd_pcm_substream *substream = dev_id;
173         struct rockchip_runtime_data *prtd;
174 #if PCM_DMA_DEBUG
175         static ktime_t before = {0},after = {0};
176         s64 t;
177         before = after;
178         after = ktime_get();
179         t = ktime_to_us(ktime_sub(after, before));
180         if(result == RK29_RES_OK)
181         {
182                 if(t > prtd->dma_period/4/44100 +73 && t != ktime_to_us(after)) // (23220)4096/4/44100 + 32/44100 
183                 {
184                         printk(KERN_DEBUG "Time out:: Audio DMA buffdone time out!!! the time = %lld!\n", t);
185                 }
186                 printk(KERN_DEBUG "audio DMA callback time = %lld\n", t);
187         }
188 //      printk(KERN_DEBUG "a %d %d\n", size, result);
189 #endif
190         DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
191         
192         if (!substream){
193                 DBG("substream is free\n");
194                 return;
195         }       
196         if (!substream->runtime){
197                 DBG("substream->runtime is free\n");
198                 return;
199         }       
200         switch(result)
201         {
202         case RK29_RES_OK:
203                 break;
204         case RK29_RES_ERR:
205         case RK29_RES_ABORT:
206                 DBG("Enter::%s dma about or error result = %d \n",__FUNCTION__,result);
207                 return;
208         }
209
210         prtd = substream->runtime->private_data;
211         
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))
215                 return; 
216         if (substream){
217                 snd_pcm_period_elapsed(substream);
218         }
219         spin_lock(&prtd->lock);
220         if (!DMA_INFIN_LOOP() && prtd->state & ST_RUNNING) {
221                 prtd->dma_loaded--;
222                 rockchip_pcm_enqueue(substream);
223         }
224         spin_unlock(&prtd->lock);
225 }
226
227 static int rockchip_pcm_hw_params(struct snd_pcm_substream *substream,
228         struct snd_pcm_hw_params *params)
229 {
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);
237 #else
238         struct rockchip_pcm_dma_params *dma = rtd->dai->cpu_dai->dma_data;
239 #endif
240         unsigned long totbytes = params_buffer_bytes(params);
241         int ret = 0;
242
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 */
246         if (!dma)
247                 return 0;
248
249         /* this may get called several times by oss emulation
250          * with different params -HW */
251         if (prtd->params == NULL) {
252                 /* prepare DMA */
253                 prtd->params = dma;
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);
258                 if (ret) {
259                         DBG(KERN_ERR "failed to get dma channel\n");
260                         return ret;
261                 }
262 #endif
263         }
264
265         ret = rk29_dma_set_buffdone_fn(prtd->params->channel, rk29_audio_buffdone);
266         if(ret < 0){
267                 DBG(KERN_ERR "failed to rk29_dma_set_buffdone_fn\n");
268                 return ret;
269         }
270         snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
271
272         runtime->dma_bytes = totbytes;
273
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;
282         prtd->curr = NULL;
283         prtd->next = NULL;
284         prtd->end = NULL;
285         spin_unlock_irq(&prtd->lock);
286         return ret;
287 }
288
289 static int rockchip_pcm_hw_free(struct snd_pcm_substream *substream)
290 {
291         struct rockchip_runtime_data *prtd = substream->runtime->private_data;
292
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);
296
297         if (prtd->params) {
298 #ifdef CONFIG_SND_I2S_DMA_EVENT_DYNAMIC         
299                 rk29_dma_free(prtd->params->channel, prtd->params->client);
300                 prtd->params = NULL;
301 #endif          
302         }
303
304         return 0;
305 }
306
307 static int rockchip_pcm_prepare(struct snd_pcm_substream *substream)
308 {
309         struct rockchip_runtime_data *prtd = substream->runtime->private_data;
310         int ret = 0;
311
312         DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
313
314         /* return if this is a bufferless transfer e.g.
315          * codec <--> BT codec or GSM modem -- lg FIXME */
316         if (!prtd->params)
317                 return 0;
318
319         if(substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
320                 ret = rk29_dma_devconfig(prtd->params->channel, 
321                                RK29_DMASRC_MEM, 
322                                prtd->params->dma_addr);
323         }else{
324                 ret = rk29_dma_devconfig(prtd->params->channel, 
325                                RK29_DMASRC_HW, 
326                                prtd->params->dma_addr);
327         }
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;  
332
333         DBG("Enter:%s, %d, ret = %d, Channel=%d, Size=%d\n", 
334                 __FUNCTION__, __LINE__, ret, prtd->params->channel, 
335                 prtd->params->dma_size);
336                 
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);
340         
341         prtd->dma_loaded = 0;
342         prtd->dma_pos = prtd->dma_start;
343
344         /* enqueue dma buffers */
345         rockchip_pcm_enqueue(substream);
346         return ret;
347 }
348
349 static int rockchip_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
350 {
351         struct rockchip_runtime_data *prtd = substream->runtime->private_data;
352         int ret = 0;
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;
357 #else
358         struct snd_soc_dai *pCodec_dai = rtd->dai->codec_dai;
359 #endif
360         int vol = 0;
361         int streamType = 0;
362         
363         DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
364         
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);
372 #else
373                 if(pCodec_dai->ops->set_volume)
374                         pCodec_dai->ops->set_volume(streamType, vol);
375 #endif
376         }
377         /****************************************************/
378         spin_lock(&prtd->lock);
379
380         switch (cmd) {
381         case SNDRV_PCM_TRIGGER_START:
382                 DBG(" START \n");
383             prtd->state |= ST_RUNNING;
384             rk29_dma_ctrl(prtd->params->channel, RK29_DMAOP_START);
385                 break;
386         case SNDRV_PCM_TRIGGER_RESUME:
387             DBG(" RESUME \n");
388             break;
389         case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
390                 DBG(" RESTART \n");
391                 break;
392
393         case SNDRV_PCM_TRIGGER_STOP:
394         case SNDRV_PCM_TRIGGER_SUSPEND:
395         case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
396             DBG(" STOPS \n");
397                 prtd->state &= ~ST_RUNNING;
398                 rk29_dma_ctrl(prtd->params->channel, RK29_DMAOP_STOP);
399                 break;
400         default:
401                 ret = -EINVAL;
402                 break;
403         }
404
405         spin_unlock(&prtd->lock);
406         return ret;
407 }
408
409
410 static snd_pcm_uframes_t
411 rockchip_pcm_pointer(struct snd_pcm_substream *substream)
412 {
413         struct snd_pcm_runtime *runtime = substream->runtime;
414         struct rockchip_runtime_data *prtd = runtime->private_data;
415         unsigned long res;
416         dma_addr_t src, dst;
417         snd_pcm_uframes_t ret;
418     
419
420         spin_lock(&prtd->lock);
421
422         rk29_dma_getposition(prtd->params->channel, &src, &dst);
423         
424         if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
425                 res = dst - prtd->dma_start;
426         else
427                 res = src - prtd->dma_start;
428
429         spin_unlock(&prtd->lock);
430
431         ret = bytes_to_frames(runtime, res);
432         if (ret == runtime->buffer_size)
433                 ret = 0;
434                 
435         if(prtd->params->channel == 2)          
436                 DBG("Enter:%s src = %x res = %x ret = %d\n",__FUNCTION__,src,res,ret);  
437
438         return ret;     
439 }
440
441
442 static int rockchip_pcm_open(struct snd_pcm_substream *substream)
443 {
444         struct snd_pcm_runtime *runtime = substream->runtime;
445         struct rockchip_runtime_data *prtd;
446
447         DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
448
449         snd_soc_set_runtime_hwparams(substream, &rockchip_pcm_hardware);
450
451         prtd = kzalloc(sizeof(struct rockchip_runtime_data), GFP_KERNEL);
452         if (prtd == NULL)
453                 return -ENOMEM;
454
455         spin_lock_init(&prtd->lock);
456
457         runtime->private_data = prtd;
458         return 0;
459 }
460
461 static int rockchip_pcm_close(struct snd_pcm_substream *substream)
462 {
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__);
467
468         if (!prtd) {
469                 DBG("rockchip_pcm_close called with prtd == NULL\n");
470                 return 0;
471         }
472
473         if (prtd->params)
474                 rk29_dma_set_buffdone_fn(prtd->params->channel, NULL);
475         sg_buf = prtd->curr;
476
477         while (sg_buf != NULL) {
478                 prtd->curr = sg_buf->next;
479                 prtd->next = sg_buf->next;
480                 sg_buf->next  = NULL;
481                 kfree(sg_buf);
482                 sg_buf = NULL;
483                 sg_buf = prtd->curr;
484         }
485         kfree(prtd);
486
487         return 0;
488 }
489
490 static int rockchip_pcm_mmap(struct snd_pcm_substream *substream,
491         struct vm_area_struct *vma)
492 {
493         struct snd_pcm_runtime *runtime = substream->runtime;
494
495    DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
496
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);
502 #else
503         return dma_mmap_writecombine(substream->pcm->card->dev, vma,
504                                      runtime->dma_area,
505                                      runtime->dma_addr,
506                                      runtime->dma_bytes);
507 #endif
508 }
509
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,
520 };
521
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)
528 #endif
529
530 static int rockchip_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
531 {
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;
535
536         DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
537
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;
545         } else{
546                 buf->area = SRAM_DMA_START_CAPTURE;
547                 buf->addr = SRAM_DMA_PHYS_CAPTURE;              
548         }
549 #else
550         buf->area = dma_alloc_writecombine(pcm->card->dev, size,
551                                            &buf->addr, GFP_KERNEL);
552 #endif
553         if (!buf->area)
554                 return -ENOMEM;
555         buf->bytes = size;
556         DBG("%s: size %d\n",__FUNCTION__, size);
557         return 0;
558 }
559
560 static void rockchip_pcm_free_dma_buffers(struct snd_pcm *pcm)
561 {
562         struct snd_pcm_substream *substream;
563         struct snd_dma_buffer *buf;
564         int stream;
565
566         DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
567
568         for (stream = 0; stream < 2; stream++) {
569                 substream = pcm->streams[stream].substream;
570                 if (!substream)
571                         continue;
572
573                 buf = &substream->dma_buffer;
574                 if (!buf->area)
575                         continue;
576
577                 dma_free_writecombine(pcm->card->dev, buf->bytes,
578                                       buf->area, buf->addr);
579                 buf->area = NULL;
580         }
581 }
582
583 static u64 rockchip_pcm_dmamask = DMA_BIT_MASK(32);
584
585 static int rockchip_pcm_new(struct snd_card *card,
586         struct snd_soc_dai *dai, struct snd_pcm *pcm)
587 {
588         int ret = 0;
589
590         DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
591
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;
596
597 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37))
598         if (dai->driver->playback.channels_min) {
599 #else
600         if (dai->playback.channels_min) {
601 #endif
602                 ret = rockchip_pcm_preallocate_dma_buffer(pcm,
603                         SNDRV_PCM_STREAM_PLAYBACK);
604                 if (ret)
605                         goto out;
606         }
607
608 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37))
609         if (dai->driver->capture.channels_min) {
610 #else
611         if (dai->capture.channels_min) {
612 #endif
613                 ret = rockchip_pcm_preallocate_dma_buffer(pcm,
614                         SNDRV_PCM_STREAM_CAPTURE);
615                 if (ret)
616                         goto out;
617         }
618  out:
619         return ret;
620 }
621
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,
627 };
628
629 static int __devinit rockchip_pcm_platform_probe(struct platform_device *pdev)
630 {
631         DBG("Enter::%s, %d\n", __FUNCTION__, __LINE__);
632         return snd_soc_register_platform(&pdev->dev, &rockchip_pcm_platform);
633 }
634
635 static int __devexit rockchip_pcm_platform_remove(struct platform_device *pdev)
636 {
637         snd_soc_unregister_platform(&pdev->dev);
638         return 0;
639 }
640
641 static struct platform_driver rockchip_pcm_driver = {
642         .driver = {
643                 .name = "rockchip-audio",
644                 .owner = THIS_MODULE,
645         },
646         .probe = rockchip_pcm_platform_probe,
647         .remove = __devexit_p(rockchip_pcm_platform_remove),
648 };
649
650 static int __init snd_rockchip_pcm_init(void)
651 {
652         DBG("Enter::%s, %d\n", __FUNCTION__, __LINE__);
653         return platform_driver_register(&rockchip_pcm_driver);
654 }
655 module_init(snd_rockchip_pcm_init);
656
657 static void __exit snd_rockchip_pcm_exit(void)
658 {
659         platform_driver_unregister(&rockchip_pcm_driver);
660 }
661 module_exit(snd_rockchip_pcm_exit);
662 #else
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,
668 };
669 EXPORT_SYMBOL_GPL(rk29_soc_platform);
670
671 static int __init rockchip_soc_platform_init(void)
672 {
673         DBG("Enter::%s, %d\n", __FUNCTION__, __LINE__);
674         return snd_soc_register_platform(&rk29_soc_platform);
675 }
676 module_init(rockchip_soc_platform_init);
677
678 static void __exit rockchip_soc_platform_exit(void)
679 {
680         snd_soc_unregister_platform(&rk29_soc_platform);
681 }
682 module_exit(rockchip_soc_platform_exit);
683 #endif
684
685 /* Module information */
686 MODULE_AUTHOR("rockchip");
687 MODULE_DESCRIPTION("ROCKCHIP PCM ASoC Interface");
688 MODULE_LICENSE("GPL");
689