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, 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, 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_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 __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", -4); 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 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); return 0; }
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 sysclk=%d\n", __func__, freq); spdif->clk_rate = freq; clk_set_rate(spdif->clk, freq); 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 int spdif_probe(struct platform_device *pdev) { /*struct device_node *spdif_np = pdev->dev.of_node;*/ 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); if (!spdif) { dev_err(&pdev->dev, "Can't allocate spdif info\n"); return -ENOMEM; } platform_set_drvdata(pdev, spdif); spin_lock_init(&spdif->lock); /* get spdif register regoin. */ mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!mem_res) { dev_err(&pdev->dev, "No memory resource\n"); ret = -ENOENT; goto err_; } 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_; } 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_; } /* 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 hclock\n"); spdif->hclk = NULL; } clk_prepare_enable(spdif->hclk); /* get spdif clock and init. */ spdif->clk = devm_clk_get(&pdev->dev, "spdif_mclk"); if (IS_ERR(spdif->clk)) { dev_err(&pdev->dev, "Can't retrieve spdif clock\n"); ret = -ENOMEM; goto err_; } clk_set_rate(spdif->clk, 12288000); clk_set_rate(spdif->clk, 11289600); clk_prepare_enable(spdif->clk); spdif->dma_playback.addr = mem_res->start + DATA_OUTBUF; 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); if (ret) { dev_err(&pdev->dev, "Could not register DAI: %d\n", ret); ret = -ENOMEM; goto err_; } ret = rockchip_pcm_platform_register(&pdev->dev); if (ret) { dev_err(&pdev->dev, "Could not register PCM: %d\n", ret); goto err_; } RK_SPDIF_DBG("spdif:spdif probe ok!\n"); return 0; err_: platform_set_drvdata(pdev, NULL); return ret; }
static int spdif_resume(struct snd_soc_dai *cpu_dai) { RK_SPDIF_DBG("spdif:Entered %s\n", __func__); return 0; }
static int spdif_hw_params(struct snd_pcm_substream * substream, 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 data_type, err_flag, data_len, data_info; int bs_num, repetition, burst_info; RK_SPDIF_DBG("Entered %s\n", __func__); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { dai->playback_dma_data = &spdif->dma_playback; } else { pr_err("spdif:Capture is not supported\n"); return -EINVAL; } 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_FORMAT_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; /* set most MCLK:192kHz */ cfgr &= ~CFGR_CLK_RATE_MASK; 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; /* stream type*/ if (!snd_pcm_format_linear(params_format(params))) 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); chnsr_byte[1] = (0x0); chnsr_byte[2] = (0x0) | (0x0 << 4) | (0x0 << 6); chnsr_byte[3] = (0x00) | (0x00); chnsr_byte[4] = (0x0 << 4) | (0x01 << 1 | 0x0); /* set stream type */ if (!snd_pcm_format_linear(params_format(params))) { chnsr_byte[0] |= (0x1<<1); chnsr_byte[4] = (0x0<<4)|(0x00<<1|0x0); } 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); /* set non-linear params */ if (!snd_pcm_format_linear(params_format(params))) { switch (params_format(params)) { case SNDRV_NON_LINEAR_PCM_FORMAT_AC3: /* bit0:6 AC-3:0x01, DTS-I -II -III:11,12,13 */ data_type = burst_info_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: data_type = BURST_INFO_DATA_TYPE_DTS_I; repetition = 512; break; case SNDRV_NON_LINEAR_PCM_FORMAT_EAC3: data_type = burst_info_DATA_TYPE_EAC3; repetition = 6144; break; default: return -EINVAL; } err_flag = 0x0; data_len = params_period_size(params) * 2 * 16; data_info = 0; bs_num = 0x0; burst_info = (data_len << 16) | (bs_num << 13) | (data_info << 8) | (err_flag << 7) | data_type; writel(burst_info, regs + SPDIF_BURST_INFO); writel(repetition, regs + SPDIF_REPETTION); } spin_unlock_irqrestore(&spdif->lock, flags); return 0; err: spin_unlock_irqrestore(&spdif->lock, flags); return -EINVAL; }