update rk29 alsa
[firefly-linux-kernel-4.4.55.git] / sound / soc / rk29 / 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
21 #include <asm/dma.h>
22 #include <sound/core.h>
23 #include <sound/pcm.h>
24 #include <sound/pcm_params.h>
25 #include <sound/initval.h>
26 #include <sound/soc.h>
27 #include <asm/io.h>
28
29 #include <mach/hardware.h>
30 #include <mach/board.h>
31 #include <mach/rk29_iomap.h>
32 #include <mach/rk29-dma-pl330.h>
33
34
35 #include "rk29_pcm.h"
36 #include "rk29_i2s.h"
37
38
39 #if 0
40 #define DBG(x...) printk(KERN_INFO x)
41 #else
42 #define DBG(x...) do { } while (0)
43 #endif
44
45 #define pheadi2s  ((pI2S_REG)(i2s->regs))
46
47 #define MAX_I2S         2
48
49 struct rk29_i2s_info {
50         struct device   *dev;
51         void __iomem    *regs;
52         
53         u32     feature;
54
55         struct clk      *iis_clk;
56         struct clk      *iis_pclk;
57
58         unsigned char   master;
59
60         struct rockchip_pcm_dma_params  *dma_playback;
61         struct rockchip_pcm_dma_params  *dma_capture;
62
63         u32              suspend_iismod;
64         u32              suspend_iiscon;
65         u32              suspend_iispsr;
66 };
67
68 static struct rk29_dma_client rk29_dma_client_out = {
69         .name = "I2S PCM Stereo Out"
70 };
71
72 static struct rk29_dma_client rk29_dma_client_in = {
73         .name = "I2S PCM Stereo In"
74 };
75
76 static inline struct rk29_i2s_info *to_info(struct snd_soc_dai *cpu_dai)
77 {
78         return cpu_dai->private_data;
79 }
80
81 static struct rockchip_pcm_dma_params rk29_i2s_pcm_stereo_out[MAX_I2S];
82 static struct rockchip_pcm_dma_params rk29_i2s_pcm_stereo_in[MAX_I2S];
83 static struct rk29_i2s_info rk29_i2s[MAX_I2S];
84
85 struct snd_soc_dai rk29_i2s_dai[MAX_I2S];
86 EXPORT_SYMBOL_GPL(rk29_i2s_dai);
87
88 /*
89 static struct rockchip_pcm_dma_params rockchip_i2s_pcm_stereo_out[MAX_I2S] = {
90         [0] = {
91                 .client         = &rk29_dma_client_out,
92                 .channel        = DMACH_I2S_2CH_TX, ///0,  //DMACH_I2S_OUT,
93                 .dma_addr       = RK29_I2S_2CH_PHYS + I2S_TXR_BUFF,
94                 .dma_size       = 4,
95         },
96         [1] = {
97                 .client         = &rk29_dma_client_out,
98                 .channel        = DMACH_I2S_8CH_TX, ///0,  //DMACH_I2S_OUT,
99                 .dma_addr       = RK29_I2S_8CH_PHYS + I2S_TXR_BUFF,
100                 .dma_size       = 4,
101         },
102 };
103
104 static struct rockchip_pcm_dma_params rockchip_i2s_pcm_stereo_in[MAX_I2S] = {
105         [0] = {
106                 .client         = &rk29_dma_client_in,
107                 .channel        = DMACH_I2S_2CH_RX,  ///1,  //DMACH_I2S_IN,
108                 .dma_addr       = RK29_I2S_2CH_PHYS + I2S_RXR_BUFF,
109                 .dma_size       = 4,
110         },
111         [1] = {
112                 .client         = &rk29_dma_client_in,
113                 .channel        = DMACH_I2S_8CH_RX,  ///1,  //DMACH_I2S_IN,
114                 .dma_addr       = RK29_I2S_8CH_PHYS + I2S_RXR_BUFF,
115                 .dma_size       = 4,
116         },
117 };
118 */
119
120
121
122
123 /* 
124  *Turn on or off the transmission path. 
125  */
126 static void rockchip_snd_txctrl(struct rk29_i2s_info *i2s, int on)
127 {
128     //struct rk29_i2s_info *i2s = &rockchip_i2s;          
129         u32 opr,fifosts;
130     
131         DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
132
133         opr = readl(&(pheadi2s->I2S_OPR));
134         fifosts = readl(&(pheadi2s->I2S_FIFOSTS));
135         fifosts = (fifosts & (~(0x0f<<16))) | TX_HALF_FULL | RX_HALF_FULL;
136         writel(fifosts, &(pheadi2s->I2S_FIFOSTS));
137         if (on) 
138         {
139                 opr = (opr & (~(RESET_RX | I2S_DMA_REQ2_DISABLE | TX_START | RX_START))) | (RESET_TX | I2S_DMA_REQ1_DISABLE);
140                 writel(opr, &(pheadi2s->I2S_OPR));
141                 udelay(5);
142                 opr = (opr & (~(I2S_DMA_REQ1_DISABLE | I2S_DMA_REQ1_RX_ENABLE | RX_START))) | I2S_DMA_REQ1_ENABLE | I2S_DMA_REQ1_TX_ENABLE | TX_START;
143                 writel(opr, &(pheadi2s->I2S_OPR));
144         }
145         else
146         {  
147                 opr = (opr & (~TX_START)) | I2S_DMA_REQ1_DISABLE;
148                 writel(opr, &(pheadi2s->I2S_OPR));
149         }
150 }
151
152 static void rockchip_snd_rxctrl(struct rk29_i2s_info *i2s, int on)
153 {
154         //struct rk29_i2s_info *i2s = &rockchip_i2s;
155         u32 opr,fifosts;
156           
157         DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
158         opr = readl(&(pheadi2s->I2S_OPR));
159         fifosts = readl(&(pheadi2s->I2S_FIFOSTS));
160         fifosts = (fifosts & (~(0x0f<<16))) | TX_HALF_FULL | RX_HALF_FULL;
161         writel(fifosts, &(pheadi2s->I2S_FIFOSTS));
162         if (on) 
163         {
164                 opr = (opr & (~(RESET_TX | I2S_DMA_REQ1_DISABLE| TX_START | RX_START))) | (RESET_RX | I2S_DMA_REQ2_DISABLE);
165                 writel(opr, &(pheadi2s->I2S_OPR));
166                 udelay(5);
167                 opr = (opr & (~(I2S_DMA_REQ2_DISABLE | I2S_DMA_REQ2_TX_ENABLE | TX_START))) | I2S_DMA_REQ2_ENABLE | I2S_DMA_REQ2_RX_ENABLE | RX_START;
168                 writel(opr, &(pheadi2s->I2S_OPR));
169         }
170         else
171         {
172                 opr = (opr & (~RX_START)) | I2S_DMA_REQ2_DISABLE;
173                 writel(opr, &(pheadi2s->I2S_OPR));
174         }   
175 }
176
177 /*
178  * Set Rockchip I2S DAI format
179  */
180 static int rockchip_i2s_set_fmt(struct snd_soc_dai *cpu_dai,
181                 unsigned int fmt)
182 {
183     struct rk29_i2s_info *i2s = to_info(cpu_dai);       
184     u32 tx_ctl,rx_ctl;
185     DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
186     
187     tx_ctl = readl(&(pheadi2s->I2S_TXCTL));
188     tx_ctl &= (~MASTER_MODE);
189     
190     switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
191           case SND_SOC_DAIFMT_CBM_CFM:          
192                 tx_ctl |= MASTER_MODE;  
193                 break;
194           case SND_SOC_DAIFMT_CBS_CFS:
195                 tx_ctl |= SLAVE_MODE;  
196                 break;
197           default:
198                 DBG("unknwon master/slave format\n");
199                 return -EINVAL;
200           }
201     tx_ctl &= ~IISMOD_SDF_MASK;
202     
203     switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
204     case SND_SOC_DAIFMT_RIGHT_J:
205         tx_ctl |= RIGHT_JUSTIFIED;
206         break;
207     case SND_SOC_DAIFMT_LEFT_J:
208         tx_ctl |= LEFT_JUSTIFIED;
209         break;
210     case SND_SOC_DAIFMT_I2S:
211         tx_ctl |= I2S_MODE;
212         break;
213     default:
214         DBG("Unknown data format\n");
215         return -EINVAL;
216           }
217         tx_ctl = tx_ctl & (~(0xff<<8)) & (~(0x03<<16)) & (~(1<<3));  
218         tx_ctl = tx_ctl | OVERSAMPLING_RATE_64FS | SCK_RATE4 | STEREO_MODE;   
219     writel(tx_ctl, &(pheadi2s->I2S_TXCTL));
220     rx_ctl = tx_ctl | CLEAR_RXFIFO;
221     writel(rx_ctl, &(pheadi2s->I2S_RXCTL));
222     return 0;
223 }
224
225 static int rockchip_i2s_hw_params(struct snd_pcm_substream *substream,
226                                 struct snd_pcm_hw_params *params, struct snd_soc_dai *socdai)
227 {
228         struct snd_soc_pcm_runtime *rtd = substream->private_data;
229         struct snd_soc_dai_link *dai = rtd->dai;
230         struct rk29_i2s_info *i2s = to_info(dai->cpu_dai);
231         u32 iismod;
232           
233         DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
234         /*by Vincent Hsiung for EQ Vol Change*/
235         #define HW_PARAMS_FLAG_EQVOL_ON 0x21
236         #define HW_PARAMS_FLAG_EQVOL_OFF 0x22
237         if ((params->flags == HW_PARAMS_FLAG_EQVOL_ON)||(params->flags == HW_PARAMS_FLAG_EQVOL_OFF))
238         {
239                 return 0;
240         }
241            
242         if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
243                 dai->cpu_dai->dma_data = i2s->dma_playback->client;
244         else
245                 dai->cpu_dai->dma_data = i2s->dma_capture->client;
246                 
247         /* Working copies of register */
248         iismod = readl(&(pheadi2s->I2S_TXCTL));
249         iismod &= (~SAMPLE_DATA_MASK);
250         switch (params_format(params)) {
251           case SNDRV_PCM_FORMAT_S8:
252                 iismod |= SAMPLE_DATA_8bit;
253                 break;
254           case SNDRV_PCM_FORMAT_S16_LE:
255                 iismod |= SAMPLE_DATA_16bit;
256                 break;
257         } 
258         /*stereo mode MCLK/SCK=4*/  
259         iismod = iismod & (~(0xff<<8)) & (~(0x03<<16)) & (~(1<<3));
260         iismod = iismod | OVERSAMPLING_RATE_64FS | SCK_RATE4 | STEREO_MODE; 
261           
262         writel(iismod, &(pheadi2s->I2S_TXCTL));
263         iismod = iismod | CLEAR_RXFIFO;
264         writel(iismod, &(pheadi2s->I2S_RXCTL));
265         return 0;
266 }
267
268
269 static int rockchip_i2s_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai)
270 {    
271         int ret = 0;
272         struct snd_soc_pcm_runtime *rtd = substream->private_data;
273         struct rk29_i2s_info *i2s = to_info(rtd->dai->cpu_dai);
274
275         DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
276
277         switch (cmd) {
278         case SNDRV_PCM_TRIGGER_START:
279         case SNDRV_PCM_TRIGGER_RESUME:
280         case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:   
281                 if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
282                         rockchip_snd_rxctrl(i2s, 1);
283                 else
284                         rockchip_snd_txctrl(i2s, 1);
285                 break;
286         case SNDRV_PCM_TRIGGER_STOP:
287         case SNDRV_PCM_TRIGGER_SUSPEND:
288         case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
289                 if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
290                         rockchip_snd_rxctrl(i2s, 0);
291                 else
292                         rockchip_snd_txctrl(i2s, 0);
293                 break;
294         default:
295                 ret = -EINVAL;
296                 break;
297         }
298
299         return ret;
300 }
301 /*
302  * Set Rockchip Clock source
303  */
304 static int rockchip_i2s_set_sysclk(struct snd_soc_dai *cpu_dai,
305         int clk_id, unsigned int freq, int dir)
306 {
307         DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
308         /*add scu clk source and enable clk*/
309
310         return 0;
311 }
312
313 /*
314  * Set Rockchip Clock dividers
315  */
316 static int rockchip_i2s_set_clkdiv(struct snd_soc_dai *cpu_dai,
317         int div_id, int div)
318 {
319     //u32 reg;
320     
321     DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
322     /*when i2s in master mode ,must set codec pll div*/
323     switch (div_id) {
324     case ROCKCHIP_DIV_BCLK:
325         //reg = readl(&(pheadi2s->I2S_TXCTL)) & ~S3C2410_IISMOD_FS_MASK;
326         //writel(reg | div, &(pheadi2s->I2S_TXCTL));
327         break;
328     case ROCKCHIP_DIV_MCLK:
329         //reg = readl(rockchip_i2s.regs + S3C2410_IISMOD) & ~(S3C2410_IISMOD_384FS);
330         //writel(reg | div, s3c24xx_i2s.regs + S3C2410_IISMOD);
331         break;
332     case ROCKCHIP_DIV_PRESCALER:
333         //writel(div, s3c24xx_i2s.regs + S3C2410_IISPSR);
334         //reg = readl(s3c24xx_i2s.regs + S3C2410_IISCON);
335         //writel(reg | S3C2410_IISCON_PSCEN, s3c24xx_i2s.regs + S3C2410_IISCON);
336         break;
337     default:
338         return -EINVAL;
339         }
340     return 0;
341 }
342
343 static int rockchip_set_sysclk(struct snd_soc_dai *cpu_dai,
344                                 int clk_id, unsigned int freq, int dir)
345 {
346         return 0;
347 }
348
349
350 /*
351  * To avoid duplicating clock code, allow machine driver to
352  * get the clockrate from here.
353  */
354 u32 rockchip_i2s_get_clockrate(void)
355 {
356     DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
357         return 0;  ///clk_get_rate(s3c24xx_i2s.iis_clk);
358 }
359 EXPORT_SYMBOL_GPL(rockchip_i2s_get_clockrate);
360
361 #ifdef CONFIG_PM
362 int rockchip_i2s_suspend(struct snd_soc_dai *cpu_dai)
363 {
364     DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
365     //clk_disable(clk);
366           return 0;
367 }
368
369 int rockchip_i2s_resume(struct snd_soc_dai *cpu_dai)
370 {
371     DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
372     //clk_enable(clk);
373     return 0;
374 }               
375 #else
376 #define rockchip_i2s_suspend NULL
377 #define rockchip_i2s_resume NULL
378 #endif
379
380 #define ROCKCHIP_I2S_RATES SNDRV_PCM_RATE_48000
381
382 static struct snd_soc_dai_ops rockchip_i2s_dai_ops = {
383         .trigger = rockchip_i2s_trigger,
384         .hw_params = rockchip_i2s_hw_params,
385         .set_fmt = rockchip_i2s_set_fmt,
386         .set_clkdiv = rockchip_i2s_set_clkdiv,
387         .set_sysclk = rockchip_i2s_set_sysclk,
388 };
389
390 static int rockchip_i2s_dai_probe(struct platform_device *pdev, struct snd_soc_dai *dai)
391 {       
392         DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
393     
394         return 0;
395 }
396
397 static int rk29_i2s_probe(struct platform_device *pdev,
398                     struct snd_soc_dai *dai,
399                     struct rk29_i2s_info *i2s,
400                     unsigned long base)
401 {
402         struct device *dev = &pdev->dev;
403         unsigned int iismod;
404         struct resource *res;
405
406         i2s->dev = dev;
407
408         /* record our i2s structure for later use in the callbacks */
409         dai->private_data = i2s;
410
411         if (!base) {
412                 res = platform_get_resource(pdev,
413                                              IORESOURCE_MEM,
414                                              0);
415                 if (!res) {
416                         dev_err(dev, "Unable to get register resource\n");
417                         return -ENXIO;
418                 }
419
420                 if (!request_mem_region(res->start, resource_size(res),
421                                         "rk29-i2s")) {
422                         dev_err(dev, "Unable to request register region\n");
423                         return -EBUSY;
424                 }
425
426                 base = res->start;
427         }
428
429         i2s->regs = ioremap(base, resource_size(res));
430         if (i2s->regs == NULL) {
431                 dev_err(dev, "cannot ioremap registers\n");
432                 return -ENXIO;
433         }
434
435         i2s->iis_pclk = clk_get(dev, "i2s");
436         if (IS_ERR(i2s->iis_pclk)) {
437                 dev_err(dev, "failed to get iis_clock\n");
438                 iounmap(i2s->regs);
439                 return -ENOENT;
440         }
441
442         clk_enable(i2s->iis_pclk);
443
444         /* Mark ourselves as in TXRX mode so we can run through our cleanup
445          * process without warnings. */
446         
447         rockchip_snd_txctrl(i2s, 0);
448         rockchip_snd_rxctrl(i2s, 0);
449
450         return 0;
451 }
452
453 static int rk29_i2s_register_dai(struct snd_soc_dai *dai)
454 {
455         struct snd_soc_dai_ops *ops = dai->ops;
456
457         ops->trigger = rockchip_i2s_trigger;
458         if (!ops->hw_params)
459                 ops->hw_params = rockchip_i2s_hw_params;
460         ops->set_fmt = rockchip_i2s_set_fmt;
461         ops->set_clkdiv = rockchip_i2s_set_clkdiv;
462         ops->set_sysclk = rockchip_set_sysclk;
463
464         dai->suspend = rockchip_i2s_suspend;
465         dai->resume = rockchip_i2s_resume;
466
467         return snd_soc_register_dai(dai);
468 }
469
470 static int __devinit rockchip_i2s_probe(struct platform_device *pdev)
471 {
472         struct rk29_i2s_info *i2s;
473         struct snd_soc_dai *dai;
474         int    ret;
475
476         if(pdev->id >= MAX_I2S) {
477                 dev_err(&pdev->dev, "id %d out of range\n", pdev->id);
478                 return -EINVAL;        
479         }
480
481         i2s = &rk29_i2s[pdev->id];
482         dai = &rk29_i2s_dai[pdev->id];
483         dai->dev = &pdev->dev;
484         dai->name = "rk29-i2s";
485         dai->id = pdev->id;
486         dai->symmetric_rates = 1;
487         dai->playback.channels_min = 2;
488         dai->playback.channels_max = 2;
489         dai->playback.rates = ROCKCHIP_I2S_RATES;
490         dai->playback.formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE;
491         dai->capture.channels_min = 2;
492         dai->capture.channels_max = 2;
493         dai->capture.rates = ROCKCHIP_I2S_RATES;
494         dai->capture.formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE;
495         dai->probe = rockchip_i2s_dai_probe; 
496         dai->ops = &rockchip_i2s_dai_ops;
497
498         //i2s->feature |= S3C_FEATURE_CDCLKCON;
499
500         i2s->dma_capture = &rk29_i2s_pcm_stereo_in[pdev->id];
501         i2s->dma_playback = &rk29_i2s_pcm_stereo_out[pdev->id];
502
503         if (pdev->id == 0) {
504                 i2s->dma_capture->channel = DMACH_I2S_2CH_RX;
505                 i2s->dma_capture->dma_addr = RK29_I2S_2CH_PHYS + I2S_RXR_BUFF;
506                 i2s->dma_playback->channel = DMACH_I2S_2CH_TX;
507                 i2s->dma_playback->dma_addr = RK29_I2S_2CH_PHYS + I2S_TXR_BUFF;
508         } else {
509                 i2s->dma_capture->channel = DMACH_I2S_8CH_RX;
510                 i2s->dma_capture->dma_addr = RK29_I2S_8CH_PHYS + I2S_RXR_BUFF;
511                 i2s->dma_playback->channel = DMACH_I2S_8CH_TX;
512                 i2s->dma_playback->dma_addr = RK29_I2S_8CH_PHYS + I2S_TXR_BUFF;
513         }
514
515         i2s->dma_capture->client = &rk29_dma_client_in;
516         i2s->dma_capture->dma_size = 4;
517         i2s->dma_playback->client = &rk29_dma_client_out;
518         i2s->dma_playback->dma_size = 4;
519
520         i2s->iis_clk = clk_get(&pdev->dev, "i2s");
521         if (IS_ERR(i2s->iis_clk)) {
522                 dev_err(&pdev->dev, "failed to get i2s clk\n");
523                 ret = PTR_ERR(i2s->iis_clk);
524                 goto err;
525         }
526
527         clk_enable(i2s->iis_clk);
528
529         ret = rk29_i2s_probe(pdev, dai, i2s, 0);
530         if (ret)
531                 goto err_clk;
532
533         ret = rk29_i2s_register_dai(dai);
534         if (ret != 0)
535                 goto err_i2sv2;
536
537         return 0;
538
539 err_i2sv2:
540         /* Not implemented for I2Sv2 core yet */
541 err_clk:
542         clk_put(i2s->iis_clk);
543 err:
544         return ret;
545 }
546
547
548 static int __devexit rockchip_i2s_remove(struct platform_device *pdev)
549 {
550         snd_soc_unregister_dai(&rk29_i2s_dai);
551
552         return 0;
553 }
554
555 static struct platform_driver rockchip_i2s_driver = {
556         .probe  = rockchip_i2s_probe,
557         .remove = __devexit_p(rockchip_i2s_remove),
558         .driver = {
559                 .name   = "rk29-i2s",
560                 .owner  = THIS_MODULE,
561         },
562 };
563
564 static int __init rockchip_i2s_init(void)
565 {
566         printk(KERN_INFO
567                 "Enter Func = %s\n", __func__);
568         return  platform_driver_register(&rockchip_i2s_driver);
569 }
570 module_init(rockchip_i2s_init);
571
572 static void __exit rockchip_i2s_exit(void)
573 {
574         platform_driver_unregister(&rockchip_i2s_driver);
575 }
576 module_exit(rockchip_i2s_exit);
577
578 /* Module information */
579 MODULE_AUTHOR("rockchip");
580 MODULE_DESCRIPTION("ROCKCHIP IIS ASoC Interface");
581 MODULE_LICENSE("GPL");
582