Merge remote-tracking branch 'kernel-2.6.32/develop' into develop-2.6.36
[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.h>
28
29 #include "rk29_pcm.h"
30
31 #ifdef CONFIG_ANDROID_POWER
32 #include <linux/android_power.h>
33 static android_suspend_lock_t audio_lock;
34 #endif
35
36 #if 0
37 #define DBG(x...) printk(KERN_INFO x)
38 #else
39 #define DBG(x...) do { } while (0)
40 #endif
41
42
43 static const struct snd_pcm_hardware rockchip_pcm_hardware = {
44         .info                   = SNDRV_PCM_INFO_INTERLEAVED |
45                                     SNDRV_PCM_INFO_BLOCK_TRANSFER |
46                                     SNDRV_PCM_INFO_MMAP |
47                                     SNDRV_PCM_INFO_MMAP_VALID |
48                                     SNDRV_PCM_INFO_PAUSE |
49                                     SNDRV_PCM_INFO_RESUME,
50         .formats                =   SNDRV_PCM_FMTBIT_S24_LE |
51                                     SNDRV_PCM_FMTBIT_S20_3LE |
52                                     SNDRV_PCM_FMTBIT_S16_LE,
53         .channels_min           = 2,
54         .channels_max           = 8,
55         .buffer_bytes_max       = 128*1024,
56         .period_bytes_min       = 64,  ///PAGE_SIZE,
57         .period_bytes_max       = 2048*4,///PAGE_SIZE*2,
58         .periods_min            = 3,///2,
59         .periods_max            = 128,
60         .fifo_size              = 16,
61 };
62
63
64 struct rockchip_dma_buf_set {
65         struct rockchip_dma_buf_set     *next;
66         struct scatterlist sg;
67 };
68
69 struct rockchip_runtime_data {
70         spinlock_t lock;
71         int state;
72         int transfer_first;
73         unsigned int dma_loaded;
74         unsigned int dma_limit;
75         unsigned int dma_period;
76         dma_addr_t dma_start;
77         dma_addr_t dma_pos;
78         dma_addr_t dma_end;
79         struct rockchip_pcm_dma_params *params;
80         struct rockchip_dma_buf_set     *curr;          /* current dma buffer set */
81         struct rockchip_dma_buf_set     *next;          /* next buffer set to load */
82         struct rockchip_dma_buf_set     *end;           /* end of queue set*/
83 };
84
85
86 /* rockchip__dma_buf_enqueue
87  *
88  *queue an given buffer for dma transfer set.
89  *data       the physical address of the buffer data
90  *size       the size of the buffer in bytes
91 */
92 static int rockchip_dma_buffer_set_enqueue(struct rockchip_runtime_data *prtd, dma_addr_t data, int size)
93 {   
94         struct rockchip_dma_buf_set *sg_buf;
95         
96         DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
97         sg_buf = kzalloc(sizeof(struct rockchip_dma_buf_set), GFP_ATOMIC);/* ddl@rock-chips.com:GFP_KERNEL->GFP_ATOMIC */
98         
99         if (sg_buf == NULL) {
100                 DBG("scatter sg buffer allocate failed,no memory!\n");
101                 return -ENOMEM;
102         }
103         sg_buf->next = NULL;
104         sg_buf->sg.dma_address = data;
105         sg_buf->sg.length = size/4;  ////4;
106         if( prtd->curr == NULL) {
107                 prtd->curr = sg_buf;
108                 prtd->end  = sg_buf;
109                 prtd->next = NULL;
110         } else {
111                 if (prtd->end == NULL)
112                         DBG("prtd->end is NULL\n");
113                         prtd->end->next = sg_buf;
114                         prtd->end = sg_buf;
115         }
116         /* if necessary, update the next buffer field */
117         if (prtd->next == NULL)
118                 prtd->next = sg_buf;
119         return 0;
120 }
121
122 void rockchip_pcm_dma_irq(s32 ch, void *data);
123
124 void audio_start_dma(struct snd_pcm_substream *substream, int mode)
125 {
126         struct rockchip_runtime_data *prtd;
127         unsigned long flags;
128         struct rockchip_dma_buf_set *sg_buf;
129     
130         DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
131
132         prtd = substream->runtime->private_data;
133
134         switch (mode) {
135         case DMA_MODE_WRITE:
136                 if (prtd->transfer_first == 1) {
137                         prtd->transfer_first = 0;
138                 } else {
139                         sg_buf = prtd->curr;
140                         if (sg_buf != NULL) {
141                                 prtd->curr = sg_buf->next;
142                                 prtd->next = sg_buf->next;
143                                 sg_buf->next  = NULL;
144                                 kfree(sg_buf);
145                                 sg_buf = NULL;
146                         }
147                 }
148
149                 sg_buf = prtd->next;
150                 DBG("Enter::%s----%d---length=%x---dma_address=%x\n",__FUNCTION__,__LINE__,sg_buf->sg.length,sg_buf->sg.dma_address);           
151                 if (sg_buf) {                   
152                         spin_lock_irqsave(&prtd->lock, flags);
153                         disable_dma(prtd->params->channel);
154                         //set_dma_sg(prtd->params->channel, &(sg_buf->sg), 1);
155                         set_dma_mode(prtd->params->channel, DMA_MODE_WRITE);
156                         set_dma_handler(prtd->params->channel, rockchip_pcm_dma_irq, substream, DMA_IRQ_RIGHTNOW_MODE);
157                         __set_dma_addr(prtd->params->channel, (void *)(sg_buf->sg.dma_address));
158                         set_dma_count(prtd->params->channel, sg_buf->sg.length);
159                         enable_dma(prtd->params->channel);
160                         spin_unlock_irqrestore(&prtd->lock, flags);
161                 } else {
162                         DBG("next buffer is NULL for playback\n");
163                         return;
164                 }
165                 break;
166         case DMA_MODE_READ:
167                 if (prtd->transfer_first == 1) {
168                         prtd->transfer_first = 0;
169                 } else {
170                         sg_buf = prtd->curr;
171                         if (sg_buf != NULL) {
172                                 prtd->curr = sg_buf->next;
173                                 prtd->next = sg_buf->next;
174                                 sg_buf->next  = NULL;
175                                 kfree(sg_buf);
176                                 sg_buf = NULL;
177                         }
178                 }
179
180                 sg_buf = prtd->next;
181                 if (sg_buf) {                   
182                         spin_lock_irqsave(&prtd->lock, flags);
183                         disable_dma(prtd->params->channel);
184                         //set_dma_sg(prtd->params->channel, &(sg_buf->sg), 1);
185                         set_dma_mode(prtd->params->channel, DMA_MODE_READ);
186                         set_dma_handler(prtd->params->channel, rockchip_pcm_dma_irq, substream, DMA_IRQ_RIGHTNOW_MODE);                 
187                         __set_dma_addr(prtd->params->channel, (void *)(sg_buf->sg.dma_address));
188                         set_dma_count(prtd->params->channel, sg_buf->sg.length);
189                         enable_dma(prtd->params->channel);
190                         spin_unlock_irqrestore(&prtd->lock, flags);
191                 } else {
192                         DBG("next buffer is NULL for capture\n");
193                         return;
194                 }
195                 break;
196         }
197 }
198
199 /* rockchip_pcm_enqueue
200  *
201  * place a dma buffer onto the queue for the dma system
202  * to handle.
203 */
204 static void rockchip_pcm_enqueue(struct snd_pcm_substream *substream)
205 {
206         struct rockchip_runtime_data *prtd = substream->runtime->private_data;  
207         dma_addr_t pos = prtd->dma_pos;
208         int ret;
209         char* vpos;
210         int i;
211         
212         
213         DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
214         
215         while (prtd->dma_loaded < prtd->dma_limit) {
216                 unsigned long len = prtd->dma_period;
217                 
218                 DBG("dma_loaded: %d\n", prtd->dma_loaded);
219                 if ((pos + len) > prtd->dma_end) {
220                         len  = prtd->dma_end - pos;
221                 }
222
223                 if((len%(prtd->params->dma_size*16) == 0) && (prtd->params->flag == 1))                 
224                 {                                               
225                         ret = rk29_dma_config(prtd->params->channel,                                    
226                                 prtd->params->dma_size, 16);                                            
227                         prtd->params->flag = 0;                                         
228                         DBG("size = 16, channel = %d, flag = %d\n",prtd->params->channel,prtd->params->flag);        
229                 }                               
230                 else if((len%(prtd->params->dma_size*16) != 0) && (prtd->params->flag == 0))            
231                 {                                               
232                         ret = rk29_dma_config(prtd->params->channel,                    
233                                 prtd->params->dma_size, 1);                                             
234                         prtd->params->flag = 1;                                         
235                         DBG("size = 1, channel = %d, flag = %d\n",prtd->params->channel,prtd->params->flag);         
236                 }
237
238
239                 //ret = rockchip_dma_buffer_set_enqueue(prtd, pos, len);                
240                 ret = rk29_dma_enqueue(prtd->params->channel, 
241                         substream, pos, len);
242                 
243                 DBG("Enter::%s, %d, ret=%d, Channel=%d, Addr=0x%X, Len=%d\n",
244                         __FUNCTION__,__LINE__, ret, prtd->params->channel, pos, len);                   
245                 if (ret == 0) {
246                         prtd->dma_loaded++;
247                         pos += prtd->dma_period;
248                         if (pos >= prtd->dma_end)
249                                 pos = prtd->dma_start;
250                 } else 
251                         break;
252         }
253
254         prtd->dma_pos = pos;
255 }
256
257 void rockchip_pcm_dma_irq(s32 ch, void *data)
258 {    
259         struct snd_pcm_substream *substream = data;
260         struct rockchip_runtime_data *prtd;
261         unsigned long flags;
262         
263         DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
264
265         prtd = substream->runtime->private_data;
266         if (substream)
267                 snd_pcm_period_elapsed(substream);
268         spin_lock(&prtd->lock);
269         prtd->dma_loaded--;
270         if (prtd->state & ST_RUNNING) {
271                 rockchip_pcm_enqueue(substream);
272         }
273         spin_unlock(&prtd->lock);
274         local_irq_save(flags);
275         if (prtd->state & ST_RUNNING) {
276                 if (prtd->dma_loaded) {
277                         if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
278                                 audio_start_dma(substream, DMA_MODE_WRITE);
279                         else
280                                 audio_start_dma(substream, DMA_MODE_READ);
281                 }
282         }
283         local_irq_restore(flags);   
284 }
285
286
287 void rk29_audio_buffdone(void *dev_id, int size,
288                                    enum rk29_dma_buffresult result)
289 {
290         struct snd_pcm_substream *substream = dev_id;
291         struct rockchip_runtime_data *prtd;
292         unsigned long flags;
293         
294         DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
295         
296         if (!substream)
297                 return;
298         if (!substream->runtime)
299                 return;
300
301         prtd = substream->runtime->private_data;
302         DBG("Enter::%s----%d, substream=0x%08X, prtd=0x%08X\n",__FUNCTION__,__LINE__, substream, prtd);
303         if (substream){
304                 snd_pcm_period_elapsed(substream);
305         }
306         spin_lock(&prtd->lock);
307         prtd->dma_loaded--;
308         if (prtd->state & ST_RUNNING) {
309                 rockchip_pcm_enqueue(substream);
310         }
311         spin_unlock(&prtd->lock);
312    
313 }
314
315 static int rockchip_pcm_hw_params(struct snd_pcm_substream *substream,
316         struct snd_pcm_hw_params *params)
317 {
318         struct snd_pcm_runtime *runtime = substream->runtime;
319         struct rockchip_runtime_data *prtd = runtime->private_data;
320         struct snd_soc_pcm_runtime *rtd = substream->private_data;
321 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35))
322         struct rockchip_pcm_dma_params *dma = snd_soc_dai_get_dma_data(rtd->dai->cpu_dai, substream);
323 #else
324         struct rockchip_pcm_dma_params *dma = rtd->dai->cpu_dai->dma_data;
325 #endif
326         unsigned long totbytes = params_buffer_bytes(params);
327         int ret = 0;
328
329         DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
330         /*by Vincent Hsiung for EQ Vol Change*/
331         #define HW_PARAMS_FLAG_EQVOL_ON 0x21
332         #define HW_PARAMS_FLAG_EQVOL_OFF 0x22
333
334         if ((params->flags == HW_PARAMS_FLAG_EQVOL_ON)||(params->flags == HW_PARAMS_FLAG_EQVOL_OFF))
335         {
336                 return 0;
337         }
338
339         /* return if this is a bufferless transfer e.g.
340          * codec <--> BT codec or GSM modem -- lg FIXME */
341         if (!dma)
342                 return 0;
343
344         /* this may get called several times by oss emulation
345          * with different params -HW */
346         if (prtd->params == NULL) {
347                 /* prepare DMA */
348                 prtd->params = dma;
349 #ifdef CONFIG_SND_I2S_DMA_EVENT_DYNAMIC
350                 DBG("params %p, client %p, channel %d\n", prtd->params,
351                         prtd->params->client, prtd->params->channel);
352
353                 //ret = request_dma(prtd->params->channel, "i2s");  ///prtd->params->client->name);
354                 ret = rk29_dma_request(prtd->params->channel, prtd->params->client, NULL);
355                 DBG("Enter::%s, %d, ret=%d, Channel=%d\n", __FUNCTION__, __LINE__, ret, prtd->params->channel);
356 /*
357                 if(ret){
358                         for(prtd->params->channel=5;prtd->params->channel>0;prtd->params->channel--){
359                                 ret = request_dma(prtd->params->channel, "i2s");
360                                 if(!ret)break;
361                         }
362                 }
363 */              
364                 if (ret) {
365                         DBG(KERN_ERR "failed to get dma channel\n");
366                         return ret;
367                 }
368 #endif
369         }
370
371         rk29_dma_set_buffdone_fn(prtd->params->channel, rk29_audio_buffdone);
372
373         snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
374
375         runtime->dma_bytes = totbytes;
376
377         spin_lock_irq(&prtd->lock);
378         prtd->dma_loaded = 0;
379         prtd->dma_limit = runtime->hw.periods_min;
380         prtd->dma_period = params_period_bytes(params);
381         prtd->dma_start = runtime->dma_addr;
382         prtd->dma_pos = prtd->dma_start;
383         prtd->dma_end = prtd->dma_start + totbytes;
384         prtd->transfer_first = 1;
385         prtd->curr = NULL;
386         prtd->next = NULL;
387         prtd->end = NULL;
388         spin_unlock_irq(&prtd->lock);
389         return 0;
390 }
391
392 static int rockchip_pcm_hw_free(struct snd_pcm_substream *substream)
393 {
394         struct rockchip_runtime_data *prtd = substream->runtime->private_data;
395
396         DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
397         /* TODO - do we need to ensure DMA flushed */
398         snd_pcm_set_runtime_buffer(substream, NULL);
399
400         if (prtd->params) {
401 #ifdef CONFIG_SND_I2S_DMA_EVENT_DYNAMIC         
402                 //free_dma(prtd->params->channel);
403                 rk29_dma_free(prtd->params->channel, prtd->params->client);
404                 prtd->params = NULL;
405 #endif          
406         }
407
408         return 0;
409 }
410
411 static int rockchip_pcm_prepare(struct snd_pcm_substream *substream)
412 {
413         struct rockchip_runtime_data *prtd = substream->runtime->private_data;
414         int ret = 0;
415
416         DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
417
418         /* return if this is a bufferless transfer e.g.
419          * codec <--> BT codec or GSM modem -- lg FIXME */
420         if (!prtd->params)
421                 return 0;
422
423         if(substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
424                 ret = rk29_dma_devconfig(prtd->params->channel, 
425                                RK29_DMASRC_MEM, 
426                                prtd->params->dma_addr);
427         }else{
428                 ret = rk29_dma_devconfig(prtd->params->channel, 
429                                RK29_DMASRC_HW, 
430                                prtd->params->dma_addr);
431         }
432         DBG("Enter::%s, %d, ret=%d, Channel=%d, Addr=0x%X\n", __FUNCTION__, __LINE__, ret, prtd->params->channel, prtd->params->dma_addr);
433         ret = rk29_dma_config(prtd->params->channel, 
434                 prtd->params->dma_size, 16);
435
436         DBG("Enter:%s, %d, ret = %d, Channel=%d, Size=%d\n", 
437                 __FUNCTION__, __LINE__, ret, prtd->params->channel, 
438                 prtd->params->dma_size);
439                 
440         ret= rk29_dma_ctrl(prtd->params->channel, RK29_DMAOP_FLUSH);
441         DBG("Enter:%s, %d, ret = %d, Channel=%d\n", 
442                 __FUNCTION__, __LINE__, ret, prtd->params->channel);
443         
444         prtd->dma_loaded = 0;
445         prtd->dma_pos = prtd->dma_start;
446
447         /* enqueue dma buffers */
448         rockchip_pcm_enqueue(substream);
449         return ret;
450 }
451
452 static int rockchip_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
453 {
454         struct rockchip_runtime_data *prtd = substream->runtime->private_data;
455         int ret = 0;
456         /**************add by qiuen for volume*****/
457         struct snd_soc_pcm_runtime *rtd = substream->private_data;
458         struct snd_soc_dai *pCodec_dai = rtd->dai->codec_dai;
459         int vol = 0;
460         int streamType = 0;
461         
462         DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
463         
464         if(cmd==SNDRV_PCM_TRIGGER_VOLUME){
465                 vol = substream->number % 100;
466                 streamType = (substream->number / 100) % 100;
467                 DBG("enter:vol=%d,streamType=%d\n",vol,streamType);
468                 if(pCodec_dai->ops->set_volume)
469                         pCodec_dai->ops->set_volume(streamType, vol);
470         }
471         /****************************************************/
472         spin_lock(&prtd->lock);
473
474         switch (cmd) {
475         case SNDRV_PCM_TRIGGER_START:
476                 DBG(" START \n");
477             prtd->state |= ST_RUNNING;
478             rk29_dma_ctrl(prtd->params->channel, RK29_DMAOP_START);
479             /*
480             if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
481                     audio_start_dma(substream, DMA_MODE_WRITE);
482                 } else {
483                     audio_start_dma(substream, DMA_MODE_READ);
484                 }
485                 */
486 #ifdef CONFIG_ANDROID_POWER        
487         android_lock_suspend(&audio_lock);
488         DBG("%s::start audio , lock system suspend\n" , __func__ );
489 #endif          
490                 break;
491         case SNDRV_PCM_TRIGGER_RESUME:
492             DBG(" RESUME \n");
493             break;
494         case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
495                 DBG(" RESTART \n");
496                 break;
497
498         case SNDRV_PCM_TRIGGER_STOP:
499         case SNDRV_PCM_TRIGGER_SUSPEND:
500         case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
501             DBG(" STOPS \n");
502                 prtd->state &= ~ST_RUNNING;
503                 rk29_dma_ctrl(prtd->params->channel, RK29_DMAOP_STOP);
504                 //disable_dma(prtd->params->channel);
505 #ifdef CONFIG_ANDROID_POWER        
506         android_unlock_suspend(&audio_lock );
507         DBG("%s::stop audio , unlock system suspend\n" , __func__ );
508 #endif
509                 
510                 break;
511         default:
512                 ret = -EINVAL;
513                 break;
514         }
515
516         spin_unlock(&prtd->lock);
517         return ret;
518 }
519
520
521 static snd_pcm_uframes_t
522 rockchip_pcm_pointer(struct snd_pcm_substream *substream)
523 {
524         struct snd_pcm_runtime *runtime = substream->runtime;
525         struct rockchip_runtime_data *prtd = runtime->private_data;
526         unsigned long res;
527         dma_addr_t src, dst;
528         snd_pcm_uframes_t ret;
529     
530         DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
531         spin_lock(&prtd->lock);
532
533         //get_dma_position(prtd->params->channel, &src, &dst);
534         rk29_dma_getposition(prtd->params->channel, &src, &dst);
535         //dma_getposition(prtd->params->channel, &src, &dst);
536         
537         if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
538                 res = dst - prtd->dma_start;
539         else
540                 res = src - prtd->dma_start;
541
542         spin_unlock(&prtd->lock);
543
544         DBG("Pointer %x %x\n",src,dst); 
545
546         ret = bytes_to_frames(runtime, res);
547         if (ret == runtime->buffer_size)
548                 ret = 0;
549         return ret;     
550 }
551
552
553 static int rockchip_pcm_open(struct snd_pcm_substream *substream)
554 {
555         struct snd_pcm_runtime *runtime = substream->runtime;
556         struct rockchip_runtime_data *prtd;
557
558         DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
559
560         snd_soc_set_runtime_hwparams(substream, &rockchip_pcm_hardware);
561
562         prtd = kzalloc(sizeof(struct rockchip_runtime_data), GFP_KERNEL);
563         if (prtd == NULL)
564                 return -ENOMEM;
565
566         spin_lock_init(&prtd->lock);
567
568         runtime->private_data = prtd;
569         return 0;
570 }
571
572 static int rockchip_pcm_close(struct snd_pcm_substream *substream)
573 {
574         struct snd_pcm_runtime *runtime = substream->runtime;
575         struct rockchip_runtime_data *prtd = runtime->private_data;
576         struct rockchip_dma_buf_set *sg_buf = NULL;
577         DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
578
579         if (!prtd)
580                 DBG("rockchip_pcm_close called with prtd == NULL\n");
581         if (prtd) 
582                 sg_buf = prtd->curr;
583
584         while (sg_buf != NULL) {
585                 prtd->curr = sg_buf->next;
586                 prtd->next = sg_buf->next;
587                 sg_buf->next  = NULL;
588                 kfree(sg_buf);
589                 sg_buf = NULL;
590                 sg_buf = prtd->curr;
591         }
592         kfree(prtd);
593
594         return 0;
595 }
596
597 static int rockchip_pcm_mmap(struct snd_pcm_substream *substream,
598         struct vm_area_struct *vma)
599 {
600         struct snd_pcm_runtime *runtime = substream->runtime;
601
602         DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
603
604         return dma_mmap_writecombine(substream->pcm->card->dev, vma,
605                                      runtime->dma_area,
606                                      runtime->dma_addr,
607                                      runtime->dma_bytes);
608 }
609
610 static struct snd_pcm_ops rockchip_pcm_ops = {
611         .open           = rockchip_pcm_open,
612         .close          = rockchip_pcm_close,
613         .ioctl          = snd_pcm_lib_ioctl,
614         .hw_params      = rockchip_pcm_hw_params,
615         .hw_free        = rockchip_pcm_hw_free,
616         .prepare        = rockchip_pcm_prepare,
617         .trigger        = rockchip_pcm_trigger,
618         .pointer        = rockchip_pcm_pointer,
619         .mmap           = rockchip_pcm_mmap,
620 };
621
622 static int rockchip_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
623 {
624         struct snd_pcm_substream *substream = pcm->streams[stream].substream;
625         struct snd_dma_buffer *buf = &substream->dma_buffer;
626         size_t size = rockchip_pcm_hardware.buffer_bytes_max;
627
628         DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
629
630         buf->dev.type = SNDRV_DMA_TYPE_DEV;
631         buf->dev.dev = pcm->card->dev;
632         buf->private_data = NULL;
633         buf->area = dma_alloc_writecombine(pcm->card->dev, size,
634                                            &buf->addr, GFP_KERNEL);
635         if (!buf->area)
636                 return -ENOMEM;
637         buf->bytes = size;
638         return 0;
639 }
640
641 static void rockchip_pcm_free_dma_buffers(struct snd_pcm *pcm)
642 {
643         struct snd_pcm_substream *substream;
644         struct snd_dma_buffer *buf;
645         int stream;
646
647         DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
648
649         for (stream = 0; stream < 2; stream++) {
650                 substream = pcm->streams[stream].substream;
651                 if (!substream)
652                         continue;
653
654                 buf = &substream->dma_buffer;
655                 if (!buf->area)
656                         continue;
657
658                 dma_free_writecombine(pcm->card->dev, buf->bytes,
659                                       buf->area, buf->addr);
660                 buf->area = NULL;
661         }
662 }
663
664 static u64 rockchip_pcm_dmamask = DMA_BIT_MASK(32);
665
666 static int rockchip_pcm_new(struct snd_card *card,
667         struct snd_soc_dai *dai, struct snd_pcm *pcm)
668 {
669         int ret = 0;
670
671         DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
672
673 #ifdef CONFIG_ANDROID_POWER
674         audio_lock.name = "rk-audio";
675         android_init_suspend_lock(&audio_lock);
676 #endif
677
678         if (!card->dev->dma_mask)
679                 card->dev->dma_mask = &rockchip_pcm_dmamask;
680         if (!card->dev->coherent_dma_mask)
681                 card->dev->coherent_dma_mask = 0xffffffff;
682
683         if (dai->playback.channels_min) {
684                 ret = rockchip_pcm_preallocate_dma_buffer(pcm,
685                         SNDRV_PCM_STREAM_PLAYBACK);
686                 if (ret)
687                         goto out;
688         }
689
690         if (dai->capture.channels_min) {
691                 ret = rockchip_pcm_preallocate_dma_buffer(pcm,
692                         SNDRV_PCM_STREAM_CAPTURE);
693                 if (ret)
694                         goto out;
695         }
696  out:
697         return ret;
698 }
699
700 struct snd_soc_platform rk29_soc_platform = {
701         .name           = "rockchip-audio",
702         .pcm_ops        = &rockchip_pcm_ops,
703         .pcm_new        = rockchip_pcm_new,
704         .pcm_free       = rockchip_pcm_free_dma_buffers,
705 };
706 EXPORT_SYMBOL_GPL(rk29_soc_platform);
707
708 static int __init rockchip_soc_platform_init(void)
709 {
710         DBG("Enter::%s, %d\n", __FUNCTION__, __LINE__);
711         return snd_soc_register_platform(&rk29_soc_platform);
712 }
713 module_init(rockchip_soc_platform_init);
714
715 static void __exit rockchip_soc_platform_exit(void)
716 {
717         snd_soc_unregister_platform(&rk29_soc_platform);
718 }
719 module_exit(rockchip_soc_platform_exit);
720
721 /* Module information */
722 MODULE_AUTHOR("rockchip");
723 MODULE_DESCRIPTION("ROCKCHIP PCM ASoC Interface");
724 MODULE_LICENSE("GPL");
725