1 /*$_FOR_ROCKCHIP_RBOX_$*/
2 /*$_rbox_$_modify_$_huangzhibao for spdif output*/
4 /* sound/soc/rockchip/rk_spdif.c
6 * ALSA SoC Audio Layer - rockchip S/PDIF Controller driver
8 * Copyright (c) 2010 rockchip Electronics Co. Ltd
9 * http://www.rockchip.com/
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.
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>
24 #include <linux/of_gpio.h>
25 #include <linux/clk.h>
27 #include <linux/platform_device.h>
28 #include <linux/pm_runtime.h>
29 #include <linux/regmap.h>
30 #include <linux/slab.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>
41 #include <linux/spinlock.h>
46 #define RK_SPDIF_DBG(x...) printk(KERN_INFO "rk_spdif:"x)
48 #define RK_SPDIF_DBG(x...) do { } while (0)
61 #define DATA_OUTBUF 0x20
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)
69 #define CFGR_HALFWORD_TX_ENABLE (0x1 << 2)
70 #define CFGR_HALFWORD_TX_DISABLE (0x0 << 2)
71 #define CFGR_HALFWORD_TX_MASK (0x1 << 2)
73 #define CFGR_CLK_RATE_MASK (0xFF<<16)
75 #define CFGR_JUSTIFIED_RIGHT (0<<3)
76 #define CFGR_JUSTIFIED_LEFT (1<<3)
77 #define CFGR_JUSTIFIED_MASK (1<<3)
79 #define XFER_TRAN_STOP (0)
80 #define XFER_TRAN_START (1)
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)
87 #define DMACR_TRAN_DATA_LEVEL 0x10
88 #define DMACR_TRAN_DATA_LEVEL_MASK 0x1F
90 #define DMACR_TRAN_DMA_MASK (0x3F)
94 struct rockchip_spdif_info {
97 unsigned long clk_rate;
99 struct snd_dmaengine_dai_dma_data dma_playback;
102 static inline struct rockchip_spdif_info *to_info(struct snd_soc_dai *cpu_dai)
104 return snd_soc_dai_get_drvdata(cpu_dai);
107 static void spdif_snd_txctrl(struct rockchip_spdif_info *spdif, int on)
109 void __iomem *regs = spdif->regs;
112 RK_SPDIF_DBG( "Entered %s\n", __func__);
114 xfer = readl(regs + XFER) & XFER_MASK;
115 opr = readl(regs + DMACR) & DMACR_TRAN_DMA_MASK & (~DMACR_TRAN_DMA_CTL_MASK);
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));
124 xfer &= ~XFER_TRAN_START;
125 opr &= ~DMACR_TRAN_DMA_ENABLE;
126 writel(xfer, regs + XFER);
127 writel(opr|0x10, regs + DMACR);
131 static int spdif_set_syclk(struct snd_soc_dai *cpu_dai,
132 int clk_id, unsigned int freq, int dir)
134 struct rockchip_spdif_info *spdif = to_info(cpu_dai);
136 RK_SPDIF_DBG("Entered %s\n", __func__);
138 spdif->clk_rate = freq;
143 static int spdif_trigger(struct snd_pcm_substream *substream, int cmd,
144 struct snd_soc_dai *dai)
146 struct snd_soc_pcm_runtime *rtd = substream->private_data;
147 struct rockchip_spdif_info *spdif = to_info(rtd->cpu_dai);
150 RK_SPDIF_DBG( "Entered %s\n", __func__);
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);
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);
175 static int spdif_hw_params(struct snd_pcm_substream *substream,
176 struct snd_pcm_hw_params *params,
177 struct snd_soc_dai *dai)
179 struct rockchip_spdif_info *spdif = to_info(dai);
180 void __iomem *regs = spdif->regs;
184 RK_SPDIF_DBG("Entered %s\n", __func__);
186 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
187 dai->playback_dma_data = &spdif->dma_playback;
189 printk("spdif:Capture is not supported\n");
193 spin_lock_irqsave(&spdif->lock, flags);
195 cfgr = readl(regs + CFGR) & CFGR_VALID_DATA_MASK;
197 cfgr &= ~CFGR_VALID_DATA_MASK;
198 switch (params_format(params)) {
199 case SNDRV_PCM_FORMAT_S16_LE:
200 cfgr |= CFGR_VALID_DATA_16bit;
202 case SNDRV_PCM_FORMAT_S20_3LE :
203 cfgr |= CFGR_VALID_DATA_20bit;
205 case SNDRV_PCM_FORMAT_S24_LE:
206 cfgr |= CFGR_VALID_DATA_24bit;
212 cfgr &= ~CFGR_HALFWORD_TX_MASK;
213 cfgr |= CFGR_HALFWORD_TX_ENABLE;
215 cfgr &= ~CFGR_CLK_RATE_MASK;
218 cfgr &= ~CFGR_JUSTIFIED_MASK;
219 cfgr |= CFGR_JUSTIFIED_RIGHT;
221 writel(cfgr, regs + CFGR);
223 dmac = readl(regs + DMACR) & DMACR_TRAN_DMA_MASK & (~DMACR_TRAN_DATA_LEVEL_MASK);
225 writel(dmac, regs + DMACR);
227 spin_unlock_irqrestore(&spdif->lock, flags);
231 spin_unlock_irqrestore(&spdif->lock, flags);
236 static int spdif_suspend(struct snd_soc_dai *cpu_dai)
238 RK_SPDIF_DBG( "spdif:Entered %s\n", __func__);
243 static int spdif_resume(struct snd_soc_dai *cpu_dai)
245 RK_SPDIF_DBG( "spdif:Entered %s\n", __func__);
250 #define spdif_suspend NULL
251 #define spdif_resume NULL
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,
260 struct snd_soc_dai_driver rockchip_spdif_dai = {
261 .name = "rockchip-spdif",
263 .stream_name = "SPDIF Playback",
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,
278 static const struct snd_soc_component_driver rockchip_spdif_component = {
279 .name = "rockchip-spdif",
282 static int spdif_probe(struct platform_device *pdev)
284 struct resource *mem_res;
285 struct rockchip_spdif_info *spdif;
288 RK_SPDIF_DBG("Entered %s\n", __func__);
290 spdif = devm_kzalloc(&pdev->dev, sizeof(struct rockchip_spdif_info), GFP_KERNEL);
292 dev_err(&pdev->dev, "Can't allocate spdif info\n");
296 spin_lock_init(&spdif->lock);
298 mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
300 printk("spdif:Unable to get register resource.\n");
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);
309 clk_prepare_enable(spdif->clk);
310 clk_set_rate(spdif->clk, 11289600);
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");
320 spdif->regs = devm_ioremap(&pdev->dev, mem_res->start, resource_size(mem_res));
322 dev_err(&pdev->dev, "ioremap failed\n");
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;
331 //set dev name to driver->name for sound card register
332 dev_set_name(&pdev->dev, "%s", pdev->dev.driver->name);
334 ret = snd_soc_register_component(&pdev->dev, &rockchip_spdif_component,
335 &rockchip_spdif_dai, 1);
337 dev_err(&pdev->dev, "Could not register DAI: %d\n", ret);
342 ret = rockchip_pcm_platform_register(&pdev->dev);
344 dev_err(&pdev->dev, "Could not register PCM: %d\n", ret);
345 goto err_unregister_component;
348 dev_set_drvdata(&pdev->dev, spdif);
350 RK_SPDIF_DBG("spdif:spdif probe ok!\n");
354 err_unregister_component:
355 snd_soc_unregister_component(&pdev->dev);
361 static int spdif_remove(struct platform_device *pdev)
363 RK_SPDIF_DBG("Entered %s\n", __func__);
365 rockchip_pcm_platform_unregister(&pdev->dev);
366 snd_soc_unregister_component(&pdev->dev);
372 static const struct of_device_id exynos_spdif_match[] = {
373 { .compatible = "rockchip-spdif"},
376 MODULE_DEVICE_TABLE(of, exynos_spdif_match);
379 static struct platform_driver rockchip_spdif_driver = {
380 .probe = spdif_probe,
381 .remove = spdif_remove,
383 .name = "rockchip-spdif",
384 .owner = THIS_MODULE,
385 .of_match_table = of_match_ptr(exynos_spdif_match),
388 module_platform_driver(rockchip_spdif_driver);
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");