diff --git a/kernel/arch/arm/boot/dts/firefly-rk3288.dts b/kernel/arch/arm/boot/dts/firefly-rk3288.dts index f32b8c34de..e5378529e7 100755 --- a/kernel/arch/arm/boot/dts/firefly-rk3288.dts +++ b/kernel/arch/arm/boot/dts/firefly-rk3288.dts @@ -94,6 +94,7 @@ }; rockchip-hdmi-i2s { + status = "disabled"; compatible = "rockchip-hdmi-i2s"; dais { dai0 { @@ -108,9 +109,9 @@ }; }; }; - - rockchip-hdmi-spdif { - compatible = "rockchip-hdmi-spdif"; + + rockchip-spdif-card { + compatible = "rockchip-spdif-card"; dais { dai0 { audio-codec = <&codec_hdmi_spdif>; diff --git a/kernel/arch/arm/boot/dts/rk3288.dtsi b/kernel/arch/arm/boot/dts/rk3288.dtsi index e4194c9657..13e67f9843 100755 --- a/kernel/arch/arm/boot/dts/rk3288.dtsi +++ b/kernel/arch/arm/boot/dts/rk3288.dtsi @@ -822,13 +822,13 @@ spdif: rockchip-spdif@0xff8b0000 { compatible = "rockchip-spdif"; - reg = <0xff8b0000 0x10000>; //8channel - //reg = ;//2channel - clocks = <&clk_spdif>, <&clk_spdif_8ch>,<&clk_gates10 11>; + //reg = <0xff8b0000 0x10000>; //8channel + reg = <0xff880000 0x10000>;//2channel + clocks = <&clk_spdif>, <&clk_spdif_8ch>,<&clk_gates10 10>; clock-names = "spdif_mclk","spdif_8ch_mclk","spdif_hclk"; - interrupts = ; - dmas = <&pdma0 3>; - //dmas = <&pdma0 2>; //2channel + interrupts = ; + //dmas = <&pdma0 3>; + dmas = <&pdma0 2>; //2channel //#dma-cells = <1>; dma-names = "tx"; pinctrl-names = "default"; diff --git a/kernel/arch/arm/configs/firefly-rk3288_defconfig b/kernel/arch/arm/configs/firefly-rk3288_defconfig index a624366935..2b8e548301 100644 --- a/kernel/arch/arm/configs/firefly-rk3288_defconfig +++ b/kernel/arch/arm/configs/firefly-rk3288_defconfig @@ -1536,7 +1536,7 @@ CONFIG_INPUT_TOUCHSCREEN=y # CONFIG_TOUCHSCREEN_SYNAPTICS_DSX is not set # CONFIG_TOUCHSCREEN_SYNAPTICS_RK is not set # CONFIG_TOUCHSCREEN_ZET62XX is not set -CONFIG_TOUCHSCREEN_GSLX680=y +# CONFIG_TOUCHSCREEN_GSLX680 is not set # CONFIG_TOUCHSCREEN_GT8XX is not set # CONFIG_TOUCHSCREEN_GT9XX is not set # CONFIG_TOUCHSCREEN_CT36X_TS is not set @@ -2532,8 +2532,9 @@ CONFIG_SND_SOC_GENERIC_DMAENGINE_PCM=y CONFIG_SND_RK_SOC=y CONFIG_SND_RK_SOC_I2S=y CONFIG_SND_RK_SOC_SPDIF=y -# CONFIG_SND_RK_SOC_HDMI_I2S is not set -CONFIG_SND_RK_SOC_HDMI_SPDIF=y +CONFIG_SND_RK_SOC_HDMI_I2S=y +# CONFIG_SND_RK_SOC_HDMI_SPDIF is not set +CONFIG_SND_RK_SOC_SPDIF_CARD=y # CONFIG_SND_RK_SOC_AK4396 is not set CONFIG_SND_RK_SOC_ES8323=y # CONFIG_SND_RK_SOC_ES8316 is not set @@ -2564,6 +2565,7 @@ CONFIG_SND_SOC_I2C_AND_SPI=y CONFIG_SND_SOC_ES8323=y CONFIG_SND_SOC_RK3036=y CONFIG_SND_SOC_RK312X=y +CONFIG_SND_SOC_HDMI_I2S=y CONFIG_SND_SOC_HDMI_SPDIF=y CONFIG_SND_SOC_RT5631=y CONFIG_SND_SOC_RT3224=y diff --git a/kernel/sound/soc/rockchip/rk_hdmi_spdif.c b/kernel/sound/soc/rockchip/rk_hdmi_spdif.c index 0fa3629b94..4dff132dca 100755 --- a/kernel/sound/soc/rockchip/rk_hdmi_spdif.c +++ b/kernel/sound/soc/rockchip/rk_hdmi_spdif.c @@ -1,13 +1,16 @@ - /* - * smdk_spdif.c -- S/PDIF audio for SMDK + * rk_hdmi_spdif.c -- hdmi spdif for rockchip * - * Copyright 2010 Samsung Electronics Co. Ltd. + * Copyright (C) 2015 Fuzhou Rockchip 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. + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. * */ @@ -24,83 +27,39 @@ #include "card_info.h" #include "rk_pcm.h" - -#if 0 -#define RK_SPDIF_DBG(x...) printk(KERN_INFO "rk_hdmi_spdif:"x) -#else -#define RK_SPDIF_DBG(x...) do { } while (0) +#if defined(CONFIG_RK_HDMI) && defined(CONFIG_SND_SOC_HDMI_SPDIF) +extern int snd_config_hdmi_audio(struct snd_pcm_hw_params *params); #endif - -static int set_audio_clock_rate(unsigned long pll_rate, - unsigned long audio_rate) -{ - struct clk *sclk_spdif; -#if defined (CONFIG_ARCH_RK30) || defined (CONFIG_ARCH_RK3188) - struct clk *hclk_spdif; -#endif - -#if defined (CONFIG_ARCH_RK30) || defined (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_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; - struct snd_soc_dai *codec_dai = rtd->codec_dai; - unsigned long pll_out, rclk_rate, dai_fmt = rtd->dai_link->dai_fmt; + unsigned long sclk; int ret, ratio; - RK_SPDIF_DBG("spdif:Entered %s\n", __func__); - + /* bmc: 2*32*fs*2 = 128fs */ + ratio = 128; 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; + case 192000: + sclk = params_rate(params) * ratio; break; default: - printk("rk_spdif: params not support\n"); + pr_err("rk_spdif: params not support\n"); return -EINVAL; } - ratio = 256; - rclk_rate = params_rate(params) * ratio; - - - /* Set S/PDIF uses internal source clock */ ret = snd_soc_dai_set_sysclk(cpu_dai, 0, - rclk_rate, SND_SOC_CLOCK_IN); - if (ret < 0) - return ret; + sclk, SND_SOC_CLOCK_IN); + +#if defined(CONFIG_RK_HDMI) && defined(CONFIG_SND_SOC_HDMI_SPDIF) + snd_config_hdmi_audio(params); +#endif return ret; } @@ -131,14 +90,16 @@ static int rockchip_hdmi_spdif_audio_probe(struct platform_device *pdev) ret = rockchip_of_get_sound_card_info_(card, false); if (ret) { - printk("%s() get sound card info failed:%d\n", __FUNCTION__, ret); + pr_err("%s() get sound card info failed:%d\n", + __func__, ret); return ret; } ret = snd_soc_register_card(card); if (ret) - printk("%s() register card failed:%d\n", __FUNCTION__, ret); + pr_err("%s() register card failed:%d\n", + __func__, ret); return ret; } @@ -154,25 +115,24 @@ static int rockchip_hdmi_spdif_audio_remove(struct platform_device *pdev) #ifdef CONFIG_OF static const struct of_device_id rockchip_hdmi_spdif_of_match[] = { - { .compatible = "rockchip-hdmi-spdif"}, + { .compatible = "rockchip-hdmi-spdif", }, {}, }; MODULE_DEVICE_TABLE(of, rockchip_hdmi_spdif_of_match); #endif /* CONFIG_OF */ static struct platform_driver rockchip_hdmi_spdif_audio_driver = { - .driver = { - .name = "rockchip-hdmi-spdif", - .owner = THIS_MODULE, + .driver = { + .name = "rockchip-hdmi-spdif", .pm = &snd_soc_pm_ops, .of_match_table = of_match_ptr(rockchip_hdmi_spdif_of_match), }, - .probe = rockchip_hdmi_spdif_audio_probe, - .remove = rockchip_hdmi_spdif_audio_remove, + .probe = rockchip_hdmi_spdif_audio_probe, + .remove = rockchip_hdmi_spdif_audio_remove, }; module_platform_driver(rockchip_hdmi_spdif_audio_driver); -MODULE_AUTHOR("hzb, "); -MODULE_DESCRIPTION("ALSA SoC RK+S/PDIF"); +MODULE_AUTHOR("hzb "); +MODULE_DESCRIPTION("Rockchip HDMI Spdif Card"); MODULE_LICENSE("GPL"); diff --git a/kernel/sound/soc/rockchip/rk_spdif.c b/kernel/sound/soc/rockchip/rk_spdif.c index 7be288955e..9ef46cd427 100755 --- a/kernel/sound/soc/rockchip/rk_spdif.c +++ b/kernel/sound/soc/rockchip/rk_spdif.c @@ -1,14 +1,17 @@ - -/* sound/soc/rockchip/rk_spdif.c +/* + * Rockchip S/PDIF ALSA SoC Digital Audio Interface(DAI) driver * - * ALSA SoC Audio Layer - rockchip S/PDIF Controller driver + * Copyright (C) 2015 Fuzhou Rockchip Electronics Co., Ltd * - * Copyright (c) 2010 rockchip Electronics Co. Ltd - * http://www.rockchip.com/ + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. * - * 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 @@ -37,115 +40,109 @@ #include #include #include -#include - #include - #include "rk_pcm.h" -#if 1 -#define RK_SPDIF_DBG(x...) printk(KERN_INFO "rk_spdif:"x) -#else -#define RK_SPDIF_DBG(x...) do { } while (0) -#endif +/* + * channel status register + * 192 frame channel status bits: include 384 subframe bits + */ +#define SPDIF_CHNSR00_ADDR 0xC0 +#define SPDIF_CHNSR01_ADDR 0xC4 +#define SPDIF_CHNSR02_ADDR 0xC8 +#define SPDIF_CHNSR03_ADDR 0xCC +#define SPDIF_CHNSR04_ADDR 0xD0 +#define SPDIF_CHNSR05_ADDR 0xD4 +#define SPDIF_CHNSR06_ADDR 0xD8 +#define SPDIF_CHNSR07_ADDR 0xDC +#define SPDIF_CHNSR08_ADDR 0xE0 +#define SPDIF_CHNSR09_ADDR 0xE4 +#define SPDIF_CHNSR10_ADDR 0xE8 +#define SPDIF_CHNSR11_ADDR 0xEC +/* + * according to iec958, we only care about + * the first meaningful 5 bytes(40 bits) + */ +#define CHNSTA_BYTES (5) +#define BIT_1_LPCM (0X0<<1) +#define BIT_1_NLPCM (0x1<<1) + +/* sample word length bit 32~35 */ +#define CHNS_SAMPLE_WORD_LEN_16 (0x2) +#define CHNS_SAMPLE_WORD_LEN_24 (0xb) + +/* sample frequency bit 24~27 */ +#define CHNS_SAMPLE_FREQ_22P05K (0X4) +#define CHNS_SAMPLE_FREQ_44P1K (0X0) +#define CHNS_SAMPLE_FREQ_88P2K (0X8) +#define CHNS_SAMPLE_FREQ_176P4K (0Xc) +#define CHNS_SAMPLE_FREQ_24K (0X6) +#define CHNS_SAMPLE_FREQ_48K (0X2) +#define CHNS_SAMPLE_FREQ_96K (0Xa) +#define CHNS_SAMPLE_FREQ_192K (0Xe) +#define CHNS_SAMPLE_FREQ_32K (0X3) +#define CHNS_SAMPLE_FREQ_768K (0X9) /* Registers */ -#define CFGR 0x00 -#define SDBLR 0x04 -#define DMACR 0x08 -#define INTCR 0x0C -#define INTSR 0x10 -#define XFER 0x18 -#define SMPDR 0x20 +#define CFGR 0x00 +#define SDBLR 0x04 +#define DMACR 0x08 +#define INTCR 0x0C +#define INTSR 0x10 +#define XFER 0x18 +#define SMPDR 0x20 -#define SPDIF_CHNSR00_ADDR 0xC0 -#define SPDIF_CHNSR01_ADDR 0xC4 -#define SPDIF_CHNSR02_ADDR 0xC8 -#define SPDIF_CHNSR03_ADDR 0xCC -#define SPDIF_CHNSR04_ADDR 0xD0 -#define SPDIF_CHNSR05_ADDR 0xD4 -#define SPDIF_CHNSR06_ADDR 0xD8 -#define SPDIF_CHNSR07_ADDR 0xDC -#define SPDIF_CHNSR08_ADDR 0xE0 -#define SPDIF_CHNSR09_ADDR 0xE4 -#define SPDIF_CHNSR10_ADDR 0xE8 -#define SPDIF_CHNSR11_ADDR 0xEC +/* transfer configuration register */ +#define CFGR_VALID_DATA_16bit (0x0 << 0) +#define CFGR_VALID_DATA_20bit (0x1 << 0) +#define CFGR_VALID_DATA_24bit (0x2 << 0) +#define CFGR_VALID_DATA_MASK (0x3 << 0) +#define CFGR_HALFWORD_TX_ENABLE (0x1 << 2) +#define CFGR_HALFWORD_TX_DISABLE (0x0 << 2) +#define CFGR_HALFWORD_TX_MASK (0x1 << 2) +#define CFGR_JUSTIFIED_RIGHT (0x0 << 3) +#define CFGR_JUSTIFIED_LEFT (0x1 << 3) +#define CFGR_JUSTIFIED_MASK (0x1 << 3) +#define CFGR_CSE_DISABLE (0x0 << 6) +#define CFGR_CSE_ENABLE (0x1 << 6) +#define CFGR_CSE_MASK (0x1 << 6) +#define CFGR_MCLK_CLR (0x1 << 7) +#define CFGR_LINEAR_PCM (0x0 << 8) +#define CFGR_NON_LINEAR_PCM (0x1 << 8) +#define CFGR_LINEAR_MASK (0x1 << 8) +#define CFGR_PRE_CHANGE_ENALBLE (0x1 << 9) +#define CFGR_PRE_CHANGE_DISABLE (0x0 << 9) +#define CFGR_PRE_CHANGE_MASK (0x1 << 9) +#define CFGR_CLK_RATE_MASK (0xFF << 16) -#define SPDIF_BURSTINFO 0x100 -#define SPDIF_REPETTION 0x104 +/* transfer start register */ +#define XFER_TRAN_STOP (0x0 << 0) +#define XFER_TRAN_START (0x1 << 0) +#define XFER_MASK (0x1 << 0) -#define DATA_OUTBUF 0x20 +/* dma control register */ +#define DMACR_TRAN_DMA_DISABLE (0x0 << 5) +#define DMACR_TRAN_DMA_ENABLE (0x1 << 5) +#define DMACR_TRAN_DMA_CTL_MASK (0x1 << 5) +#define DMACR_TRAN_DATA_LEVEL (0x10) +#define DMACR_TRAN_DATA_LEVEL_MASK (0x1F) +#define DMACR_TRAN_DMA_MASK (0x3F) +#define DMA_DATA_LEVEL_16 (0x10) -#define SPDIF_CHANNEL_SEL_8CH ((0x2<<16)|(0x0<<0)) -#define SPDIF_CHANNEL_SEL_2CH ((0x2<<16)|(0x2<<0)) +/* interrupt control register */ +#define INTCR_SDBEIE_DISABLE (0x0 << 4) +#define INTCR_SDBEIE_ENABLE (0x1 << 4) +#define INTCR_SDBEIE_MASK (0x1 << 4) -//BURSTINFO bit0:6 //AC-3:0x01, DTS-I -II -III:11,12,13 -#define BURSTINFO_DATA_TYPE_AC3 0x01 -#define BURSTINFO_DATA_TYPE_EAC3 0x15 -#define BURSTINFO_DATA_TYPE_DTS_I 0x0b - -#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) - -//CSE:channel status enable -//The bit should be set to 1 when the channel conveys non-linear PCM -#define CFGR_CSE_DISABLE (0<<6) -#define CFGR_CSE_ENABLE (1<<6) -#define CFGR_CSE_MASK (1<<6) - - -#define CFGR_MCLK_CLR (1<<7) - -//new -#define CFGR_LINEAR_PCM (0<<8) -#define CFGR_NON_LINEAR_PCM (1<<8) -#define CFGR_LINEAR_MASK (1<<8) - -//support 7.1 amplifier,new -#define CFGR_PRE_CHANGE_ENALBLE (1<<9) -#define CFGR_PRE_CHANGE_DISABLE (0<<9) -#define CFGR_PRE_CHANGE_MASK (1<<9) - -#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 - -//Sample Date Buffer empty interrupt enable,new -#define INTCR_SDBEIE_DISABLE (0<<4) -#define INTCR_SDBEIE_ENABLE (1<<4) -#define INTCR_SDBEIE_MASK (1<<4) -#define INTCR_BTTIC_CLEAR (1<<16) -#define INTCR_UDTIC_CLEAR (1<<17) - struct rockchip_spdif_info { - spinlock_t lock; - void __iomem *regs; - unsigned long clk_rate; - struct clk *clk; - struct clk *hclk; - struct snd_dmaengine_dai_dma_data dma_playback; + spinlock_t lock;/*lock parmeter setting.*/ + void __iomem *regs; + unsigned long clk_rate; + struct clk *hclk; + struct clk *clk; + struct device *dev; + struct snd_dmaengine_dai_dma_data dma_playback; }; static inline struct rockchip_spdif_info *to_info(struct snd_soc_dai *cpu_dai) @@ -156,35 +153,34 @@ static inline struct rockchip_spdif_info *to_info(struct snd_soc_dai *cpu_dai) static void spdif_snd_txctrl(struct rockchip_spdif_info *spdif, int on) { void __iomem *regs = spdif->regs; - u32 opr,xfer; + u32 dmacr, xfer; - RK_SPDIF_DBG( "Entered %s\n", __func__); + xfer = readl(regs + XFER) & (~XFER_MASK); + dmacr = readl(regs + DMACR) & (~DMACR_TRAN_DMA_CTL_MASK); - xfer = readl(regs + XFER) & XFER_MASK; - opr = readl(regs + DMACR) & DMACR_TRAN_DMA_MASK & (~DMACR_TRAN_DMA_CTL_MASK); - - if (on){ + if (on) { xfer |= XFER_TRAN_START; - opr |= DMACR_TRAN_DMA_ENABLE; + dmacr |= DMACR_TRAN_DMA_ENABLE; + writel(dmacr, regs + DMACR); writel(xfer, regs + XFER); - writel(opr, 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; + } else { + xfer &= XFER_TRAN_STOP; + dmacr &= DMACR_TRAN_DMA_DISABLE; writel(xfer, regs + XFER); - writel(opr, regs + DMACR); - writel(1<<7, regs + CFGR); - RK_SPDIF_DBG("off xfer=0x%x,opr=0x%x\n",readl(regs + XFER),readl(regs + DMACR)); + writel(dmacr, regs + DMACR); + writel(CFGR_MCLK_CLR, regs + CFGR); } + + dev_dbg(spdif->dev, "on: %d, xfer = 0x%x, dmacr = 0x%x\n", + on, readl(regs + XFER), readl(regs + DMACR)); } -static int spdif_set_syclk(struct snd_soc_dai *cpu_dai, - int clk_id, unsigned int freq, int dir) +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); - RK_SPDIF_DBG("Entered %s, freq: %d\n", __func__, freq); + dev_dbg(spdif->dev, "%s: sysclk = %d\n", __func__, freq); spdif->clk_rate = freq; clk_set_rate(spdif->clk, freq); @@ -193,13 +189,13 @@ static int spdif_set_syclk(struct snd_soc_dai *cpu_dai, } static int spdif_trigger(struct snd_pcm_substream *substream, int cmd, - struct snd_soc_dai *dai) + 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__); + dev_dbg(spdif->dev, "%s: cmd: %d\n", __func__, cmd); switch (cmd) { case SNDRV_PCM_TRIGGER_START: @@ -224,119 +220,113 @@ static int spdif_trigger(struct snd_pcm_substream *substream, int cmd, } static int spdif_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) { struct rockchip_spdif_info *spdif = to_info(dai); void __iomem *regs = spdif->regs; unsigned long flags; - int cfgr, dmac,intcr,chnsr_byte[5]={0}; - int dataType,ErrFlag,DataLen,DataInfo,BsNum,Repetition,BurstInfo; + unsigned int val; + int cfgr, dmac, intcr, chnregval; + char chnsta[CHNSTA_BYTES]; - RK_SPDIF_DBG("Entered %s\n", __func__); + dev_dbg(spdif->dev, "%s\n", __func__); - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { dai->playback_dma_data = &spdif->dma_playback; - else { - printk("spdif:Capture is not supported\n"); + } else { + dev_err(spdif->dev, "capture is not supported\n"); return -EINVAL; } spin_lock_irqsave(&spdif->lock, flags); - - cfgr = readl(regs + CFGR) & CFGR_VALID_DATA_MASK; - + + cfgr = readl(regs + CFGR); + cfgr &= ~CFGR_VALID_DATA_MASK; switch (params_format(params)) { case SNDRV_PCM_FORMAT_S16_LE: cfgr |= CFGR_VALID_DATA_16bit; break; - case SNDRV_PCM_FORMAT_S20_3LE : + case SNDRV_PCM_FORMAT_S20_3LE: cfgr |= CFGR_VALID_DATA_20bit; break; case SNDRV_PCM_FORMAT_S24_LE: cfgr |= CFGR_VALID_DATA_24bit; - break; + break; default: goto err; } - + cfgr &= ~CFGR_HALFWORD_TX_MASK; cfgr |= CFGR_HALFWORD_TX_ENABLE; - - cfgr &= ~CFGR_CLK_RATE_MASK;//set most MCLK:192kHz - cfgr |= (1<<16); - + + /* no need divder, let set_syclk care about this */ + cfgr &= ~CFGR_CLK_RATE_MASK; + cfgr |= (0x0<<16); + cfgr &= ~CFGR_JUSTIFIED_MASK; cfgr |= CFGR_JUSTIFIED_RIGHT; cfgr &= ~CFGR_CSE_MASK; - cfgr |= CFGR_CSE_DISABLE; + cfgr |= CFGR_CSE_ENABLE; cfgr &= ~CFGR_LINEAR_MASK; cfgr |= CFGR_LINEAR_PCM; - if(!snd_pcm_format_linear(params_format(params))){//stream type - cfgr |= CFGR_NON_LINEAR_PCM; - } - + cfgr &= ~CFGR_PRE_CHANGE_MASK; cfgr |= CFGR_PRE_CHANGE_ENALBLE; writel(cfgr, regs + CFGR); - intcr = readl(regs + INTCR) & INTCR_SDBEIE_MASK; - intcr |= INTCR_SDBEIE_ENABLE; + intcr = readl(regs + INTCR) & (~INTCR_SDBEIE_MASK); + intcr |= INTCR_SDBEIE_DISABLE; writel(intcr, regs + INTCR); - dmac = readl(regs + DMACR) & DMACR_TRAN_DMA_MASK & (~DMACR_TRAN_DATA_LEVEL_MASK); - dmac |= 0x10; + dmac = readl(regs + DMACR) & (~DMACR_TRAN_DATA_LEVEL_MASK); + dmac |= DMA_DATA_LEVEL_16; writel(dmac, regs + DMACR); - /* channel byte 0: - Bit 1 1 Main data field represents linear PCM samples. - 0 Main data field used for purposes other purposes. - */ - chnsr_byte[0]= (0x0)|(0x0<<1)|(0x0<<2)|(0x0<<3)|(0x00<<6);//consumer|pcm|copyright?|pre-emphasis|(0x00<<6); - chnsr_byte[1]= (0x0);//category code general mode?? - chnsr_byte[2]= (0x0)|(0x0<<4)|(0x0<<6);// - chnsr_byte[3]= (0x00)|(0x00);//khz;clock acurracy - chnsr_byte[4]= (0x0<<4)|(0x01<<1|0x0);//16 bit; - - if(!snd_pcm_format_linear(params_format(params))){//set stream type - chnsr_byte[0] |= (0x1<<1);//set 0:represent main data is linear - chnsr_byte[4] = (0x0<<4)|(0x00<<1|0x0);//16 bit; + /* channel status bit */ + memset(chnsta, 0x0, CHNSTA_BYTES); + switch (params_rate(params)) { + case 44100: + val = CHNS_SAMPLE_FREQ_44P1K; + break; + case 48000: + val = CHNS_SAMPLE_FREQ_48K; + break; + case 88200: + val = CHNS_SAMPLE_FREQ_88P2K; + break; + case 96000: + val = CHNS_SAMPLE_FREQ_96K; + break; + case 176400: + val = CHNS_SAMPLE_FREQ_176P4K; + break; + case 192000: + val = CHNS_SAMPLE_FREQ_192K; + break; + default: + val = CHNS_SAMPLE_FREQ_44P1K; + break; } - writel((chnsr_byte[4]<<16)|(chnsr_byte[4]),regs+SPDIF_CHNSR02_ADDR); - writel((chnsr_byte[3]<<24)|(chnsr_byte[2]<<16)|(chnsr_byte[3]<<8)|(chnsr_byte[2]),regs+SPDIF_CHNSR01_ADDR); - writel((chnsr_byte[1]<<24)|(chnsr_byte[0]<<16)|(chnsr_byte[1]<<8)|(chnsr_byte[0]),regs+SPDIF_CHNSR00_ADDR); - if(!snd_pcm_format_linear(params_format(params))) {//set non-linear params - switch(params_format(params)){ - case SNDRV_NON_LINEAR_PCM_FORMAT_AC3: - //bit0:6 //AC-3:0x01, DTS-I -II -III:11,12,13 - dataType = BURSTINFO_DATA_TYPE_AC3; - //Repetition:AC-3:1536 DTS-I -II -III:512,1024,2048 EAC3:6144 - Repetition = 1536; - break; - case SNDRV_NON_LINEAR_PCM_FORMAT_DTS_I: - dataType = BURSTINFO_DATA_TYPE_DTS_I; - Repetition = 512; - break; - case SNDRV_NON_LINEAR_PCM_FORMAT_EAC3: - dataType = BURSTINFO_DATA_TYPE_EAC3; - Repetition = 6144; - break; - default: - return -EINVAL; - } - ErrFlag=0x0; - DataLen=params_period_size(params)*2*16;//bit32:16 //640kbps:0x5000 448kbps:0x3800 - DataInfo=0; - BsNum=0x0; - BurstInfo = (DataLen<<16)|(BsNum<<13)|(DataInfo<<8)|(ErrFlag<<7)|dataType; - writel(BurstInfo,regs+SPDIF_BURSTINFO); - writel(Repetition,regs+SPDIF_REPETTION); - } + chnsta[0] |= BIT_1_LPCM; + chnsta[3] |= val; + chnsta[4] |= ((~val)<<4 | CHNS_SAMPLE_WORD_LEN_16); + + chnregval = (chnsta[4] << 16) | (chnsta[4]); + writel(chnregval, regs + SPDIF_CHNSR02_ADDR); + + chnregval = (chnsta[3] << 24) | (chnsta[3] << 8); + writel(chnregval, regs + SPDIF_CHNSR01_ADDR); + + chnregval = (chnsta[1] << 24) | (chnsta[0] << 16) | + (chnsta[1] << 8) | (chnsta[0]); + writel(chnregval, regs + SPDIF_CHNSR00_ADDR); + spin_unlock_irqrestore(&spdif->lock, flags); return 0; @@ -349,24 +339,16 @@ err: static int spdif_suspend(struct snd_soc_dai *cpu_dai) { struct rockchip_spdif_info *spdif = to_info(cpu_dai); - void __iomem *regs = spdif->regs; - u32 intc; - RK_SPDIF_DBG( "Entered %s\n", __func__); - //g_intc = readl(regs + INTCR); - writel(0, regs + INTCR); // - RK_SPDIF_DBG( "spdif:Entered %s\n", __func__); + dev_dbg(spdif->dev, "%s\n", __func__); return 0; } static int spdif_resume(struct snd_soc_dai *cpu_dai) { struct rockchip_spdif_info *spdif = to_info(cpu_dai); - void __iomem *regs = spdif->regs; - u32 intc; - - RK_SPDIF_DBG( "spdif:Entered %s\n", __func__); - //writel(g_intc, regs + INTCR); // + + dev_dbg(spdif->dev, "%s\n", __func__); return 0; } #else @@ -386,114 +368,112 @@ struct snd_soc_dai_driver rockchip_spdif_dai = { .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, }, + .rates = SNDRV_PCM_RATE_8000_192000, + .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 const struct snd_soc_component_driver rockchip_spdif_component = { - .name = "rockchip-spdif", + .name = "rockchip-spdif", }; static int spdif_probe(struct platform_device *pdev) { + struct resource *memregion; struct resource *mem_res; struct rockchip_spdif_info *spdif; int ret; - RK_SPDIF_DBG("Entered %s\n", __func__); - - spdif = devm_kzalloc(&pdev->dev, sizeof(struct rockchip_spdif_info), GFP_KERNEL); + spdif = devm_kzalloc(&pdev->dev, sizeof( + struct rockchip_spdif_info), GFP_KERNEL); if (!spdif) { dev_err(&pdev->dev, "Can't allocate spdif info\n"); return -ENOMEM; } + spdif->dev = &pdev->dev; + platform_set_drvdata(pdev, spdif); + spin_lock_init(&spdif->lock); + /* get spdif register region. */ mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!mem_res) { - printk("spdif:Unable to get register resource.\n"); - return -ENXIO; + dev_err(&pdev->dev, "No memory resource\n"); + ret = -ENOENT; + goto err_; } - spdif->hclk = clk_get(&pdev->dev, "spdif_hclk"); - if(IS_ERR(spdif->hclk) ) { - dev_err(&pdev->dev, "get spdif_hclk failed.\n"); - } else{ - clk_prepare_enable(spdif->hclk); - } - - spdif->clk= clk_get(&pdev->dev, "spdif_8ch_mclk"); - if (IS_ERR(spdif->clk)) { - dev_err(&pdev->dev, "Can't retrieve spdif clock\n"); - return PTR_ERR(spdif->clk); - } - clk_set_rate(spdif->clk, 12288000);//clk have some problem - clk_set_rate(spdif->clk, 11289600); - clk_prepare_enable(spdif->clk); - - - /* 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"); + memregion = devm_request_mem_region(&pdev->dev, + mem_res->start, + resource_size(mem_res), + "rockchip-spdif"); + if (!memregion) { + dev_err(&pdev->dev, "Memory region already claimed\n"); ret = -EBUSY; - goto err_clk_put; + goto err_; } - - spdif->regs = devm_ioremap(&pdev->dev, mem_res->start, resource_size(mem_res)); + spdif->regs = devm_ioremap(&pdev->dev, + memregion->start, + resource_size(memregion)); if (!spdif->regs) { dev_err(&pdev->dev, "ioremap failed\n"); ret = -ENOMEM; - goto err_clk_put; + goto err_; } - spdif->dma_playback.addr = mem_res->start + DATA_OUTBUF; + /* get spdif clock and init. */ + spdif->hclk = devm_clk_get(&pdev->dev, "spdif_hclk"); + if (IS_ERR(spdif->hclk)) { + dev_err(&pdev->dev, "Can't retrieve spdif hclk\n"); + spdif->hclk = NULL; + } + clk_prepare_enable(spdif->hclk); + + spdif->clk = devm_clk_get(&pdev->dev, "spdif_mclk"); + if (IS_ERR(spdif->clk)) { + dev_err(&pdev->dev, "Can't retrieve spdif mclk\n"); + ret = -ENOMEM; + goto err_; + } + /* init freq */ + clk_set_rate(spdif->clk, 11289600); + clk_prepare_enable(spdif->clk); + + spdif->dma_playback.addr = mem_res->start + SMPDR; spdif->dma_playback.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; spdif->dma_playback.maxburst = 4; - //set dev name to driver->name for sound card register - dev_set_name(&pdev->dev, "%s", pdev->dev.driver->name); - - ret = snd_soc_register_component(&pdev->dev, &rockchip_spdif_component, - &rockchip_spdif_dai, 1); + ret = snd_soc_register_component(&pdev->dev, + &rockchip_spdif_component, + &rockchip_spdif_dai, 1); if (ret) { dev_err(&pdev->dev, "Could not register DAI: %d\n", ret); ret = -ENOMEM; - goto err_clk_put; + goto err_; } ret = rockchip_pcm_platform_register(&pdev->dev); if (ret) { dev_err(&pdev->dev, "Could not register PCM: %d\n", ret); - goto err_unregister_component; + goto err_; } - dev_set_drvdata(&pdev->dev, spdif); - writel_relaxed(SPDIF_CHANNEL_SEL_8CH, RK_GRF_VIRT + RK3288_GRF_SOC_CON2); - - RK_SPDIF_DBG("spdif:spdif probe ok!\n"); + dev_info(&pdev->dev, "spdif ready.\n"); return 0; -err_unregister_component: - snd_soc_unregister_component(&pdev->dev); -err_clk_put: - clk_put(spdif->clk); +err_: + platform_set_drvdata(pdev, NULL); + return ret; } static int spdif_remove(struct platform_device *pdev) { - RK_SPDIF_DBG("Entered %s\n", __func__); - rockchip_pcm_platform_unregister(&pdev->dev); snd_soc_unregister_component(&pdev->dev); @@ -501,11 +481,11 @@ static int spdif_remove(struct platform_device *pdev) } #ifdef CONFIG_OF -static const struct of_device_id exynos_spdif_match[] = { - { .compatible = "rockchip-spdif"}, - {}, +static const struct of_device_id rockchip_spdif_match[] = { + { .compatible = "rockchip-spdif", }, + {}, }; -MODULE_DEVICE_TABLE(of, exynos_spdif_match); +MODULE_DEVICE_TABLE(of, rockchip_spdif_match); #endif static struct platform_driver rockchip_spdif_driver = { @@ -513,29 +493,12 @@ static struct platform_driver rockchip_spdif_driver = { .remove = spdif_remove, .driver = { .name = "rockchip-spdif", - .owner = THIS_MODULE, - .of_match_table = of_match_ptr(exynos_spdif_match), + .of_match_table = of_match_ptr(rockchip_spdif_match), }, }; +module_platform_driver(rockchip_spdif_driver); -static int __init rk_spdif_init(void) -{ - RK_SPDIF_DBG("rk_spdif_init\n"); - return platform_driver_register(&rockchip_spdif_driver); -} - -static void __exit rk_spdif_exit(void) -{ - RK_SPDIF_DBG("rk_spdif_exit\n"); - platform_driver_unregister(&rockchip_spdif_driver); -} - - -late_initcall(rk_spdif_init); -module_exit(rk_spdif_exit); -//module_platform_driver(rockchip_spdif_driver); - -MODULE_AUTHOR("Seungwhan Youn, "); -MODULE_DESCRIPTION("rockchip S/PDIF Controller Driver"); -MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Sugar "); +MODULE_DESCRIPTION("Rockchip S/PDIF Controller Driver"); +MODULE_LICENSE("GPL v2"); MODULE_ALIAS("platform:rockchip-spdif");