rk spdif: support
authoryzq <yzq@rock-chips.com>
Tue, 7 May 2013 03:42:27 +0000 (11:42 +0800)
committeryzq <yzq@rock-chips.com>
Tue, 7 May 2013 04:27:43 +0000 (12:27 +0800)
arch/arm/configs/rk3188_jettaplus_defconfig
arch/arm/mach-rk30/devices.c
sound/soc/rk29/Kconfig
sound/soc/rk29/Makefile
sound/soc/rk29/rk_spdif.c [new file with mode: 0644]
sound/soc/rk29/spdif.c [new file with mode: 0644]
sound/soc/rk29/spdif.h [new file with mode: 0644]

index 7bf889a59e3d55e7893f2685d13996e94055c4c3..276e3a284409cf07f9e0f56670a4a45ac345118f 100644 (file)
@@ -326,7 +326,8 @@ CONFIG_SND=y
 # CONFIG_SND_ARM is not set
 CONFIG_SND_SOC=y
 CONFIG_SND_RK29_SOC=y
-CONFIG_SND_I2S_DMA_EVENT_STATIC=y
+CONFIG_SND_I2S_DMA_EVENT_DYNAMIC=y
+CONFIG_SND_RK_SOC_SPDIF=y
 CONFIG_SND_RK29_SOC_RK616=y
 CONFIG_SND_RK29_CODEC_SOC_SLAVE=y
 CONFIG_UHID=y
index 32ddb4b9f1a435917338ecd5d2b5bd2430bf239f..a51ae35545c6b771b774cfcf6c39de07808fd7c8 100755 (executable)
@@ -1112,6 +1112,35 @@ static void __init rk30_init_sdmmc(void)
 #endif
 }
 
