kernel->spdif:use base source and moidfy dts file

This commit is contained in:
cjp
2015-08-28 17:48:39 +08:00
committed by jp
parent 688bd90323
commit 9bcd9e1673
5 changed files with 301 additions and 375 deletions

View File

@ -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>;

View File

@ -822,13 +822,13 @@
spdif: rockchip-spdif@0xff8b0000 {
compatible = "rockchip-spdif";
reg = <0xff8b0000 0x10000>; //8channel
//reg = <ff880000 0x10000>;//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 = <GIC_SPI 86 IRQ_TYPE_LEVEL_HIGH>;
dmas = <&pdma0 3>;
//dmas = <&pdma0 2>; //2channel
interrupts = <GIC_SPI 54 IRQ_TYPE_LEVEL_HIGH>;
//dmas = <&pdma0 3>;
dmas = <&pdma0 2>; //2channel
//#dma-cells = <1>;
dma-names = "tx";
pinctrl-names = "default";

View File

@ -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

View File

@ -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, <hzb@rock-chips.com>");
MODULE_DESCRIPTION("ALSA SoC RK+S/PDIF");
MODULE_AUTHOR("hzb <hzb@rock-chips.com>");
MODULE_DESCRIPTION("Rockchip HDMI Spdif Card");
MODULE_LICENSE("GPL");

View File

@ -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 <linux/init.h>
@ -37,115 +40,109 @@
#include <sound/initval.h>
#include <sound/soc.h>
#include <sound/dmaengine_pcm.h>
#include <asm/io.h>
#include <linux/spinlock.h>
#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, <sw.youn@rockchip.com>");
MODULE_DESCRIPTION("rockchip S/PDIF Controller Driver");
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Sugar <sugar.zhang@rock-chips.com>");
MODULE_DESCRIPTION("Rockchip S/PDIF Controller Driver");
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("platform:rockchip-spdif");