#include <linux/regmap.h>
#include <linux/slab.h>
+#include <linux/rockchip/iomap.h>
+#include <linux/rockchip/grf.h>
+
#include <asm/dma.h>
#include <sound/core.h>
#include <sound/pcm.h>
/* 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)
#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 {
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,
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__);
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;
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,
}
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");