rk3288 spdif: spdif sound support
[firefly-linux-kernel-4.4.55.git] / sound / soc / rockchip / rk_spdif.c
index 85075797afe16e448031a396ae5607bacf1a3189..5d963e30796403508b84a1078b34e1e8e596897d 100755 (executable)
@@ -29,6 +29,9 @@
 #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 {
@@ -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");