Merge tag 'lsk-android-14.02' into develop-3.10
[firefly-linux-kernel-4.4.55.git] / sound / soc / rockchip / rk_spdif.c
1 /*$_FOR_ROCKCHIP_RBOX_$*/
2 /*$_rbox_$_modify_$_huangzhibao for spdif output*/
3
4 /* sound/soc/rockchip/rk_spdif.c
5  *
6  * ALSA SoC Audio Layer - rockchip S/PDIF Controller driver
7  *
8  * Copyright (c) 2010 rockchip Electronics Co. Ltd
9  *              http://www.rockchip.com/
10  *
11  * This program is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License version 2 as
13  * published by the Free Software Foundation.
14  */
15
16 #include <linux/init.h>
17 #include <linux/module.h>
18 #include <linux/interrupt.h>
19 #include <linux/device.h>
20 #include <linux/delay.h>
21 #include <linux/clk.h>
22 #include <linux/version.h>
23 #include <linux/of.h>
24 #include <linux/of_gpio.h>
25 #include <linux/clk.h>
26 #include <linux/io.h>
27 #include <linux/platform_device.h>
28 #include <linux/pm_runtime.h>
29 #include <linux/regmap.h>
30 #include <linux/slab.h>
31
32 #include <asm/dma.h>
33 #include <sound/core.h>
34 #include <sound/pcm.h>
35 #include <sound/pcm_params.h>
36 #include <sound/initval.h>
37 #include <sound/soc.h>
38 #include <sound/dmaengine_pcm.h>
39 #include <asm/io.h>
40
41 #include <linux/spinlock.h>
42
43 #include "rk_pcm.h"
44
45 #if 0
46 #define RK_SPDIF_DBG(x...) printk(KERN_INFO "rk_spdif:"x)
47 #else
48 #define RK_SPDIF_DBG(x...) do { } while (0)
49 #endif
50
51
52 /* Registers */
53 #define CFGR                            0x00
54 #define SDBLR                           0x04
55 #define DMACR                           0x08
56 #define INTCR                           0x0C
57 #define INTSR                     0x10
58 #define XFER                            0x18
59 #define SMPDR                           0x20
60
61 #define DATA_OUTBUF                     0x20   
62  
63 #define CFGR_MASK                       0x0ffffff
64 #define CFGR_VALID_DATA_16bit       (00)
65 #define CFGR_VALID_DATA_20bit       (01)
66 #define CFGR_VALID_DATA_24bit       (10)
67 #define CFGR_VALID_DATA_MASK        (11)
68
69 #define CFGR_HALFWORD_TX_ENABLE     (0x1 << 2)
70 #define CFGR_HALFWORD_TX_DISABLE    (0x0 << 2)
71 #define CFGR_HALFWORD_TX_MASK       (0x1 << 2)  
72
73 #define CFGR_CLK_RATE_MASK          (0xFF<<16)                 
74
75 #define CFGR_JUSTIFIED_RIGHT        (0<<3)
76 #define CFGR_JUSTIFIED_LEFT         (1<<3)
77 #define CFGR_JUSTIFIED_MASK         (1<<3)
78
79 #define XFER_TRAN_STOP        (0)
80 #define XFER_TRAN_START       (1)
81 #define XFER_MASK             (1)
82
83 #define DMACR_TRAN_DMA_DISABLE   (0<<5)
84 #define DMACR_TRAN_DMA_ENABLE   (1<<5)
85 #define DMACR_TRAN_DMA_CTL_MASK   (1<<5)
86
87 #define DMACR_TRAN_DATA_LEVEL       0x10
88 #define DMACR_TRAN_DATA_LEVEL_MASK  0x1F
89
90 #define DMACR_TRAN_DMA_MASK   (0x3F)
91
92
93  
94 struct rockchip_spdif_info {
95         spinlock_t      lock;
96         void __iomem    *regs;
97         unsigned long   clk_rate;
98         struct clk      *clk;
99         struct snd_dmaengine_dai_dma_data       dma_playback;
100 };
101
102 static inline struct rockchip_spdif_info *to_info(struct snd_soc_dai *cpu_dai)
103 {
104         return snd_soc_dai_get_drvdata(cpu_dai);
105 }
106
107 static void spdif_snd_txctrl(struct rockchip_spdif_info *spdif, int on)
108 {
109         void __iomem *regs = spdif->regs;
110         u32 opr,xfer;
111
112         RK_SPDIF_DBG( "Entered %s\n", __func__);
113
114         xfer = readl(regs + XFER) & XFER_MASK;
115         opr  = readl(regs + DMACR) & DMACR_TRAN_DMA_MASK & (~DMACR_TRAN_DMA_CTL_MASK);
116         
117         if (on){
118                 xfer |= XFER_TRAN_START;
119                 opr |= DMACR_TRAN_DMA_ENABLE;
120                 writel(xfer, regs + XFER);
121                 writel(opr|0x10, regs + DMACR);
122                 RK_SPDIF_DBG("on xfer=0x%x,opr=0x%x\n",readl(regs + XFER),readl(regs + DMACR));
123     }else{
124             xfer &= ~XFER_TRAN_START;
125             opr  &= ~DMACR_TRAN_DMA_ENABLE; 
126                 writel(xfer, regs + XFER);
127                 writel(opr|0x10, regs + DMACR);
128     }
129 }
130
131 static int spdif_set_syclk(struct snd_soc_dai *cpu_dai,
132                                 int clk_id, unsigned int freq, int dir)
133 {
134         struct rockchip_spdif_info *spdif = to_info(cpu_dai);
135
136         RK_SPDIF_DBG("Entered %s\n", __func__);
137
138         spdif->clk_rate = freq;
139
140         return 0;
141 }
142
143 static int spdif_trigger(struct snd_pcm_substream *substream, int cmd,
144                                 struct snd_soc_dai *dai)
145 {
146         struct snd_soc_pcm_runtime *rtd = substream->private_data;
147         struct rockchip_spdif_info *spdif = to_info(rtd->cpu_dai);
148         unsigned long flags;
149
150         RK_SPDIF_DBG( "Entered %s\n", __func__);
151
152         switch (cmd) {
153         case SNDRV_PCM_TRIGGER_START:
154         case SNDRV_PCM_TRIGGER_RESUME:
155         case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
156                 spin_lock_irqsave(&spdif->lock, flags);
157                 spdif_snd_txctrl(spdif, 1);
158                 spin_unlock_irqrestore(&spdif->lock, flags);
159                 break;
160         case SNDRV_PCM_TRIGGER_STOP:
161         case SNDRV_PCM_TRIGGER_SUSPEND:
162         case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
163                 spin_lock_irqsave(&spdif->lock, flags);
164                 spdif_snd_txctrl(spdif, 0);
165                 spin_unlock_irqrestore(&spdif->lock, flags);
166                 break;
167         default:
168                 return -EINVAL;
169         }
170
171         return 0;
172 }
173
174
175 static int spdif_hw_params(struct snd_pcm_substream *substream,
176                                 struct snd_pcm_hw_params *params,
177                                 struct snd_soc_dai *dai)
178 {
179         struct rockchip_spdif_info *spdif = to_info(dai);
180         void __iomem *regs = spdif->regs;
181         unsigned long flags;
182         int cfgr, dmac;
183
184         RK_SPDIF_DBG("Entered %s\n", __func__);
185
186         if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
187                 dai->playback_dma_data = &spdif->dma_playback;
188         else {
189                 printk("spdif:Capture is not supported\n");
190                 return -EINVAL;
191         }
192
193         spin_lock_irqsave(&spdif->lock, flags);
194         
195         cfgr = readl(regs + CFGR) & CFGR_VALID_DATA_MASK;
196         
197         cfgr &= ~CFGR_VALID_DATA_MASK;
198         switch (params_format(params)) {
199         case SNDRV_PCM_FORMAT_S16_LE:
200                 cfgr |= CFGR_VALID_DATA_16bit;
201                 break;
202         case SNDRV_PCM_FORMAT_S20_3LE :
203                 cfgr |= CFGR_VALID_DATA_20bit;
204                 break;
205         case SNDRV_PCM_FORMAT_S24_LE:
206                 cfgr |= CFGR_VALID_DATA_24bit;
207                 break;                  
208         default:
209                 goto err;
210         }
211         
212         cfgr &= ~CFGR_HALFWORD_TX_MASK;
213         cfgr |= CFGR_HALFWORD_TX_ENABLE;
214         
215         cfgr &= ~CFGR_CLK_RATE_MASK;
216         cfgr |= (1<<16);
217         
218         cfgr &= ~CFGR_JUSTIFIED_MASK;
219         cfgr |= CFGR_JUSTIFIED_RIGHT;
220         
221         writel(cfgr, regs + CFGR);
222   
223         dmac = readl(regs + DMACR) & DMACR_TRAN_DMA_MASK & (~DMACR_TRAN_DATA_LEVEL_MASK);
224         dmac |= 0x10;
225         writel(dmac, regs + DMACR);
226   
227         spin_unlock_irqrestore(&spdif->lock, flags);
228
229         return 0;
230 err:
231         spin_unlock_irqrestore(&spdif->lock, flags);
232         return -EINVAL;
233 }
234
235 #ifdef CONFIG_PM
236 static int spdif_suspend(struct snd_soc_dai *cpu_dai)
237 {
238         RK_SPDIF_DBG( "spdif:Entered %s\n", __func__);
239
240         return 0;
241 }
242
243 static int spdif_resume(struct snd_soc_dai *cpu_dai)
244 {
245         RK_SPDIF_DBG( "spdif:Entered %s\n", __func__);
246
247         return 0;
248 }
249 #else
250 #define spdif_suspend NULL
251 #define spdif_resume NULL
252 #endif
253
254 static struct snd_soc_dai_ops spdif_dai_ops = {
255         .set_sysclk     = spdif_set_syclk,
256         .trigger        = spdif_trigger,
257         .hw_params      = spdif_hw_params,
258 };
259
260 struct snd_soc_dai_driver rockchip_spdif_dai = {
261         .name = "rockchip-spdif",
262         .playback = {
263                 .stream_name = "SPDIF Playback",
264                 .channels_min = 2,
265                 .channels_max = 2,
266                 .rates = (SNDRV_PCM_RATE_32000 |
267                                 SNDRV_PCM_RATE_44100 |
268                                 SNDRV_PCM_RATE_48000 |
269                                 SNDRV_PCM_RATE_96000),
270                 .formats = SNDRV_PCM_FMTBIT_S16_LE|
271                 SNDRV_PCM_FMTBIT_S20_3LE|
272                 SNDRV_PCM_FMTBIT_S24_LE, },
273         .ops = &spdif_dai_ops,
274         .suspend = spdif_suspend,
275         .resume = spdif_resume,
276 };
277
278 static const struct snd_soc_component_driver rockchip_spdif_component = {
279         .name           = "rockchip-spdif",
280 };
281
282 static int spdif_probe(struct platform_device *pdev)
283 {
284         struct resource *mem_res;
285         struct rockchip_spdif_info *spdif;
286         int ret;
287
288         RK_SPDIF_DBG("Entered %s\n", __func__);
289
290         spdif = devm_kzalloc(&pdev->dev, sizeof(struct rockchip_spdif_info), GFP_KERNEL);
291         if (!spdif) {
292                 dev_err(&pdev->dev, "Can't allocate spdif info\n");
293                 return -ENOMEM;
294         }
295
296         spin_lock_init(&spdif->lock);
297
298         mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
299         if (!mem_res) {
300                 printk("spdif:Unable to get register resource.\n");
301                 return -ENXIO;
302         }
303
304         spdif->clk= clk_get(&pdev->dev, NULL);
305         if (IS_ERR(spdif->clk)) {
306                 dev_err(&pdev->dev, "Can't retrieve spdif clock\n");
307                 return PTR_ERR(spdif->clk);
308         }
309         clk_prepare_enable(spdif->clk);
310         clk_set_rate(spdif->clk, 11289600);
311
312         /* Request S/PDIF Register's memory region */
313         if (!request_mem_region(mem_res->start,
314                                 resource_size(mem_res), "rockchip-spdif")) {
315                 printk("spdif:Unable to request register region\n");
316                 ret = -EBUSY;
317                 goto err_clk_put;
318         }
319
320         spdif->regs = devm_ioremap(&pdev->dev, mem_res->start, resource_size(mem_res));
321         if (!spdif->regs) {
322                 dev_err(&pdev->dev, "ioremap failed\n");
323                 ret = -ENOMEM;
324                 goto err_clk_put;
325         }
326
327         spdif->dma_playback.addr = mem_res->start + DATA_OUTBUF;
328         spdif->dma_playback.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
329         spdif->dma_playback.maxburst = 4;
330
331         //set dev name to driver->name for sound card register
332         dev_set_name(&pdev->dev, "%s", pdev->dev.driver->name);
333
334         ret = snd_soc_register_component(&pdev->dev, &rockchip_spdif_component,
335                 &rockchip_spdif_dai, 1);
336         if (ret) {
337                 dev_err(&pdev->dev, "Could not register DAI: %d\n", ret);
338                 ret = -ENOMEM;
339                 goto err_clk_put;
340         }
341
342         ret = rockchip_pcm_platform_register(&pdev->dev);
343         if (ret) {
344                 dev_err(&pdev->dev, "Could not register PCM: %d\n", ret);
345                 goto err_unregister_component;
346         }
347
348         dev_set_drvdata(&pdev->dev, spdif);
349
350         RK_SPDIF_DBG("spdif:spdif probe ok!\n");
351
352         return 0;
353
354 err_unregister_component:
355         snd_soc_unregister_component(&pdev->dev);
356 err_clk_put:
357         clk_put(spdif->clk);
358         return ret;
359 }
360
361 static int spdif_remove(struct platform_device *pdev)
362 {
363         RK_SPDIF_DBG("Entered %s\n", __func__);
364         
365         rockchip_pcm_platform_unregister(&pdev->dev);
366         snd_soc_unregister_component(&pdev->dev);
367
368         return 0;
369 }
370
371 #ifdef CONFIG_OF
372 static const struct of_device_id exynos_spdif_match[] = {
373         { .compatible = "rockchip-spdif"},
374         {},
375 };
376 MODULE_DEVICE_TABLE(of, exynos_spdif_match);
377 #endif
378
379 static struct platform_driver rockchip_spdif_driver = {
380         .probe  = spdif_probe,
381         .remove = spdif_remove,
382         .driver = {
383                 .name   = "rockchip-spdif",
384                 .owner  = THIS_MODULE,
385                 .of_match_table = of_match_ptr(exynos_spdif_match),
386         },
387 };
388 module_platform_driver(rockchip_spdif_driver);
389
390 MODULE_AUTHOR("Seungwhan Youn, <sw.youn@rockchip.com>");
391 MODULE_DESCRIPTION("rockchip S/PDIF Controller Driver");
392 MODULE_LICENSE("GPL");
393 MODULE_ALIAS("platform:rockchip-spdif");