From 8d0e47e29b295723bc2a926415a3b0d593fda5a6 Mon Sep 17 00:00:00 2001 From: yzq Date: Tue, 7 May 2013 11:42:27 +0800 Subject: [PATCH] rk spdif: support --- arch/arm/configs/rk3188_jettaplus_defconfig | 3 +- arch/arm/mach-rk30/devices.c | 33 ++ sound/soc/rk29/Kconfig | 12 +- sound/soc/rk29/Makefile | 6 +- sound/soc/rk29/rk_spdif.c | 186 ++++++++ sound/soc/rk29/spdif.c | 485 ++++++++++++++++++++ sound/soc/rk29/spdif.h | 18 + 7 files changed, 739 insertions(+), 4 deletions(-) create mode 100644 sound/soc/rk29/rk_spdif.c create mode 100644 sound/soc/rk29/spdif.c create mode 100644 sound/soc/rk29/spdif.h diff --git a/arch/arm/configs/rk3188_jettaplus_defconfig b/arch/arm/configs/rk3188_jettaplus_defconfig index 7bf889a59e3d..276e3a284409 100644 --- a/arch/arm/configs/rk3188_jettaplus_defconfig +++ b/arch/arm/configs/rk3188_jettaplus_defconfig @@ -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 diff --git a/arch/arm/mach-rk30/devices.c b/arch/arm/mach-rk30/devices.c index 32ddb4b9f1a4..a51ae35545c6 100755 --- a/arch/arm/mach-rk30/devices.c +++ b/arch/arm/mach-rk30/devices.c @@ -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 diff --git a/sound/soc/rk29/Kconfig b/sound/soc/rk29/Kconfig index 739f55e24c49..682fb18917b4 100755 --- a/sound/soc/rk29/Kconfig +++ b/sound/soc/rk29/Kconfig @@ -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 diff --git a/sound/soc/rk29/Makefile b/sound/soc/rk29/Makefile index cfd5e3bbc1a2..728bdae8dcde 100755 --- a/sound/soc/rk29/Makefile +++ b/sound/soc/rk29/Makefile @@ -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 index 000000000000..6ec311ed63bd --- /dev/null +++ b/sound/soc/rk29/rk_spdif.c @@ -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 + +#include + +#include "spdif.h" +#include + +#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, "); +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 index 000000000000..53e4e7b12992 --- /dev/null +++ b/sound/soc/rk29/spdif.c @@ -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 +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#if defined (CONFIG_ARCH_RK29) +#include +#endif + +#if defined (CONFIG_ARCH_RK30) +#include +#endif + +#if defined (CONFIG_ARCH_RK3188) +#include +#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, "); +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 index 000000000000..d669f7defa8e --- /dev/null +++ b/sound/soc/rk29/spdif.h @@ -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 */ -- 2.34.1