From c94512d406dfa2263b6df77ddb3cf93adc16aa42 Mon Sep 17 00:00:00 2001 From: qjb Date: Sat, 22 Mar 2014 17:40:01 +0800 Subject: [PATCH] rk3288 spdif: spdif sound support --- arch/arm/boot/dts/rk3288-tb.dts | 12 ++ include/uapi/sound/asound.h | 3 + sound/soc/rockchip/rk_hdmi_spdif.c | 12 ++ sound/soc/rockchip/rk_spdif.c | 178 ++++++++++++++++++++++++----- 4 files changed, 174 insertions(+), 31 deletions(-) mode change 100644 => 100755 include/uapi/sound/asound.h diff --git a/arch/arm/boot/dts/rk3288-tb.dts b/arch/arm/boot/dts/rk3288-tb.dts index f7df9854e572..33d7d3ea32fb 100755 --- a/arch/arm/boot/dts/rk3288-tb.dts +++ b/arch/arm/boot/dts/rk3288-tb.dts @@ -105,6 +105,18 @@ rockchip-hdmi-spdif { compatible = "rockchip-hdmi-spdif"; + dais { + dai0 { + audio-codec = <&codec_hdmi_spdif>; + i2s-controller = <&spdif>; + format = "spdif"; + //continuous-clock; + //bitclock-inversion; + //frame-inversion; + //bitclock-master; + //frame-master; + }; + }; }; rockchip-rt5631 { diff --git a/include/uapi/sound/asound.h b/include/uapi/sound/asound.h old mode 100644 new mode 100755 index e3983d508272..3ebd1422cffe --- a/include/uapi/sound/asound.h +++ b/include/uapi/sound/asound.h @@ -216,6 +216,9 @@ typedef int __bitwise snd_pcm_format_t; #define SNDRV_PCM_FORMAT_G723_40_1B ((__force snd_pcm_format_t) 47) /* 1 sample in 1 byte */ #define SNDRV_PCM_FORMAT_DSD_U8 ((__force snd_pcm_format_t) 48) /* DSD, 1-byte samples DSD (x8) */ #define SNDRV_PCM_FORMAT_DSD_U16_LE ((__force snd_pcm_format_t) 49) /* DSD, 2-byte samples DSD (x16), little endian */ +#define SNDRV_NON_LINEAR_PCM_FORMAT_AC3 ((__force snd_pcm_format_t) 50) /* AC3,NON Linear PCM,spdif */ +#define SNDRV_NON_LINEAR_PCM_FORMAT_EAC3 ((__force snd_pcm_format_t) 51) /* EAC3,NON Linear PCM,spdif*/ +#define SNDRV_NON_LINEAR_PCM_FORMAT_DTS_I ((__force snd_pcm_format_t) 52) /* DTS-I,NON Linear PCM,spdif*/ #define SNDRV_PCM_FORMAT_LAST SNDRV_PCM_FORMAT_DSD_U16_LE #ifdef SNDRV_LITTLE_ENDIAN diff --git a/sound/soc/rockchip/rk_hdmi_spdif.c b/sound/soc/rockchip/rk_hdmi_spdif.c index 039ea452a32c..b8a0a98f509f 100755 --- a/sound/soc/rockchip/rk_hdmi_spdif.c +++ b/sound/soc/rockchip/rk_hdmi_spdif.c @@ -23,6 +23,10 @@ #include #include +#include "card_info.h" +#include "rk_pcm.h" + + #if 0 #define RK_SPDIF_DBG(x...) printk(KERN_INFO "rk_hdmi_spdif:"x) #else @@ -69,6 +73,8 @@ static int rk_hw_params(struct snd_pcm_substream *substream, RK_SPDIF_DBG("spdif:Entered %s\n", __func__); + return 0; + /* set codec DAI configuration */ ret = snd_soc_dai_set_fmt(codec_dai, dai_fmt); if (ret < 0) { @@ -144,6 +150,12 @@ static int rockchip_hdmi_spdif_audio_probe(struct platform_device *pdev) card->dev = &pdev->dev; + ret = rockchip_of_get_sound_card_info(card); + if (ret) { + printk("%s() get sound card info failed:%d\n", __FUNCTION__, ret); + return ret; + } + ret = snd_soc_register_card(card); if (ret) diff --git a/sound/soc/rockchip/rk_spdif.c b/sound/soc/rockchip/rk_spdif.c index 85075797afe1..5d963e307964 100755 --- a/sound/soc/rockchip/rk_spdif.c +++ b/sound/soc/rockchip/rk_spdif.c @@ -29,6 +29,9 @@ #include #include +#include +#include + #include #include #include @@ -50,25 +53,49 @@ /* 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 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 + +#define SPDIF_BURSTINFO 0x100 +#define SPDIF_REPETTION 0x104 + +#define DATA_OUTBUF 0x20 + +#define SPDIF_CHANNEL_SEL_8CH ((0x2<<16)|(0x0<<0)) +#define SPDIF_CHANNEL_SEL_2CH ((0x2<<16)|(0x2<<0)) + +//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_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) @@ -76,19 +103,41 @@ #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) +//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 DMACR_TRAN_DMA_DISABLE (0<<5) -#define DMACR_TRAN_DMA_ENABLE (1<<5) -#define DMACR_TRAN_DMA_CTL_MASK (1<<5) +#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 -#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) struct rockchip_spdif_info { @@ -118,14 +167,16 @@ static void spdif_snd_txctrl(struct rockchip_spdif_info *spdif, int on) xfer |= XFER_TRAN_START; opr |= DMACR_TRAN_DMA_ENABLE; writel(xfer, regs + XFER); - writel(opr|0x10, regs + DMACR); + 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; writel(xfer, regs + XFER); - writel(opr|0x10, regs + DMACR); - } + 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)); + } } static int spdif_set_syclk(struct snd_soc_dai *cpu_dai, @@ -179,7 +230,8 @@ static int spdif_hw_params(struct snd_pcm_substream *substream, struct rockchip_spdif_info *spdif = to_info(dai); void __iomem *regs = spdif->regs; unsigned long flags; - int cfgr, dmac; + int cfgr, dmac,intcr,chnsr_byte[5]={0}; + int dataType,ErrFlag,DataLen,DataInfo,BsNum,Repetition,BurstInfo; RK_SPDIF_DBG("Entered %s\n", __func__); @@ -212,18 +264,79 @@ static int spdif_hw_params(struct snd_pcm_substream *substream, cfgr &= ~CFGR_HALFWORD_TX_MASK; cfgr |= CFGR_HALFWORD_TX_ENABLE; - cfgr &= ~CFGR_CLK_RATE_MASK; + cfgr &= ~CFGR_CLK_RATE_MASK;//set most MCLK:192kHz cfgr |= (1<<16); cfgr &= ~CFGR_JUSTIFIED_MASK; cfgr |= CFGR_JUSTIFIED_RIGHT; + + cfgr &= ~CFGR_CSE_MASK; + cfgr |= CFGR_CSE_DISABLE; + + 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; + writel(intcr, regs + INTCR); + dmac = readl(regs + DMACR) & DMACR_TRAN_DMA_MASK & (~DMACR_TRAN_DATA_LEVEL_MASK); dmac |= 0x10; 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; + } + 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); + } spin_unlock_irqrestore(&spdif->lock, flags); return 0; @@ -301,13 +414,15 @@ static int spdif_probe(struct platform_device *pdev) return -ENXIO; } - spdif->clk= clk_get(&pdev->dev, NULL); + spdif->clk= clk_get(&pdev->dev, "spdif_mclk"); if (IS_ERR(spdif->clk)) { dev_err(&pdev->dev, "Can't retrieve spdif clock\n"); return PTR_ERR(spdif->clk); } - clk_prepare_enable(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, @@ -346,6 +461,7 @@ static int spdif_probe(struct platform_device *pdev) } 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"); -- 2.34.1