+#ifdef CONFIG_SND_RK_SOC_SPDIF
+static struct resource resources_spdif[] = {
+    [0] = {
+               .name   = "spdif_base",
+        .start         = RK30_SPDIF_PHYS,
+        .end    = RK30_SPDIF_PHYS + RK30_SPDIF_SIZE - 1,
+        .flags  = IORESOURCE_MEM,
+    },
+    [1] = {
+               .name   = "spdif_irq",
+        .start         = IRQ_SPDIF,
+        .end    = IRQ_SPDIF,
+        .flags  = IORESOURCE_IRQ,
+    },
+    [2] = {
+               .name   = "spdif_dma",
+        .start         = DMACH_SPDIF_TX,
+        .end    = DMACH_SPDIF_TX,
+        .flags  = IORESOURCE_DMA,
+    },
+};
+struct platform_device rk29_device_spdif = {
+    .name             = "rk-spdif",
+    .id               = 0,
+    .num_resources    = ARRAY_SIZE(resources_spdif),
+    .resource         = resources_spdif,
+};
+#endif
+
 #ifdef CONFIG_RK29_VMAC
 static u64 eth_dmamask = DMA_BIT_MASK(32);
 static struct resource resources_vmac[] = {
@@ -1220,6 +1249,10 @@ static int __init rk30_init_devices(void)
        rk_serial_debug_init(DEBUG_UART_BASE, IRQ_DEBUG_UART, IRQ_UART_SIGNAL, -1);
 #endif
        rk30_init_i2s();
+
+#ifdef CONFIG_SND_RK_SOC_SPDIF
+    platform_device_register(&rk29_device_spdif);
+#endif
 #ifdef CONFIG_RK29_VMAC
        platform_device_register(&device_vmac);
 #endif
index 739f55e24c499d247b75de9f95a5af70c8f8dbfb..682fb18917b464306d58255a341fd0b9d0c553bb 100755 (executable)
@@ -42,6 +42,9 @@ config SND_RK_SOC_I2S2_2CH
        help
                This supports the use of the 2 Channel I2S2 interface on rk30 processors.
 
+config SND_ROCKCHIP_SPDIF
+       tristate
+       select SND_SOC_SPDIF
 if     SND_RK29_SOC_I2S_2CH || SND_RK29_SOC_I2S_8CH || SND_RK_SOC_I2S2_2CH
 choice
   bool "Set i2s on DMA event mode"
@@ -53,7 +56,14 @@ choice
                tristate  "static mode"
 endchoice
 endif
-
+config SND_RK_SOC_SPDIF
+       bool "spdif support for rockchip rk29 or rk30"
+       depends on SND_RK29_SOC 
+       select SND_ROCKCHIP_SPDIF
+       help
+         Say Y if you want to add support for SoC audio on rockchip
+         with the spdif.
+         
 config SND_RK29_SOC_SPDIF
        bool "Soc RK29 SPDIF support"
        depends on SND_RK29_SOC
index cfd5e3bbc1a2486d333b25b3ff0b8b4cd58bf1e4..728bdae8dcdede685c889bb1b6bf04133e58c4c2 100755 (executable)
@@ -5,11 +5,11 @@ snd-soc-rockchip-i2s-objs := rk29_i2s.o
 else
 snd-soc-rockchip-i2s-objs := rk30_i2s.o
 endif
-snd-soc-rockchip-spdif-objs := rk29_spdif.o
+snd-soc-rockchip-spdif-objs := spdif.o
 
 obj-$(CONFIG_SND_RK29_SOC) += snd-soc-rockchip.o
 obj-$(CONFIG_SND_RK29_SOC_I2S) += snd-soc-rockchip-i2s.o
-obj-$(CONFIG_SND_RK29_SOC_SPDIF) += snd-soc-rockchip-spdif.o
+obj-$(CONFIG_SND_ROCKCHIP_SPDIF) += snd-soc-rockchip-spdif.o
 
 # ROCKCHIP Machine Support
 snd-soc-wm8900-objs := rk29_wm8900.o
@@ -33,6 +33,7 @@ snd-soc-rk616-objs := rk_rk616.o
 snd-soc-aic3262-objs := rk29_aic3262.o
 snd-soc-rk2928-objs := rk2928-card.o
 snd-soc-es8323-objs := rk29_es8323.o
+snd-soc-rk_spdif-objs := rk_spdif.o
 
 obj-$(CONFIG_SND_RK29_SOC_WM8994) += snd-soc-wm8994.o
 obj-$(CONFIG_SND_RK29_SOC_WM8988) += snd-soc-wm8988.o
@@ -53,5 +54,6 @@ obj-$(CONFIG_SND_RK29_SOC_AIC3262) += snd-soc-aic3262.o
 obj-$(CONFIG_SND_RK29_SOC_HDMI) += snd-soc-hdmi.o
 obj-$(CONFIG_SND_RK29_SOC_RK610) += snd-soc-rk610.o
 obj-$(CONFIG_SND_RK29_SOC_RK616) += snd-soc-rk616.o
+obj-$(CONFIG_SND_RK_SOC_SPDIF) += snd-soc-rk_spdif.o
 obj-$(CONFIG_SND_RK_SOC_RK2928) += snd-soc-rk2928.o
 obj-$(CONFIG_SND_RK29_SOC_ES8323) += snd-soc-es8323.o
diff --git a/sound/soc/rk29/rk_spdif.c b/sound/soc/rk29/rk_spdif.c
new file mode 100644 (file)
index 0000000..6ec311e
--- /dev/null
@@ -0,0 +1,186 @@
+/*$_FOR_ROCKCHIP_RBOX_$*/
+/*$_rbox_$_modify_$_huangzhibao for spdif output*/
+
+/*
+ * smdk_spdif.c  --  S/PDIF audio for SMDK
+ *
+ * Copyright 2010 Samsung Electronics Co. Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ */
+
+#include <linux/clk.h>
+
+#include <sound/soc.h>
+
+#include "spdif.h"
+#include <mach/iomux.h>
+
+#if 0
+#define RK_SPDIF_DBG(x...) printk(KERN_INFO "rk_spdif:"x)
+#else
+#define RK_SPDIF_DBG(x...) do { } while (0)
+#endif
+
+
+static int set_audio_clock_rate(unsigned long pll_rate,
+                               unsigned long audio_rate)
+{
+       struct clk *hclk_spdif, *sclk_spdif;
+
+#if defined (CONFIG_ARCH_RK30) || (CONFIG_ARCH_RK3188) 
+       hclk_spdif = clk_get(NULL, "hclk_spdif");
+       if (IS_ERR(hclk_spdif)) {
+               printk(KERN_ERR "spdif:failed to get hclk_spdif\n");
+               return -ENOENT;
+       }
+
+       clk_set_rate(hclk_spdif, pll_rate);
+       clk_put(hclk_spdif);
+#endif
+
+       sclk_spdif = clk_get(NULL, "spdif");
+       if (IS_ERR(sclk_spdif)) {
+               printk(KERN_ERR "spdif:failed to get sclk_spdif\n");
+               return -ENOENT;
+       }
+
+       clk_set_rate(sclk_spdif, audio_rate);
+       clk_put(sclk_spdif);
+
+       return 0;
+}
+
+static int rk_hw_params(struct snd_pcm_substream *substream,
+               struct snd_pcm_hw_params *params)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+       unsigned long pll_out, rclk_rate;
+       int ret, ratio;
+
+  RK_SPDIF_DBG("spdif:Entered %s\n", __func__);
+  
+       switch (params_rate(params)) {
+       case 44100:
+               pll_out = 11289600;
+               break;
+       case 32000:
+               pll_out = 8192000;
+               break;
+       case 48000:
+               pll_out = 12288000;
+               break;
+       case 96000:
+               pll_out = 24576000;
+               break;
+       default:
+               printk("rk_spdif: params not support\n");
+               return -EINVAL;
+       }
+
+       ratio = 256;
+       rclk_rate = params_rate(params) * ratio;
+
+       /* Set audio source clock rates */
+       ret = set_audio_clock_rate(pll_out, rclk_rate);
+       if (ret < 0)
+               return ret;
+
+       /* Set S/PDIF uses internal source clock */
+       //ret = snd_soc_dai_set_sysclk(cpu_dai, SND_SOC_SPDIF_INT_MCLK,
+                                       //rclk_rate, SND_SOC_CLOCK_IN);
+       //if (ret < 0)
+               //return ret;
+
+       return ret;
+}
+
+static struct snd_soc_ops rk_spdif_ops = {
+       .hw_params = rk_hw_params,
+};
+
+static struct snd_soc_dai_link rk_dai = {
+       .name = "SPDIF",
+       .stream_name = "SPDIF PCM Playback",
+       .platform_name = "rockchip-audio",
+       .cpu_dai_name = "rk-spdif.0",
+       .codec_dai_name = "dit-hifi",
+       .codec_name = "spdif-dit",
+       .ops = &rk_spdif_ops,
+};
+
+static struct snd_soc_card rk_spdif = {
+       .name = "ROCKCHIP-SPDIF",
+       .dai_link = &rk_dai,
+       .num_links = 1,
+};
+
+static struct platform_device *rk_snd_spdif_dit_device;
+static struct platform_device *rk_snd_spdif_device;
+
+static int __init rk_spdif_init(void)
+{
+       int ret;
+       
+       RK_SPDIF_DBG("Entered %s\n", __func__);
+       
+       rk_snd_spdif_dit_device = platform_device_alloc("spdif-dit", -1);
+       if (!rk_snd_spdif_dit_device){
+               printk("spdif:platform_device_alloc spdif-dit\n");
+               return -ENOMEM;
+  }
+       ret = platform_device_add(rk_snd_spdif_dit_device);
+       if (ret)
+               goto err1;
+
+       rk_snd_spdif_device = platform_device_alloc("soc-audio", -3);
+       if (!rk_snd_spdif_device) {
+               printk("spdif:platform_device_alloc rk_soc-audio\n");
+               ret = -ENOMEM;
+               goto err2;
+       }
+       
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37))
+       platform_set_drvdata(rk_snd_spdif_device, &rk_spdif);
+#else
+       platform_set_drvdata(rk_snd_spdif_device, &rk_spdif);
+       rk_spdif.dev = &rk_snd_spdif_device->dev;
+#endif
+
+       //platform_set_drvdata(rk_snd_spdif_device, &rk_spdif);
+
+       ret = platform_device_add(rk_snd_spdif_device);
+       if (ret)
+               goto err3;
+       
+       RK_SPDIF_DBG("rk_spdif_init ok\n");
+       return ret;
+err3:
+       platform_device_put(rk_snd_spdif_device);
+err2:
+       platform_device_del(rk_snd_spdif_dit_device);
+err1:
+       platform_device_put(rk_snd_spdif_dit_device);
+       
+       return ret;
+}
+
+static void __exit rk_spdif_exit(void)
+{
+       platform_device_unregister(rk_snd_spdif_device);
+       platform_device_unregister(rk_snd_spdif_dit_device);
+}
+
+//using late_initcall to make sure spdif is after board codec. added by zxg.
+//module_init(rk_spdif_init);
+late_initcall(rk_spdif_init);
+module_exit(rk_spdif_exit);
+
+MODULE_AUTHOR("hzb, <hzb@rock-chips.com>");
+MODULE_DESCRIPTION("ALSA SoC RK+S/PDIF");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/rk29/spdif.c b/sound/soc/rk29/spdif.c
new file mode 100644 (file)
index 0000000..53e4e7b
--- /dev/null
@@ -0,0 +1,485 @@
+/*$_FOR_ROCKCHIP_RBOX_$*/
+/*$_rbox_$_modify_$_huangzhibao for spdif output*/
+
+/* sound/soc/rockchip/spdif.c
+ *
+ * ALSA SoC Audio Layer - rockchip S/PDIF Controller driver
+ *
+ * Copyright (c) 2010 rockchip Electronics Co. Ltd
+ *             http://www.rockchip.com/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/version.h>
+
+#include <asm/dma.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+#include <asm/io.h>
+
+#include <mach/board.h>
+#include <mach/hardware.h>
+#include <mach/io.h>
+#include <mach/gpio.h>
+#include <mach/iomux.h>
+
+#if defined (CONFIG_ARCH_RK29)
+#include <mach/rk29-dma-pl330.h>
+#endif
+
+#if defined (CONFIG_ARCH_RK30)
+#include <mach/dma-pl330.h>
+#endif
+
+#if defined (CONFIG_ARCH_RK3188)
+#include <mach/dma-pl330.h>
+#endif
+
+#include "rk29_pcm.h"
+#include "spdif.h"
+
+#if 1
+#define RK_SPDIF_DBG(x...) printk(KERN_INFO "spdif:"x)
+#else
+#define RK_SPDIF_DBG(x...) do { } while (0)
+#endif
+
+
+/* Registers */
+#define CFGR                           0x00
+#define SDBLR                          0x04
+#define DMACR                          0x08
+#define INTCR                          0x0C
+#define INTSR                    0x10
+#define XFER                           0x18
+#define SMPDR                          0x20
+
+#define DATA_OUTBUF                    0x20   
+#define CFGR_MASK                      0x0ffffff
+#define CFGR_VALID_DATA_16bit       (00)
+#define CFGR_VALID_DATA_20bit       (01)
+#define CFGR_VALID_DATA_24bit       (10)
+#define CFGR_VALID_DATA_MASK        (11)
+
+#define CFGR_HALFWORD_TX_ENABLE     (0x1 << 2)
+#define CFGR_HALFWORD_TX_DISABLE    (0x0 << 2)
+#define CFGR_HALFWORD_TX_MASK       (0x1 << 2)  
+
+#define CFGR_CLK_RATE_MASK          (0xFF<<16)                 
+
+#define CFGR_JUSTIFIED_RIGHT        (0<<3)
+#define CFGR_JUSTIFIED_LEFT         (1<<3)
+#define CFGR_JUSTIFIED_MASK         (1<<3)
+
+#define XFER_TRAN_STOP        (0)
+#define XFER_TRAN_START       (1)
+#define XFER_MASK             (1)
+
+#define DMACR_TRAN_DMA_DISABLE   (0<<5)
+#define DMACR_TRAN_DMA_ENABLE   (1<<5)
+#define DMACR_TRAN_DMA_CTL_MASK   (1<<5)
+
+#define DMACR_TRAN_DATA_LEVEL       0x10
+#define DMACR_TRAN_DATA_LEVEL_MASK  0x1F
+
+#define DMACR_TRAN_DMA_MASK   (0x3F)
+
+
+struct rockchip_spdif_info {
+       spinlock_t      lock;
+       struct device   *dev;
+       void __iomem    *regs;
+       unsigned long   clk_rate;
+       struct clk      *hclk;
+       struct clk      *clk;
+       u32             saved_clkcon;
+       u32             saved_con;
+       u32             saved_cstas;
+       struct rockchip_pcm_dma_params  *dma_playback;
+};
+
+static struct rk29_dma_client spdif_dma_client_out = {
+       .name           = "SPDIF Stereo out"
+};
+
+static struct rockchip_pcm_dma_params spdif_stereo_out;
+
+static struct rockchip_spdif_info spdif_info;
+
+static inline struct rockchip_spdif_info *to_info(struct snd_soc_dai *cpu_dai)
+{
+       return snd_soc_dai_get_drvdata(cpu_dai);
+}
+
+static void spdif_snd_txctrl(struct rockchip_spdif_info *spdif, int on)
+{
+       void __iomem *regs = spdif->regs;
+       u32 opr,xfer;
+
+       RK_SPDIF_DBG( "Entered %s\n", __func__);
+
+       xfer = readl(regs + XFER) & XFER_MASK;
+       opr  = readl(regs + DMACR) & DMACR_TRAN_DMA_MASK & (~DMACR_TRAN_DMA_CTL_MASK);
+       
+       if (on){
+               xfer |= XFER_TRAN_START;
+               opr |= DMACR_TRAN_DMA_ENABLE;
+               writel(xfer, regs + XFER);
+               writel(opr|0x10, regs + DMACR);
+               RK_SPDIF_DBG("on xfer=0x%x,opr=0x%x\n",readl(regs + XFER),readl(regs + DMACR));
+  }    else{
+       xfer &= ~XFER_TRAN_START;
+       opr  &= ~DMACR_TRAN_DMA_ENABLE; 
+               writel(xfer, regs + XFER);
+               writel(opr|0x10, regs + DMACR);
+  }
+}
+
+static int spdif_set_syclk(struct snd_soc_dai *cpu_dai,
+                               int clk_id, unsigned int freq, int dir)
+{
+       struct rockchip_spdif_info *spdif = to_info(cpu_dai);
+       u32 clkcon;
+
+       RK_SPDIF_DBG("Entered %s\n", __func__);
+
+       spdif->clk_rate = freq;
+
+       return 0;
+}
+
+static int spdif_trigger(struct snd_pcm_substream *substream, int cmd,
+                               struct snd_soc_dai *dai)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct rockchip_spdif_info *spdif = to_info(rtd->cpu_dai);
+       unsigned long flags;
+
+       RK_SPDIF_DBG( "Entered %s\n", __func__);
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+       case SNDRV_PCM_TRIGGER_RESUME:
+       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+               spin_lock_irqsave(&spdif->lock, flags);
+               spdif_snd_txctrl(spdif, 1);
+               spin_unlock_irqrestore(&spdif->lock, flags);
+               break;
+       case SNDRV_PCM_TRIGGER_STOP:
+       case SNDRV_PCM_TRIGGER_SUSPEND:
+       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+               spin_lock_irqsave(&spdif->lock, flags);
+               spdif_snd_txctrl(spdif, 0);
+               spin_unlock_irqrestore(&spdif->lock, flags);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+
+static int spdif_hw_params(struct snd_pcm_substream *substream,
+                               struct snd_pcm_hw_params *params,
+                               struct snd_soc_dai *socdai)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct rockchip_spdif_info *spdif = to_info(rtd->cpu_dai);
+       void __iomem *regs = spdif->regs;
+       struct rockchip_pcm_dma_params *dma_data;
+       unsigned long flags;
+       int i, cfgr, dmac;
+
+       RK_SPDIF_DBG("Entered %s\n", __func__);
+
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+               dma_data = spdif->dma_playback;
+       else {
+               printk("spdif:Capture is not supported\n");
+               return -EINVAL;
+       }
+
+       snd_soc_dai_set_dma_data(rtd->cpu_dai, substream, dma_data);
+       spin_lock_irqsave(&spdif->lock, flags);
+       
+       cfgr = readl(regs + CFGR) & CFGR_VALID_DATA_MASK;
+       
+  cfgr &= ~CFGR_VALID_DATA_MASK;
+       switch (params_format(params)) {
+       case SNDRV_PCM_FORMAT_S16_LE:
+               cfgr |= CFGR_VALID_DATA_16bit;
+               break;
+       case SNDRV_PCM_FMTBIT_S20_3LE :
+               cfgr |= CFGR_VALID_DATA_20bit;
+               break;
+       case SNDRV_PCM_FORMAT_S24_LE:
+               cfgr |= CFGR_VALID_DATA_24bit;
+               break;                  
+       default:
+               goto err;
+       }
+       
+       cfgr &= ~CFGR_HALFWORD_TX_MASK;
+       cfgr |= CFGR_HALFWORD_TX_ENABLE;
+       
+       cfgr &= ~CFGR_CLK_RATE_MASK;
+       cfgr |= (1<<16);
+       
+       cfgr &= ~CFGR_JUSTIFIED_MASK;
+       cfgr |= CFGR_JUSTIFIED_RIGHT;
+       
+       writel(cfgr, regs + CFGR);
+  
+  dmac = readl(regs + DMACR) & DMACR_TRAN_DMA_MASK & (~DMACR_TRAN_DATA_LEVEL_MASK);
+  dmac |= 0x10;
+  writel(dmac, regs + DMACR);
+  
+       spin_unlock_irqrestore(&spdif->lock, flags);
+
+       return 0;
+err:
+       spin_unlock_irqrestore(&spdif->lock, flags);
+       return -EINVAL;
+}
+
+static void spdif_shutdown(struct snd_pcm_substream *substream,
+                               struct snd_soc_dai *dai)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct rockchip_spdif_info *spdif = to_info(rtd->cpu_dai);
+       void __iomem *regs = spdif->regs;
+       u32 con, clkcon;
+
+       RK_SPDIF_DBG( "spdif:Entered %s\n", __func__);
+
+}
+
+#ifdef CONFIG_PM
+static int spdif_suspend(struct snd_soc_dai *cpu_dai)
+{
+       struct rockchip_spdif_info *spdif = to_info(cpu_dai);
+       u32 con = spdif->saved_con;
+
+       RK_SPDIF_DBG( "spdif:Entered %s\n", __func__);
+
+       return 0;
+}
+
+static int spdif_resume(struct snd_soc_dai *cpu_dai)
+{
+       struct rockchip_spdif_info *spdif = to_info(cpu_dai);
+
+       RK_SPDIF_DBG( "spdif:Entered %s\n", __func__);
+
+       return 0;
+}
+#else
+#define spdif_suspend NULL
+#define spdif_resume NULL
+#endif
+
+static struct snd_soc_dai_ops spdif_dai_ops = {
+       .set_sysclk     = spdif_set_syclk,
+       .trigger        = spdif_trigger,
+       .hw_params      = spdif_hw_params,
+       .shutdown       = spdif_shutdown,
+};
+
+struct snd_soc_dai_driver rockchip_spdif_dai = {
+       .name = "rk-spdif",
+       .playback = {
+               .stream_name = "SPDIF Playback",
+               .channels_min = 2,
+               .channels_max = 2,
+               .rates = (SNDRV_PCM_RATE_32000 |
+                               SNDRV_PCM_RATE_44100 |
+                               SNDRV_PCM_RATE_48000 |
+                               SNDRV_PCM_RATE_96000),
+               .formats = SNDRV_PCM_FMTBIT_S16_LE|
+               SNDRV_PCM_FMTBIT_S20_3LE|
+               SNDRV_PCM_FMTBIT_S24_LE, },
+       .ops = &spdif_dai_ops,
+       .suspend = spdif_suspend,
+       .resume = spdif_resume,
+};
+
+
+static __devinit int spdif_probe(struct platform_device *pdev)
+{
+       struct s3c_audio_pdata *spdif_pdata;
+       struct resource *mem_res, *dma_res;
+       struct rockchip_spdif_info *spdif;
+       int ret;
+  
+       spdif_pdata = pdev->dev.platform_data;
+
+       RK_SPDIF_DBG("Entered %s\n", __func__);
+       
+#if defined  (CONFIG_ARCH_RK29)
+    rk29_mux_api_set(GPIO4A7_SPDIFTX_NAME, GPIO4L_SPDIF_TX);
+#endif
+
+#if defined (CONFIG_ARCH_RK30)    
+    rk30_mux_api_set(GPIO1B2_SPDIFTX_NAME, GPIO1B_SPDIF_TX);
+#elif defined (CONFIG_ARCH_RK3188)
+    iomux_set(SPDIF_TX);
+#endif
+
+
+       dma_res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "spdif_dma");
+       if (!dma_res) {
+               printk("spdif:Unable to get dma resource.\n");
+               return -ENXIO;
+       }
+
+       mem_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "spdif_base");
+       if (!mem_res) {
+               printk("spdif:Unable to get register resource.\n");
+               return -ENXIO;
+       }
+
+       spdif = &spdif_info;
+       spdif->dev = &pdev->dev;
+
+       spin_lock_init(&spdif->lock);
+       
+       spdif->clk = clk_get(&pdev->dev, "spdif");
+       if (IS_ERR(spdif->clk)) {
+               printk("spdif:failed to get internal source clock\n");
+               ret = -ENOENT;
+               goto err1;
+       }
+       clk_enable(spdif->clk);
+       clk_set_rate(spdif->clk, 11289600);
+       
+#if 1// defined (CONFIG_ARCH_RK30)     
+       spdif->hclk = clk_get(&pdev->dev, "hclk_spdif");
+       if (IS_ERR(spdif->hclk)) {
+               printk("spdif:failed to get spdif hclk\n");
+               ret = -ENOENT;
+               goto err0;
+       }
+       clk_enable(spdif->hclk);
+       clk_set_rate(spdif->hclk, 11289600);
+#endif
+
+       /* Request S/PDIF Register's memory region */
+       if (!request_mem_region(mem_res->start,
+                               resource_size(mem_res), "rockchip-spdif")) {
+               printk("spdif:Unable to request register region\n");
+               ret = -EBUSY;
+               goto err2;
+       }
+
+       spdif->regs = ioremap(mem_res->start, mem_res->end - mem_res->start + 1);
+       if (spdif->regs == NULL) {
+               printk("spdif:Cannot ioremap registers\n");
+               ret = -ENXIO;
+               goto err3;
+       }
+
+       dev_set_drvdata(&pdev->dev, spdif);
+       
+       ret = snd_soc_register_dai(&pdev->dev, &rockchip_spdif_dai);
+       if (ret != 0) {
+               printk("spdif:fail to register dai\n");
+               goto err4;
+       }
+
+       spdif_stereo_out.dma_size = 4;
+       spdif_stereo_out.client = &spdif_dma_client_out;
+       spdif_stereo_out.dma_addr = mem_res->start + DATA_OUTBUF;
+       spdif_stereo_out.channel = dma_res->start;
+
+       spdif->dma_playback = &spdif_stereo_out;
+#ifdef CONFIG_SND_DMA_EVENT_STATIC
+       WARN_ON(rk29_dma_request(spdif_stereo_out.channel, spdif_stereo_out.client, NULL));
+#endif
+
+       RK_SPDIF_DBG("spdif:spdif probe ok!\n");
+       
+       return 0;
+
+err4:
+       iounmap(spdif->regs);
+err3:
+       release_mem_region(mem_res->start, resource_size(mem_res));
+err2:
+       clk_disable(spdif->clk);
+       clk_put(spdif->clk);
+err1:
+       clk_disable(spdif->hclk);
+       clk_put(spdif->hclk);
+#if  1//defined (CONFIG_ARCH_RK30)     
+err0:
+#endif
+       return ret;
+}
+
+static __devexit int spdif_remove(struct platform_device *pdev)
+{
+       struct rockchip_spdif_info *spdif = &spdif_info;
+       struct resource *mem_res;
+       
+       RK_SPDIF_DBG("Entered %s\n", __func__);
+       
+       snd_soc_unregister_dai(&pdev->dev);
+
+       iounmap(spdif->regs);
+
+       mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (mem_res)
+               release_mem_region(mem_res->start, resource_size(mem_res));
+
+       clk_disable(spdif->clk);
+       clk_put(spdif->clk);
+       clk_disable(spdif->hclk);
+       clk_put(spdif->hclk);
+
+       return 0;
+}
+
+
+static struct platform_driver rockchip_spdif_driver = {
+       .probe  = spdif_probe,
+       .remove = spdif_remove,
+       .driver = {
+               .name   = "rk-spdif",
+               .owner  = THIS_MODULE,
+       },
+};
+
+
+static int __init spdif_init(void)
+{
+       RK_SPDIF_DBG("Entered %s\n", __func__);
+       return platform_driver_register(&rockchip_spdif_driver);
+}
+module_init(spdif_init);
+
+static void __exit spdif_exit(void)
+{
+       RK_SPDIF_DBG("Entered %s\n", __func__);
+       platform_driver_unregister(&rockchip_spdif_driver);
+}
+module_exit(spdif_exit);
+
+MODULE_AUTHOR("Seungwhan Youn, <sw.youn@rockchip.com>");
+MODULE_DESCRIPTION("rockchip S/PDIF Controller Driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:rockchip-spdif");
diff --git a/sound/soc/rk29/spdif.h b/sound/soc/rk29/spdif.h
new file mode 100644 (file)
index 0000000..d669f7d
--- /dev/null
@@ -0,0 +1,18 @@
+/*$_FOR_ROCKCHIP_RBOX_$*/
+/*$_rbox_$_modify_$_huangzhibao for spdif output*/
+
+/*
+ *
+ * ALSA SoC Audio Layer - 
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __SND_SOC_SAMSUNG_SPDIF_H
+#define __SND_SOC_SAMSUNG_SPDIF_H      __FILE__
+
+
+#endif /* __SND_SOC_RK_SPDIF_H */