Merge tag 'lsk-v3.10-android-15.01'
[firefly-linux-kernel-4.4.55.git] / sound / soc / rockchip / rk29_i2s.c
1 /*
2  * rk29_i2s.c  --  ALSA SoC ROCKCHIP IIS Audio Layer Platform driver
3  *
4  * Driver for rockchip iis 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
14 #include <linux/init.h>
15 #include <linux/module.h>
16 #include <linux/interrupt.h>
17 #include <linux/device.h>
18 #include <linux/delay.h>
19 #include <linux/clk.h>
20 #include <linux/version.h>
21
22 #include <asm/dma.h>
23 #include <sound/core.h>
24 #include <sound/pcm.h>
25 #include <sound/pcm_params.h>
26 #include <sound/initval.h>
27 #include <sound/soc.h>
28 #include <asm/io.h>
29
30 #include <mach/hardware.h>
31 #include <mach/board.h>
32 #include <mach/rk29_iomap.h>
33 #include <mach/rk29-dma-pl330.h>
34 #include <mach/iomux.h>
35 #include <mach/cru.h>
36
37 #include "rk_pcm.h"
38 #include "rk_i2s.h"
39
40
41 #if 0
42 #define I2S_DBG(x...) printk(KERN_INFO x)
43 #else
44 #define I2S_DBG(x...) do { } while (0)
45 #endif
46
47 #define pheadi2s  ((pI2S_REG)(i2s->regs))
48
49 #define MAX_I2S         2
50
51 struct rk29_i2s_info {
52         struct device   *dev;
53         void __iomem    *regs;
54         
55         u32     feature;
56
57         struct clk      *iis_clk;
58         struct clk      *iis_pclk;
59
60         unsigned char   master;
61
62         struct rockchip_pcm_dma_params  *dma_playback;
63         struct rockchip_pcm_dma_params  *dma_capture;
64
65         u32              suspend_iismod;
66         u32              suspend_iiscon;
67         u32              suspend_iispsr;
68 };
69
70 static struct rk29_dma_client rk29_dma_client_out = {
71         .name = "I2S PCM Stereo Out"
72 };
73
74 static struct rk29_dma_client rk29_dma_client_in = {
75         .name = "I2S PCM Stereo In"
76 };
77
78 static inline struct rk29_i2s_info *to_info(struct snd_soc_dai *cpu_dai)
79 {
80 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37))
81         return snd_soc_dai_get_drvdata(cpu_dai);
82 #else
83         return cpu_dai->private_data;
84 #endif
85 }
86
87 static struct rockchip_pcm_dma_params rk29_i2s_pcm_stereo_out[MAX_I2S];
88 static struct rockchip_pcm_dma_params rk29_i2s_pcm_stereo_in[MAX_I2S];
89 static struct rk29_i2s_info rk29_i2s[MAX_I2S];
90
91 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37))
92 struct snd_soc_dai_driver rk29_i2s_dai[MAX_I2S];
93 #else
94 struct snd_soc_dai rk29_i2s_dai[MAX_I2S];
95 #endif
96 EXPORT_SYMBOL_GPL(rk29_i2s_dai);
97
98 /*
99 static struct rockchip_pcm_dma_params rockchip_i2s_pcm_stereo_out[MAX_I2S] = {
100         [0] = {
101                 .client         = &rk29_dma_client_out,
102                 .channel        = DMACH_I2S_2CH_TX, ///0,  //DMACH_I2S_OUT,
103                 .dma_addr       = RK29_I2S_2CH_PHYS + I2S_TXR_BUFF,
104                 .dma_size       = 4,
105         },
106         [1] = {
107                 .client         = &rk29_dma_client_out,
108                 .channel        = DMACH_I2S_8CH_TX, ///0,  //DMACH_I2S_OUT,
109                 .dma_addr       = RK29_I2S_8CH_PHYS + I2S_TXR_BUFF,
110                 .dma_size       = 4,
111         },
112 };
113
114 static struct rockchip_pcm_dma_params rockchip_i2s_pcm_stereo_in[MAX_I2S] = {
115         [0] = {
116                 .client         = &rk29_dma_client_in,
117                 .channel        = DMACH_I2S_2CH_RX,  ///1,  //DMACH_I2S_IN,
118                 .dma_addr       = RK29_I2S_2CH_PHYS + I2S_RXR_BUFF,
119                 .dma_size       = 4,
120         },
121         [1] = {
122                 .client         = &rk29_dma_client_in,
123                 .channel        = DMACH_I2S_8CH_RX,  ///1,  //DMACH_I2S_IN,
124                 .dma_addr       = RK29_I2S_8CH_PHYS + I2S_RXR_BUFF,
125                 .dma_size       = 4,
126         },
127 };
128 */
129
130 #if 1
131 static u32 i2s0_clk_enter(void)
132 {
133   u32 clk = cru_readl(CRU_CLKSEL3_CON);
134   cru_writel(0x1ffff, CRU_CLKSEL3_CON);
135   mdelay(1);
136   return clk;
137 }
138
139 static void i2s0_clk_exit(u32 clk)
140 {
141   mdelay(1);    
142   cru_writel(clk, CRU_CLKSEL3_CON);
143   mdelay(1);
144 }
145 #else
146 static u32 i2s0_clk_enter()
147 {
148   return 0;
149 }
150
151 static void i2s0_clk_exit(u32 clk)
152 {
153 }
154 #endif
155
156 /* 
157  *Turn on or off the transmission path. 
158  */
159  
160 static int flag_i2s_tx = 0;
161 static int flag_i2s_rx = 0;
162 static void rockchip_snd_txctrl(struct rk29_i2s_info *i2s, int on, bool stopI2S)
163 {
164         u32 opr,xfer;
165         u32 clk;
166
167         opr  = readl(&(pheadi2s->I2S_DMACR));
168         xfer = readl(&(pheadi2s->I2S_XFER));
169
170         if (on) 
171         {         
172                 I2S_DBG("rockchip_snd_txctrl: on\n");
173
174                 //start tx
175                 //if ((flag_i2s_tx == 0) && (flag_i2s_rx == 0))
176                 if ((xfer&I2S_TX_TRAN_START)==0 || (xfer&I2S_RX_TRAN_START)==0)
177                 {
178                         clk = i2s0_clk_enter();
179                         
180                         //if start tx & rx clk, need reset i2s
181                         xfer |= I2S_TX_TRAN_START;
182                         xfer |= I2S_RX_TRAN_START;
183                         writel(xfer, &(pheadi2s->I2S_XFER));
184                         
185                         i2s0_clk_exit(clk);
186                 }
187
188                 if ((opr & I2S_TRAN_DMA_ENABLE) == 0)
189                 {
190                         opr  |= I2S_TRAN_DMA_ENABLE;
191                         writel(opr, &(pheadi2s->I2S_DMACR));         
192                 }
193
194                 flag_i2s_tx = 1;
195         }
196         else
197         {
198                 //stop tx
199
200                 flag_i2s_tx = 0;
201                 if ((flag_i2s_rx == 0) && (flag_i2s_tx == 0))
202                 {
203                         opr  &= ~I2S_TRAN_DMA_ENABLE;        
204                         writel(opr, &(pheadi2s->I2S_DMACR));  
205                         if(stopI2S)     
206                         {
207                                 clk = i2s0_clk_enter();
208         
209                                 xfer &= ~I2S_RX_TRAN_START;
210                                 xfer &= ~I2S_TX_TRAN_START;
211                                 writel(xfer, &(pheadi2s->I2S_XFER));
212                                 
213                                 i2s0_clk_exit(clk);
214                         }
215
216                         //after stop rx & tx clk, reset i2s
217                         //writel(0x001,&(pheadi2s->I2S_TXRST));
218                         //writel(0x001,&(pheadi2s->I2S_RXRST));
219                 }
220
221                 I2S_DBG("rockchip_snd_txctrl: off\n");
222         } 
223 }
224
225 static void rockchip_snd_rxctrl(struct rk29_i2s_info *i2s, int on, bool stopI2S)
226 {
227         u32 opr,xfer;
228         u32 clk;
229
230         opr  = readl(&(pheadi2s->I2S_DMACR));
231         xfer = readl(&(pheadi2s->I2S_XFER));
232
233         if (on) 
234         {                                
235             I2S_DBG("rockchip_snd_rxctrl: on\n");
236             
237                 //start rx
238                 //if ((flag_i2s_tx == 0) && (flag_i2s_rx == 0))
239                 if ((xfer&I2S_TX_TRAN_START)==0 || (xfer&I2S_RX_TRAN_START)==0)
240                 {
241                         clk = i2s0_clk_enter();
242                         
243                         xfer |= I2S_TX_TRAN_START;
244                         xfer |= I2S_RX_TRAN_START;
245                         writel(xfer, &(pheadi2s->I2S_XFER));
246                         
247                         i2s0_clk_exit(clk);
248                 }
249
250                 if ((opr & I2S_RECE_DMA_ENABLE) == 0)
251                 {
252                         opr  |= I2S_RECE_DMA_ENABLE;
253                         writel(opr, &(pheadi2s->I2S_DMACR));
254                 }
255
256           flag_i2s_rx = 1;
257 #if (CONFIG_SND_SOC_RT5631)
258 //bard 7-16 s
259                 schedule_delayed_work(&rt5631_delay_cap,HZ/4);
260 //bard 7-16 e
261 #endif
262         }
263         else
264         {
265                 //stop rx
266                 flag_i2s_rx = 0;
267                 if ((flag_i2s_rx == 0) && (flag_i2s_tx == 0))
268                 {
269                         opr  &= ~I2S_RECE_DMA_ENABLE;
270                         writel(opr, &(pheadi2s->I2S_DMACR));
271                 
272                         if(stopI2S)     
273                         {
274                                 clk = i2s0_clk_enter();
275                         
276                                 xfer &= ~I2S_RX_TRAN_START;
277                                 xfer &= ~I2S_TX_TRAN_START;
278                                 writel(xfer, &(pheadi2s->I2S_XFER));
279                                 
280                                 i2s0_clk_exit(clk);
281                         } 
282
283                         //after stop rx & tx clk, reset i2s
284                         //writel(0x001,&(pheadi2s->I2S_TXRST));
285                         //writel(0x001,&(pheadi2s->I2S_RXRST));
286                 }               
287                     
288                 I2S_DBG("rockchip_snd_rxctrl: off\n");
289         }
290 }
291
292 /*
293  * Set Rockchip I2S DAI format
294  */
295 static int rockchip_i2s_set_fmt(struct snd_soc_dai *cpu_dai,
296                 unsigned int fmt)
297 {
298         struct rk29_i2s_info *i2s = to_info(cpu_dai);   
299         u32 tx_ctl,rx_ctl;
300
301         I2S_DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
302
303         tx_ctl = readl(&(pheadi2s->I2S_TXCR));
304
305         switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
306                 case SND_SOC_DAIFMT_CBM_CFM:    
307                         tx_ctl &= ~I2S_MODE_MASK;  
308                         tx_ctl |= I2S_MASTER_MODE;
309                         break;
310                 case SND_SOC_DAIFMT_CBS_CFS:
311                         tx_ctl &= ~I2S_MODE_MASK;   
312                         tx_ctl |= I2S_SLAVE_MODE;
313                         break;
314                 default:
315                         I2S_DBG("unknwon master/slave format\n");
316                         return -EINVAL;
317         }       
318
319         switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
320                 case SND_SOC_DAIFMT_RIGHT_J:
321                         tx_ctl &= ~I2S_BUS_MODE_MASK;    //I2S Bus Mode
322                         tx_ctl |= I2S_BUS_MODE_RSJM;
323                         break;
324                 case SND_SOC_DAIFMT_LEFT_J:
325                         tx_ctl &= ~I2S_BUS_MODE_MASK;    //I2S Bus Mode
326                         tx_ctl |= I2S_BUS_MODE_LSJM;
327                         break;
328                 case SND_SOC_DAIFMT_I2S:
329                         tx_ctl &= ~I2S_BUS_MODE_MASK;    //I2S Bus Mode
330                         tx_ctl |= I2S_BUS_MODE_NOR;
331                         break;
332                 default:
333                         I2S_DBG("Unknown data format\n");
334                         return -EINVAL;
335         }
336         I2S_DBG("Enter::%s----%d, I2S_TXCR=0x%X\n",__FUNCTION__,__LINE__,tx_ctl);
337 #if 0//defined(CONFIG_SND_RK_SOC_alc5631) || defined(CONFIG_SND_RK_SOC_alc5621)
338         rx_ctl = tx_ctl;
339         rx_ctl &= ~I2S_MODE_MASK;   
340         rx_ctl |= I2S_SLAVE_MODE;  // set tx slave, rx master
341         writel(rx_ctl, &(pheadi2s->I2S_TXCR));
342 #else
343         writel(tx_ctl, &(pheadi2s->I2S_TXCR));
344 #endif
345         rx_ctl = tx_ctl & 0x00007FFF;
346         writel(rx_ctl, &(pheadi2s->I2S_RXCR));
347         return 0;
348 }
349
350 static int rockchip_i2s_hw_params(struct snd_pcm_substream *substream,
351                                 struct snd_pcm_hw_params *params, struct snd_soc_dai *socdai)
352 {
353 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37))
354         struct rk29_i2s_info *i2s = to_info(socdai);
355 #else
356         struct snd_soc_pcm_runtime *rtd = substream->private_data;
357         struct snd_soc_dai_link *dai = rtd->dai;
358         struct rk29_i2s_info *i2s = to_info(dai->cpu_dai);
359 #endif
360         u32 iismod;
361         u32 dmarc;
362           
363         I2S_DBG("Enter %s, %d >>>>>>>>>>>\n", __func__, __LINE__);
364         /*by Vincent Hsiung for EQ Vol Change*/
365         #define HW_PARAMS_FLAG_EQVOL_ON 0x21
366         #define HW_PARAMS_FLAG_EQVOL_OFF 0x22
367         if ((params->flags == HW_PARAMS_FLAG_EQVOL_ON)||(params->flags == HW_PARAMS_FLAG_EQVOL_OFF))
368         {
369                 return 0;
370         }
371
372 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37))
373         if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
374                 snd_soc_dai_set_dma_data(socdai, substream, i2s->dma_playback);
375         else
376                 snd_soc_dai_set_dma_data(socdai, substream, i2s->dma_capture);
377 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35))
378         if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
379                 dai->cpu_dai->playback.dma_data = i2s->dma_playback;
380         else
381                 dai->cpu_dai->capture.dma_data = i2s->dma_capture;
382 #else
383         if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
384                 dai->cpu_dai->dma_data = i2s->dma_playback;
385         else
386                 dai->cpu_dai->dma_data = i2s->dma_capture;
387 #endif
388                 
389         /* Working copies of register */
390         iismod = readl(&(pheadi2s->I2S_TXCR));
391         //iismod &= (~((1<<5)-1));
392         switch (params_format(params)) {
393         case SNDRV_PCM_FORMAT_S8:
394                 iismod |= SAMPLE_DATA_8bit;
395                 break;
396         case SNDRV_PCM_FORMAT_S16_LE:
397                 iismod |= I2S_DATA_WIDTH(15);
398                 break;
399         case SNDRV_PCM_FORMAT_S20_3LE:
400                 iismod |= I2S_DATA_WIDTH(19);
401                 break;
402         case SNDRV_PCM_FORMAT_S24_LE:
403                 iismod |= I2S_DATA_WIDTH(23);
404                 break;
405         case SNDRV_PCM_FORMAT_S32_LE:
406                 iismod |= I2S_DATA_WIDTH(31);
407                 break;
408         }
409         #if defined (CONFIG_SND_RK_CODEC_SOC_SLAVE) 
410         iismod &= ~I2S_SLAVE_MODE;
411         #endif
412
413         #if defined (CONFIG_SND_RK_CODEC_SOC_MASTER) 
414         iismod |= I2S_SLAVE_MODE;
415         #endif
416
417         //writel((16<<24) |(16<<18)|(16<<12)|(16<<6)|16, &(pheadi2s->I2S_FIFOLR));
418         dmarc = readl(&(pheadi2s->I2S_DMACR));
419         
420         if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
421                 dmarc = ((dmarc & 0xFFFFFE00) | 16);
422         else
423                 dmarc = ((dmarc & 0xFE00FFFF) | 16<<16);
424
425         writel(dmarc, &(pheadi2s->I2S_DMACR));
426         I2S_DBG("Enter %s, %d I2S_TXCR=0x%08X\n", __func__, __LINE__, iismod);  
427 #if 0//defined(CONFIG_SND_RK_SOC_alc5631) || defined(CONFIG_SND_RK_SOC_alc5621)
428         dmarc = iismod;
429         dmarc &= ~I2S_MODE_MASK;   
430         dmarc |= I2S_SLAVE_MODE;     // set tx slave, rx master
431         writel(dmarc, &(pheadi2s->I2S_TXCR));
432 #else
433         writel(iismod, &(pheadi2s->I2S_TXCR));
434 #endif
435         iismod = iismod & 0x00007FFF;
436         writel(iismod, &(pheadi2s->I2S_RXCR));        
437         return 0;
438 }
439
440
441 static int rockchip_i2s_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai)
442 {    
443         int ret = 0;
444         struct snd_soc_pcm_runtime *rtd = substream->private_data;
445 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37))
446         struct rk29_i2s_info *i2s = to_info(rtd->cpu_dai);
447 #else
448         struct rk29_i2s_info *i2s = to_info(rtd->dai->cpu_dai);
449 #endif
450         bool stopI2S = false;
451
452         I2S_DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
453         switch (cmd) {
454         case SNDRV_PCM_TRIGGER_START:
455         case SNDRV_PCM_TRIGGER_RESUME:
456         case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:   
457                 if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
458                         rockchip_snd_rxctrl(i2s, 1, stopI2S);
459                 else
460                         rockchip_snd_txctrl(i2s, 1, stopI2S);
461                 break;
462         
463         case SNDRV_PCM_TRIGGER_SUSPEND:
464                 stopI2S = true;
465         case SNDRV_PCM_TRIGGER_STOP:
466         case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
467                 if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
468                         rockchip_snd_rxctrl(i2s, 0, stopI2S);
469                 else
470                         rockchip_snd_txctrl(i2s, 0, stopI2S);
471                 break;
472         default:
473                 ret = -EINVAL;
474                 break;
475         }
476
477         return ret;
478 }
479 /*
480  * Set Rockchip Clock source
481  */
482 static int rockchip_i2s_set_sysclk(struct snd_soc_dai *cpu_dai,
483         int clk_id, unsigned int freq, int dir)
484 {
485         struct rk29_i2s_info *i2s;        
486
487         i2s = to_info(cpu_dai);
488         
489         I2S_DBG("Enter:%s, %d, i2s=0x%p, freq=%d\n", __FUNCTION__, __LINE__, i2s, freq);
490         /*add scu clk source and enable clk*/
491         clk_set_rate(i2s->iis_clk, freq);
492         return 0;
493 }
494
495 /*
496  * Set Rockchip Clock dividers
497  */
498 static int rockchip_i2s_set_clkdiv(struct snd_soc_dai *cpu_dai,
499         int div_id, int div)
500 {
501         struct rk29_i2s_info *i2s;
502         u32    reg;
503
504         i2s = to_info(cpu_dai);
505         
506         /*stereo mode MCLK/SCK=4*/  
507         
508         reg    = readl(&(pheadi2s->I2S_TXCKR));
509
510         I2S_DBG("Enter:%s, %d, div_id=0x%08X, div=0x%08X\n", __FUNCTION__, __LINE__, div_id, div);
511         
512         /*when i2s in master mode ,must set codec pll div*/
513         switch (div_id) {
514         case ROCKCHIP_DIV_BCLK:
515                 reg &= ~I2S_TX_SCLK_DIV_MASK;
516                 reg |= I2S_TX_SCLK_DIV(div);
517                 break;
518         case ROCKCHIP_DIV_MCLK:
519                 reg &= ~I2S_MCLK_DIV_MASK;
520                 reg |= I2S_MCLK_DIV(div);
521                 break;
522         case ROCKCHIP_DIV_PRESCALER:
523                 
524                 break;
525         default:
526                 return -EINVAL;
527         }
528         writel(reg, &(pheadi2s->I2S_TXCKR));
529         writel(reg, &(pheadi2s->I2S_RXCKR));
530         return 0;
531 }
532
533 /*
534  * To avoid duplicating clock code, allow machine driver to
535  * get the clockrate from here.
536  */
537 u32 rockchip_i2s_get_clockrate(void)
538 {
539         I2S_DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
540         return 0;  ///clk_get_rate(s3c24xx_i2s.iis_clk);
541 }
542 EXPORT_SYMBOL_GPL(rockchip_i2s_get_clockrate);
543
544 #ifdef CONFIG_PM
545 int rockchip_i2s_suspend(struct snd_soc_dai *cpu_dai)
546 {
547         I2S_DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
548         //clk_disable(clk);
549         return 0;
550 }
551
552 int rockchip_i2s_resume(struct snd_soc_dai *cpu_dai)
553 {
554         I2S_DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
555         //clk_enable(clk);
556         return 0;
557 }               
558 #else
559 #define rockchip_i2s_suspend NULL
560 #define rockchip_i2s_resume NULL
561 #endif
562
563 #if defined(CONFIG_SND_RK_SOC_alc5631) || defined(CONFIG_SND_RK_SOC_alc5621)
564 #define ROCKCHIP_I2S_RATES (SNDRV_PCM_RATE_44100)  //zyy 20110704, playback and record use same sample rate
565 #else
566 #define ROCKCHIP_I2S_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
567                             SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |\
568                             SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000)
569 #endif
570
571 static struct snd_soc_dai_ops rockchip_i2s_dai_ops = {
572         .trigger = rockchip_i2s_trigger,
573         .hw_params = rockchip_i2s_hw_params,
574         .set_fmt = rockchip_i2s_set_fmt,
575         .set_clkdiv = rockchip_i2s_set_clkdiv,
576         .set_sysclk = rockchip_i2s_set_sysclk,
577 };
578
579 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37))
580 static int rockchip_i2s_dai_probe(struct snd_soc_dai *dai)
581 #else
582 static int rockchip_i2s_dai_probe(struct platform_device *pdev, struct snd_soc_dai *dai)
583 #endif
584 {       
585         I2S_DBG("Enter %s, %d >>>>>>>>>>>\n", __func__, __LINE__);
586
587         switch(dai->id) {
588         case 0:
589                 rk29_mux_api_set(GPIO2D0_I2S0CLK_MIIRXCLKIN_NAME, GPIO2H_I2S0_CLK);                
590                 rk29_mux_api_set(GPIO2D1_I2S0SCLK_MIICRS_NAME, GPIO2H_I2S0_SCLK);
591                 rk29_mux_api_set(GPIO2D2_I2S0LRCKRX_MIITXERR_NAME, GPIO2H_I2S0_LRCK_RX);
592                 rk29_mux_api_set(GPIO2D3_I2S0SDI_MIICOL_NAME, GPIO2H_I2S0_SDI);
593                 rk29_mux_api_set(GPIO2D4_I2S0SDO0_MIIRXD2_NAME, GPIO2H_I2S0_SDO0);
594                 rk29_mux_api_set(GPIO2D5_I2S0SDO1_MIIRXD3_NAME, GPIO2H_I2S0_SDO1);
595                 rk29_mux_api_set(GPIO2D6_I2S0SDO2_MIITXD2_NAME, GPIO2H_I2S0_SDO2);
596                 rk29_mux_api_set(GPIO2D7_I2S0SDO3_MIITXD3_NAME, GPIO2H_I2S0_SDO3);
597                 
598                 rk29_mux_api_set(GPIO4D6_I2S0LRCKTX0_NAME, GPIO4H_I2S0_LRCK_TX0);
599                 rk29_mux_api_set(GPIO4D7_I2S0LRCKTX1_NAME, GPIO4H_I2S0_LRCK_TX1);
600                 break;
601         case 1:
602                 rk29_mux_api_set(GPIO3A0_I2S1CLK_NAME, GPIO3L_I2S1_CLK);
603                 rk29_mux_api_set(GPIO3A1_I2S1SCLK_NAME, GPIO3L_I2S1_SCLK);
604                 rk29_mux_api_set(GPIO3A2_I2S1LRCKRX_NAME, GPIO3L_I2S1_LRCK_RX);
605                 rk29_mux_api_set(GPIO3A3_I2S1SDI_NAME, GPIO3L_I2S1_SDI);
606                 rk29_mux_api_set(GPIO3A4_I2S1SDO_NAME, GPIO3L_I2S1_SDO);
607                 rk29_mux_api_set(GPIO3A5_I2S1LRCKTX_NAME, GPIO3L_I2S1_LRCK_TX);
608                 break;
609         default:
610                 I2S_DBG("Enter:%s, %d, Error For DevId!!!", __FUNCTION__, __LINE__);
611                 return -EINVAL;
612         }
613         return 0;
614 }
615
616 static int rk29_i2s_probe(struct platform_device *pdev,
617 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37))
618                     struct snd_soc_dai_driver *dai,
619 #else
620                     struct snd_soc_dai *dai,
621 #endif
622                     struct rk29_i2s_info *i2s,
623                     unsigned long base)
624 {
625         struct device *dev = &pdev->dev;
626         struct resource *res;
627
628         I2S_DBG("Enter %s, %d >>>>>>>>>>>\n", __func__, __LINE__);
629
630         i2s->dev = dev;
631
632         /* record our i2s structure for later use in the callbacks */
633 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37))
634         dev_set_drvdata(&pdev->dev, i2s);
635 #else
636         dai->private_data = i2s;
637 #endif
638
639         if (!base) {
640                 res = platform_get_resource(pdev,
641                                              IORESOURCE_MEM,
642                                              0);
643                 if (!res) {
644                         dev_err(dev, "Unable to get register resource\n");
645                         return -ENXIO;
646                 }
647
648                 if (!request_mem_region(res->start, resource_size(res),
649                                         "rk29_i2s")) {
650                         dev_err(dev, "Unable to request register region\n");
651                         return -EBUSY;
652                 }
653
654                 base = res->start;
655         }
656
657         i2s->regs = ioremap(base, (res->end - res->start) + 1); ////res));
658         if (i2s->regs == NULL) {
659                 dev_err(dev, "cannot ioremap registers\n");
660                 return -ENXIO;
661         }
662
663         i2s->iis_pclk = clk_get(dev, "i2s");
664         if (IS_ERR(i2s->iis_pclk)) {
665                 dev_err(dev, "failed to get iis_clock\n");
666                 iounmap(i2s->regs);
667                 return -ENOENT;
668         }
669
670         clk_enable(i2s->iis_pclk);
671
672         /* Mark ourselves as in TXRX mode so we can run through our cleanup
673          * process without warnings. */
674         rockchip_snd_txctrl(i2s, 0, true);
675         rockchip_snd_rxctrl(i2s, 0, true);
676
677         return 0;
678 }
679
680 static int __devinit rockchip_i2s_probe(struct platform_device *pdev)
681 {
682         struct rk29_i2s_info *i2s;
683 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37))
684         struct snd_soc_dai_driver *dai;
685 #else
686         struct snd_soc_dai *dai;
687 #endif
688         int    ret;
689
690         I2S_DBG("Enter %s, %d pdev->id = %d >>>>>>>>>>>\n", __func__, __LINE__, pdev->id);
691
692         if(pdev->id >= MAX_I2S) {
693                 dev_err(&pdev->dev, "id %d out of range\n", pdev->id);
694                 return -EINVAL;        
695         }
696
697         i2s = &rk29_i2s[pdev->id];
698         dai = &rk29_i2s_dai[pdev->id];
699 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 37))
700         dai->dev = &pdev->dev;
701 #endif
702         dai->id = pdev->id;
703         dai->symmetric_rates = 1;
704         if(pdev->id == 0) {
705                 dai->name = "rk_i2s.0";
706                 dai->playback.channels_min = 2;
707                 dai->playback.channels_max = 8;
708         }else{
709                 dai->name = "rk_i2s.1";
710                 dai->playback.channels_min = 2;
711                 dai->playback.channels_max = 2;
712         }
713         dai->playback.rates = ROCKCHIP_I2S_RATES;
714         dai->playback.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE;
715         dai->capture.channels_min = 2;
716         dai->capture.channels_max = 2;
717         dai->capture.rates = ROCKCHIP_I2S_RATES;//;SNDRV_PCM_RATE_44100
718         dai->capture.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE;
719         dai->probe = rockchip_i2s_dai_probe; 
720         dai->ops = &rockchip_i2s_dai_ops;
721         dai->suspend = rockchip_i2s_suspend;
722         dai->resume = rockchip_i2s_resume;
723
724         //i2s->feature |= S3C_FEATURE_CDCLKCON;
725
726         i2s->dma_capture = &rk29_i2s_pcm_stereo_in[pdev->id];
727         i2s->dma_playback = &rk29_i2s_pcm_stereo_out[pdev->id];
728
729         if (pdev->id == 1) {
730                 i2s->dma_capture->channel = DMACH_I2S_2CH_RX;
731                 i2s->dma_capture->dma_addr = RK29_I2S_2CH_PHYS + I2S_RXR_BUFF;
732                 i2s->dma_playback->channel = DMACH_I2S_2CH_TX;
733                 i2s->dma_playback->dma_addr = RK29_I2S_2CH_PHYS + I2S_TXR_BUFF;
734         } else {
735                 i2s->dma_capture->channel = DMACH_I2S_8CH_RX;
736                 i2s->dma_capture->dma_addr = RK29_I2S_8CH_PHYS + I2S_RXR_BUFF;
737                 i2s->dma_playback->channel = DMACH_I2S_8CH_TX;
738                 i2s->dma_playback->dma_addr = RK29_I2S_8CH_PHYS + I2S_TXR_BUFF;
739         }
740
741         i2s->dma_capture->client = &rk29_dma_client_in;
742         i2s->dma_capture->dma_size = 4;
743         i2s->dma_capture->flag = 0;                     //add by sxj, used for burst change
744         i2s->dma_playback->client = &rk29_dma_client_out;
745         i2s->dma_playback->dma_size = 4;
746         i2s->dma_playback->flag = 0;                    //add by sxj, used for burst change
747 #ifdef CONFIG_SND_I2S_DMA_EVENT_STATIC
748          WARN_ON(rk29_dma_request(i2s->dma_playback->channel, i2s->dma_playback->client, NULL));
749          WARN_ON(rk29_dma_request(i2s->dma_capture->channel, i2s->dma_capture->client, NULL));
750 #endif
751         i2s->iis_clk = clk_get(&pdev->dev, "i2s");
752         I2S_DBG("Enter:%s, %d, iis_clk=%p\n", __FUNCTION__, __LINE__, i2s->iis_clk);
753         if (IS_ERR(i2s->iis_clk)) {
754                 dev_err(&pdev->dev, "failed to get i2s clk\n");
755                 ret = PTR_ERR(i2s->iis_clk);
756                 goto err;
757         }
758
759         clk_enable(i2s->iis_clk);
760         clk_set_rate(i2s->iis_clk, 11289600);
761         ret = rk29_i2s_probe(pdev, dai, i2s, 0);
762         if (ret)
763                 goto err_clk;
764
765         ret = snd_soc_register_dai(&pdev->dev, dai);
766         if (ret != 0)
767                 goto err_i2sv2;
768
769         return 0;
770
771 err_i2sv2:
772         /* Not implemented for I2Sv2 core yet */
773 err_clk:
774         clk_put(i2s->iis_clk);
775 err:
776         return ret;
777 }
778
779
780 static int __devexit rockchip_i2s_remove(struct platform_device *pdev)
781 {
782 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37))
783         snd_soc_unregister_dai(&pdev->dev);
784 #else
785         snd_soc_unregister_dai(&rk29_i2s_dai);
786 #endif
787
788         return 0;
789 }
790
791 static struct platform_driver rockchip_i2s_driver = {
792         .probe  = rockchip_i2s_probe,
793         .remove = __devexit_p(rockchip_i2s_remove),
794         .driver = {
795                 .name   = "rk29_i2s",
796                 .owner  = THIS_MODULE,
797         },
798 };
799
800 static int __init rockchip_i2s_init(void)
801 {
802         I2S_DBG("Enter %s, %d >>>>>>>>>>>\n", __func__, __LINE__);
803         
804         return  platform_driver_register(&rockchip_i2s_driver);
805 }
806 module_init(rockchip_i2s_init);
807
808 static void __exit rockchip_i2s_exit(void)
809 {
810         platform_driver_unregister(&rockchip_i2s_driver);
811 }
812 module_exit(rockchip_i2s_exit);
813
814 /* Module information */
815 MODULE_AUTHOR("rockchip");
816 MODULE_DESCRIPTION("ROCKCHIP IIS ASoC Interface");
817 MODULE_LICENSE("GPL");
818
819
820 #ifdef CONFIG_PROC_FS
821 #include <linux/proc_fs.h>
822 #include <linux/seq_file.h>
823 static int proc_i2s_show(struct seq_file *s, void *v)
824 {
825         struct rk29_i2s_info *i2s=&rk29_i2s[0];
826         
827         printk("========Show I2S reg========\n");
828         
829         printk("I2S_TXCR = 0x%08X\n", readl(&(pheadi2s->I2S_TXCR)));
830         printk("I2S_RXCR = 0x%08X\n", readl(&(pheadi2s->I2S_RXCR)));
831         printk("I2S_TXCKR = 0x%08X\n", readl(&(pheadi2s->I2S_TXCKR)));
832         printk("I2S_RXCKR = 0x%08X\n", readl(&(pheadi2s->I2S_RXCKR)));
833         printk("I2S_DMACR = 0x%08X\n", readl(&(pheadi2s->I2S_DMACR)));
834         printk("I2S_INTCR = 0x%08X\n", readl(&(pheadi2s->I2S_INTCR)));
835         printk("I2S_INTSR = 0x%08X\n", readl(&(pheadi2s->I2S_INTSR)));
836         printk("I2S_XFER = 0x%08X\n", readl(&(pheadi2s->I2S_XFER)));
837
838         printk("========Show I2S reg========\n");
839         return 0;
840 }
841
842 static int proc_i2s_open(struct inode *inode, struct file *file)
843 {
844         return single_open(file, proc_i2s_show, NULL);
845 }
846
847 static const struct file_operations proc_i2s_fops = {
848         .open           = proc_i2s_open,
849         .read           = seq_read,
850         .llseek         = seq_lseek,
851         .release        = single_release,
852 };
853
854 static int __init i2s_proc_init(void)
855 {
856         proc_create("i2s_reg", 0, NULL, &proc_i2s_fops);
857         return 0;
858
859 }
860 late_initcall(i2s_proc_init);
861 #endif /* CONFIG_PROC_FS */
862