build/patch/kernel/sun7i-default/0028-dev-i2s-spdif.patch

3393 lines
118 KiB
Diff

diff --git a/include/sound/pcm.h b/include/sound/pcm.h
index 0d11128..1648b5d 100644
--- a/include/sound/pcm.h
+++ b/include/sound/pcm.h
@@ -124,6 +124,10 @@ struct snd_pcm_ops {
#define SNDRV_PCM_RATE_96000 (1<<10) /* 96000Hz */
#define SNDRV_PCM_RATE_176400 (1<<11) /* 176400Hz */
#define SNDRV_PCM_RATE_192000 (1<<12) /* 192000Hz */
+#define SNDRV_PCM_RATE_352800 (1<<13) /* 352800Hz */
+#define SNDRV_PCM_RATE_384000 (1<<14) /* 384000Hz */
+#define SNDRV_PCM_RATE_705600 (1<<15) /* 705600Hz */
+#define SNDRV_PCM_RATE_768000 (1<<16) /* 768000Hz */
#define SNDRV_PCM_RATE_CONTINUOUS (1<<30) /* continuous range */
#define SNDRV_PCM_RATE_KNOT (1<<31) /* supports more non-continuos rates */
@@ -136,6 +140,10 @@ struct snd_pcm_ops {
SNDRV_PCM_RATE_88200|SNDRV_PCM_RATE_96000)
#define SNDRV_PCM_RATE_8000_192000 (SNDRV_PCM_RATE_8000_96000|SNDRV_PCM_RATE_176400|\
SNDRV_PCM_RATE_192000)
+#define SNDRV_PCM_RATE_8000_384000 (SNDRV_PCM_RATE_8000_192000|SNDRV_PCM_RATE_352800|\
+ SNDRV_PCM_RATE_384000)
+#define SNDRV_PCM_RATE_8000_768000 (SNDRV_PCM_RATE_8000_384000|SNDRV_PCM_RATE_705600|\
+ SNDRV_PCM_RATE_768000)
#define _SNDRV_PCM_FMTBIT(fmt) (1ULL << (__force int)SNDRV_PCM_FORMAT_##fmt)
#define SNDRV_PCM_FMTBIT_S8 _SNDRV_PCM_FMTBIT(S8)
#define SNDRV_PCM_FMTBIT_U8 _SNDRV_PCM_FMTBIT(U8)
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
old mode 100644
new mode 100755
index d776291..167cbd2
--- a/sound/core/pcm_native.c
+++ b/sound/core/pcm_native.c
@@ -1763,12 +1763,13 @@ static int snd_pcm_hw_rule_sample_bits(struct snd_pcm_hw_params *params,
return snd_interval_refine(hw_param_interval(params, rule->var), &t);
}
-#if SNDRV_PCM_RATE_5512 != 1 << 0 || SNDRV_PCM_RATE_192000 != 1 << 12
+#if SNDRV_PCM_RATE_5512 != 1 << 0 || SNDRV_PCM_RATE_768000 != 1 << 16
#error "Change this table"
#endif
static unsigned int rates[] = { 5512, 8000, 11025, 16000, 22050, 32000, 44100,
- 48000, 64000, 88200, 96000, 176400, 192000 };
+ 48000, 64000, 88200, 96000, 176400, 192000,
+ 352800, 384000, 705600, 768000 };
const struct snd_pcm_hw_constraint_list snd_pcm_known_rates = {
.count = ARRAY_SIZE(rates),
diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig
index adafead..2334cab 100644
--- a/sound/soc/Kconfig
+++ b/sound/soc/Kconfig
@@ -60,7 +60,7 @@ source "sound/soc/sunxi/Kconfig"
source "sound/soc/sunxi/hdmiaudio/Kconfig"
source "sound/soc/sunxi/spdif/Kconfig"
# i2s needs various adjustments for sun7i
-if ARCH_SUN4I || ARCH_SUN5I
+if ARCH_SUN4I || ARCH_SUN5I || ARCH_SUN7I
source "sound/soc/sunxi/i2s/Kconfig"
endif
endif
diff --git a/sound/soc/sunxi/i2s/Kconfig b/sound/soc/sunxi/i2s/Kconfig
index a6dff42..f244faa 100644
--- a/sound/soc/sunxi/i2s/Kconfig
+++ b/sound/soc/sunxi/i2s/Kconfig
@@ -1,5 +1,5 @@
config SND_SUNXI_SOC_I2S_INTERFACE
- tristate "SoC i2s interface for the AllWinner sun4i and sun5i chips"
+ tristate "SoC i2s interface for the AllWinner sun4i, sun5i and sun7i chips"
default m
help
Say Y or M if you want to add support for codecs attached to
diff --git a/sound/soc/sunxi/i2s/sndi2s.c b/sound/soc/sunxi/i2s/sndi2s.c
index 68bad02..92e01a8 100644
--- a/sound/soc/sunxi/i2s/sndi2s.c
+++ b/sound/soc/sunxi/i2s/sndi2s.c
@@ -35,11 +35,20 @@ struct sndi2s_priv {
};
static int i2s_used = 0;
-#define sndi2s_RATES (SNDRV_PCM_RATE_8000_192000|SNDRV_PCM_RATE_KNOT)
-#define sndi2s_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE | \
- SNDRV_PCM_FMTBIT_S18_3LE | SNDRV_PCM_FMTBIT_S20_3LE)
+static int sunxi_i2s_slave = 0;
+
+#define sndi2s_RATES_MASTER (SNDRV_PCM_RATE_8000_192000|SNDRV_PCM_RATE_KNOT)
+#define sndi2s_RATES_SLAVE (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |\
+ SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |\
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000|\
+ SNDRV_PCM_RATE_352800 | SNDRV_PCM_RATE_384000)
-hdmi_audio_t hdmi_parameter;
+#if defined CONFIG_ARCH_SUN7I
+#define sndi2s_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE)
+#else
+#define sndi2s_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE | \
+ SNDRV_PCM_FMTBIT_S18_3LE | SNDRV_PCM_FMTBIT_S20_LE)
+#endif
static int sndi2s_mute(struct snd_soc_dai *dai, int mute)
{
@@ -62,8 +71,6 @@ static int sndi2s_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
- hdmi_parameter.sample_rate = params_rate(params);
-
return 0;
}
@@ -75,9 +82,6 @@ static int sndi2s_set_dai_sysclk(struct snd_soc_dai *codec_dai,
static int sndi2s_set_dai_clkdiv(struct snd_soc_dai *codec_dai, int div_id, int div)
{
-
- hdmi_parameter.fs_between = div;
-
return 0;
}
@@ -104,7 +108,14 @@ struct snd_soc_dai_driver sndi2s_dai = {
.stream_name = "Playback",
.channels_min = 1,
.channels_max = 2,
- .rates = sndi2s_RATES,
+ .rates = sndi2s_RATES_MASTER,
+ .formats = sndi2s_FORMATS,
+ },
+ .capture = {
+ .stream_name = "Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = sndi2s_RATES_MASTER,
.formats = sndi2s_FORMATS,
},
/* pcm operations */
@@ -129,10 +140,8 @@ static int sndi2s_soc_probe(struct snd_soc_codec *codec)
/* power down chip */
static int sndi2s_soc_remove(struct snd_soc_codec *codec)
{
- struct sndhdmi_priv *sndi2s = snd_soc_codec_get_drvdata(codec);
-
+ struct sndi2s_priv *sndi2s = snd_soc_codec_get_drvdata(codec);
kfree(sndi2s);
-
return 0;
}
@@ -143,6 +152,13 @@ static struct snd_soc_codec_driver soc_codec_dev_sndi2s = {
static int __devinit sndi2s_codec_probe(struct platform_device *pdev)
{
+ if(sunxi_i2s_slave) {
+ sndi2s_dai.playback.rates = sndi2s_RATES_SLAVE;
+ sndi2s_dai.capture.rates = sndi2s_RATES_SLAVE;
+ printk("[I2S-0] sndi2s_codec_probe I2S used in slave mode\n");
+ }
+ else
+ printk("[I2S-0] sndi2s_codec_probe I2S used in master mode\n");
return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_sndi2s, &sndi2s_dai, 1);
}
@@ -169,21 +185,31 @@ static struct platform_driver sndi2s_codec_driver = {
static int __init sndi2s_codec_init(void)
{
int err = 0;
- int ret = 0;
+ int ret = 0, i2s_slave = 0;
ret = script_parser_fetch("i2s_para","i2s_used", &i2s_used, sizeof(int));
if (ret) {
- printk("[I2S]sndi2s_init fetch i2s using configuration failed\n");
+ printk("[I2S-0] sndi2s_init fetch i2s using configuration failed\n");
}
if (i2s_used) {
+ ret = script_parser_fetch("i2s_para","i2s_slave", &i2s_slave, sizeof(int));
+ if(ret == 0 && i2s_slave == 1) {
+ sunxi_i2s_slave = 1;
+ printk("[I2S-0] sndi2s_codec_init I2S used in slave mode\n");
+ }
+ else {
+ sunxi_i2s_slave = 0;
+ printk("[I2S-0] sndi2s_codec_init I2S used in master mode\n");
+ }
+
if((err = platform_device_register(&sndi2s_codec_device)) < 0)
return err;
if ((err = platform_driver_register(&sndi2s_codec_driver)) < 0)
return err;
} else {
- printk("[I2S]sndi2s cannot find any using configuration for controllers, return directly!\n");
+ printk("[I2S-0] sndi2s cannot find any using configuration for controllers, return directly!\n");
return 0;
}
@@ -204,3 +230,4 @@ MODULE_DESCRIPTION("SNDI2S ALSA soc codec driver");
MODULE_AUTHOR("Zoltan Devai, Christian Pellegrin <chripell@evolware.org>");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:sunxi-i2s-codec");
+
diff --git a/sound/soc/sunxi/i2s/sndi2s.h b/sound/soc/sunxi/i2s/sndi2s.h
index e5b95c8..57e2aa5 100644
--- a/sound/soc/sunxi/i2s/sndi2s.h
+++ b/sound/soc/sunxi/i2s/sndi2s.h
@@ -16,6 +16,8 @@
#ifndef SNDI2S_H_
#define SNDI2S_H_
+#if 0
+cleaning code
typedef struct hdmi_audio
{
__u8 hw_intf; /* 0:iis 1:spdif 2:pcm */
@@ -54,5 +56,6 @@ typedef enum tag_HDMI_CMD
HDMI_CMD_AUDIO_ENABLE,
HDMI_CMD_GET_HPD_STATUS,
}__hdmi_cmd_t;
+#endif
#endif
diff --git a/sound/soc/sunxi/i2s/sunxi-i2s.c b/sound/soc/sunxi/i2s/sunxi-i2s.c
index b4dd3ad..f136f80 100644
--- a/sound/soc/sunxi/i2s/sunxi-i2s.c
+++ b/sound/soc/sunxi/i2s/sunxi-i2s.c
@@ -38,7 +38,7 @@
#include "sunxi-i2sdma.h"
#include "sunxi-i2s.h"
-static int regsave[8];
+static int regsave[10];
static int i2s_used = 0;
static struct sunxi_dma_params sunxi_i2s_pcm_stereo_out = {
@@ -58,13 +58,16 @@ static struct sunxi_dma_params sunxi_i2s_pcm_stereo_in = {
};
- struct sunxi_i2s_info sunxi_iis;
+/* most of fields of this structure is never initialized and useless !!!*/
+struct sunxi_i2s_info sunxi_iis;
static u32 i2s_handle = 0;
- static struct clk *i2s_apbclk, *i2s_pll2clk, *i2s_pllx8, *i2s_moduleclk;
+static struct clk *i2s_apbclk, *i2s_pll2clk, *i2s_pllx8, *i2s_moduleclk;
void sunxi_snd_txctrl_i2s(struct snd_pcm_substream *substream, int on)
{
u32 reg_val;
+ int res;
+ printk("[I2S-0] sunxi_snd_txctrl_i2s is on=(%d)\n", on);
reg_val = readl(sunxi_iis.regs + SUNXI_TXCHSEL);
reg_val &= ~0x7;
@@ -73,7 +76,7 @@ void sunxi_snd_txctrl_i2s(struct snd_pcm_substream *substream, int on)
reg_val = readl(sunxi_iis.regs + SUNXI_TXCHMAP);
reg_val = 0;
- if (sunxi_is_sun4i()) {
+ if (sunxi_is_sun4i() || sunxi_is_sun7i()) {
if(substream->runtime->channels == 1) {
reg_val = 0x76543200;
} else {
@@ -89,7 +92,7 @@ void sunxi_snd_txctrl_i2s(struct snd_pcm_substream *substream, int on)
writel(reg_val, sunxi_iis.regs + SUNXI_TXCHMAP);
reg_val = readl(sunxi_iis.regs + SUNXI_IISCTL);
- if (sunxi_is_sun4i()) {
+ if (sunxi_is_sun4i() || sunxi_is_sun7i()) {
reg_val &= ~SUNXI_IISCTL_SDO3EN;
reg_val &= ~SUNXI_IISCTL_SDO2EN;
reg_val &= ~SUNXI_IISCTL_SDO1EN;
@@ -144,12 +147,13 @@ void sunxi_snd_txctrl_i2s(struct snd_pcm_substream *substream, int on)
reg_val |= SUNXI_IISINT_TXDRQEN;
writel(reg_val, sunxi_iis.regs + SUNXI_IISINT);
- //Global Enable Digital Audio Interface
- reg_val = readl(sunxi_iis.regs + SUNXI_IISCTL);
- reg_val |= SUNXI_IISCTL_GEN;
- writel(reg_val, sunxi_iis.regs + SUNXI_IISCTL);
+ //Disable mute
+ res = gpio_write_one_pin_value(i2s_handle, 0, "i2s_mute");
} else {
+ //Enable mute
+ res = gpio_write_one_pin_value(i2s_handle, 1, "i2s_mute");
+
/* IIS TX DISABLE */
reg_val = readl(sunxi_iis.regs + SUNXI_IISCTL);
reg_val &= ~SUNXI_IISCTL_TXEN;
@@ -159,17 +163,26 @@ void sunxi_snd_txctrl_i2s(struct snd_pcm_substream *substream, int on)
reg_val = readl(sunxi_iis.regs + SUNXI_IISINT);
reg_val &= ~SUNXI_IISINT_TXDRQEN;
writel(reg_val, sunxi_iis.regs + SUNXI_IISINT);
-
- //Global disable Digital Audio Interface
- reg_val = readl(sunxi_iis.regs + SUNXI_IISCTL);
- reg_val &= ~SUNXI_IISCTL_GEN;
- writel(reg_val, sunxi_iis.regs + SUNXI_IISCTL);
}
}
-void sunxi_snd_rxctrl_i2s(int on)
+void sunxi_snd_rxctrl_i2s(struct snd_pcm_substream *substream, int on)
{
u32 reg_val;
+ printk("[I2S-0] sunxi_snd_rxctrl_i2s is on=(%d)\n", on);
+ reg_val = readl(sunxi_iis.regs + SUNXI_RXCHSEL);
+ reg_val &= ~0x7;
+ reg_val |= SUNXI_RXCHSEL_CHNUM(substream->runtime->channels);
+ writel(reg_val, sunxi_iis.regs + SUNXI_RXCHSEL);
+
+ reg_val = readl(sunxi_iis.regs + SUNXI_RXCHMAP);
+ reg_val = 0;
+ if(substream->runtime->channels == 1) {
+ reg_val = 0x00003200;
+ } else {
+ reg_val = 0x00003210;
+ }
+ writel(reg_val, sunxi_iis.regs + SUNXI_RXCHMAP);
//flush RX FIFO
reg_val = readl(sunxi_iis.regs + SUNXI_IISFCTL);
@@ -190,63 +203,52 @@ void sunxi_snd_rxctrl_i2s(int on)
reg_val |= SUNXI_IISINT_RXDRQEN;
writel(reg_val, sunxi_iis.regs + SUNXI_IISINT);
- //Global Enable Digital Audio Interface
- reg_val = readl(sunxi_iis.regs + SUNXI_IISCTL);
- reg_val |= SUNXI_IISCTL_GEN;
- writel(reg_val, sunxi_iis.regs + SUNXI_IISCTL);
-
} else {
/* IIS RX DISABLE */
reg_val = readl(sunxi_iis.regs + SUNXI_IISCTL);
reg_val &= ~SUNXI_IISCTL_RXEN;
writel(reg_val, sunxi_iis.regs + SUNXI_IISCTL);
- /* DISBALE dma DRQ mode */
+ /* DISABLE dma DRQ mode */
reg_val = readl(sunxi_iis.regs + SUNXI_IISINT);
reg_val &= ~SUNXI_IISINT_RXDRQEN;
writel(reg_val, sunxi_iis.regs + SUNXI_IISINT);
-
- //Global disable Digital Audio Interface
- reg_val = readl(sunxi_iis.regs + SUNXI_IISCTL);
- reg_val &= ~SUNXI_IISCTL_GEN;
- writel(reg_val, sunxi_iis.regs + SUNXI_IISCTL);
}
}
-static inline int sunxi_snd_is_clkmaster(void)
-{
- return ((readl(sunxi_iis.regs + SUNXI_IISCTL) & SUNXI_IISCTL_MS) ? 0 : 1);
-}
-
static int sunxi_i2s_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
{
u32 reg_val;
u32 reg_val1;
+ printk("[IIS-0] sunxi_i2s_set_fmt\n");
+
//SDO ON
reg_val = readl(sunxi_iis.regs + SUNXI_IISCTL);
- if (sunxi_is_sun4i()) {
+ if (sunxi_is_sun4i() || sunxi_is_sun7i()) {
reg_val |= (SUNXI_IISCTL_SDO0EN | SUNXI_IISCTL_SDO1EN |
SUNXI_IISCTL_SDO2EN | SUNXI_IISCTL_SDO3EN);
} else {
reg_val |= SUNXI_IISCTL_SDO0EN;
}
- writel(reg_val, sunxi_iis.regs + SUNXI_IISCTL);
+
+ //writel(reg_val, sunxi_iis.regs + SUNXI_IISCTL);
/* master or slave selection */
- reg_val = readl(sunxi_iis.regs + SUNXI_IISCTL);
- switch(fmt & SND_SOC_DAIFMT_MASTER_MASK){
- case SND_SOC_DAIFMT_CBM_CFM: /* codec clk & frm master */
- reg_val |= SUNXI_IISCTL_MS;
- break;
- case SND_SOC_DAIFMT_CBS_CFS: /* codec clk & frm slave */
- reg_val &= ~SUNXI_IISCTL_MS;
- break;
- default:
- return -EINVAL;
+ //reg_val = readl(sunxi_iis.regs + SUNXI_IISCTL);
+ if(sunxi_iis.slave)
+ {
+ reg_val |= SUNXI_IISCTL_MS; // 1: Slave!
+ printk("[IIS-0] sunxi_i2s_set_fmt: set slave mode for I2S interface\n");
+ }
+ else
+ {
+ reg_val &= ~SUNXI_IISCTL_MS; // 0: Master!
+ printk("[IIS-0] sunxi_i2s_set_fmt: set master mode for I2S interface\n");
}
writel(reg_val, sunxi_iis.regs + SUNXI_IISCTL);
+ sunxi_iis.lrc_pol = 0;
/* pcm or i2s mode selection */
reg_val = readl(sunxi_iis.regs + SUNXI_IISCTL);
reg_val1 = readl(sunxi_iis.regs + SUNXI_IISFAT0);
@@ -255,24 +257,36 @@ static int sunxi_i2s_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
case SND_SOC_DAIFMT_I2S: /* I2S mode */
reg_val &= ~SUNXI_IISCTL_PCM;
reg_val1 |= SUNXI_IISFAT0_FMT_I2S;
+ sunxi_iis.samp_format = 0;
+ printk("[IIS-0] sunxi_i2s_set_fmt: set I2S mode\n");
break;
case SND_SOC_DAIFMT_RIGHT_J: /* Right Justified mode */
reg_val &= ~SUNXI_IISCTL_PCM;
reg_val1 |= SUNXI_IISFAT0_FMT_RGT;
+ sunxi_iis.samp_format = 2;
+ printk("[IIS-0] sunxi_i2s_set_fmt: set Right Justified mode\n");
break;
case SND_SOC_DAIFMT_LEFT_J: /* Left Justified mode */
reg_val &= ~SUNXI_IISCTL_PCM;
reg_val1 |= SUNXI_IISFAT0_FMT_LFT;
+ sunxi_iis.samp_format = 1;
+ /*printk("[IIS-0] sunxi_i2s_set_fmt: set Left Justified mode\n");*/
break;
case SND_SOC_DAIFMT_DSP_A: /* L data msb after FRM LRC */
reg_val |= SUNXI_IISCTL_PCM;
reg_val1 &= ~SUNXI_IISFAT0_LRCP;
+ sunxi_iis.samp_format = 3;
+ printk("[IIS-0] sunxi_i2s_set_fmt: set L data msb after FRM LRC mode\n");
break;
case SND_SOC_DAIFMT_DSP_B: /* L data msb during FRM LRC */
reg_val |= SUNXI_IISCTL_PCM;
reg_val1 |= SUNXI_IISFAT0_LRCP;
+ sunxi_iis.samp_format = 3;
+ sunxi_iis.lrc_pol = 1;
+ printk("[IIS-0] sunxi_i2s_set_fmt: set L data msb during FRM LRC mode\n");
break;
default:
+ printk("[IIS-0] sunxi_i2s_set_fmt: unknown mode\n");
return -EINVAL;
}
writel(reg_val, sunxi_iis.regs + SUNXI_IISCTL);
@@ -284,25 +298,41 @@ static int sunxi_i2s_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
case SND_SOC_DAIFMT_NB_NF: /* normal bit clock + frame */
reg_val1 &= ~SUNXI_IISFAT0_LRCP;
reg_val1 &= ~SUNXI_IISFAT0_BCP;
+ sunxi_iis.lrc_pol = 0;
+ sunxi_iis.bclk_pol = 0;
+ printk("[IIS-0] sunxi_i2s_set_fmt: normal bit clock + frame\n");
break;
case SND_SOC_DAIFMT_NB_IF: /* normal bclk + inv frm */
reg_val1 |= SUNXI_IISFAT0_LRCP;
reg_val1 &= ~SUNXI_IISFAT0_BCP;
+ sunxi_iis.lrc_pol = 1;
+ sunxi_iis.bclk_pol = 0;
+ printk("[IIS-0] sunxi_i2s_set_fmt: normal bclk + inv frm\n");
break;
case SND_SOC_DAIFMT_IB_NF: /* invert bclk + nor frm */
reg_val1 &= ~SUNXI_IISFAT0_LRCP;
reg_val1 |= SUNXI_IISFAT0_BCP;
+ sunxi_iis.lrc_pol = 0;
+ sunxi_iis.bclk_pol = 1;
+ printk("[IIS-0] sunxi_i2s_set_fmt: invert bclk + nor frm\n");
break;
case SND_SOC_DAIFMT_IB_IF: /* invert bclk + frm */
reg_val1 |= SUNXI_IISFAT0_LRCP;
reg_val1 |= SUNXI_IISFAT0_BCP;
+ sunxi_iis.lrc_pol = 1;
+ sunxi_iis.bclk_pol = 1;
+ printk("[IIS-0] sunxi_i2s_set_fmt: invert bclk + frm\n");
break;
}
writel(reg_val1, sunxi_iis.regs + SUNXI_IISFAT0);
- /* word select size */
+ /* clear word select size */
reg_val = readl(sunxi_iis.regs + SUNXI_IISFAT0);
reg_val &= ~SUNXI_IISFAT0_WSS_32BCLK;
+ /* word size hardcoded to 32 (ref. sunxi-sndi2s.c func. sunxi_sndi2s_hw_params()) */
+ sunxi_iis.ws_size = 32;
+ printk("[IIS-0] sunxi_i2s_set_fmt: word size = %d\n", sunxi_iis.ws_size);
+ /*
if(sunxi_iis.ws_size == 16)
reg_val |= SUNXI_IISFAT0_WSS_16BCLK;
else if(sunxi_iis.ws_size == 20)
@@ -310,47 +340,57 @@ static int sunxi_i2s_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
else if(sunxi_iis.ws_size == 24)
reg_val |= SUNXI_IISFAT0_WSS_24BCLK;
else
- reg_val |= SUNXI_IISFAT0_WSS_32BCLK;
+ */
+ reg_val |= SUNXI_IISFAT0_WSS_32BCLK;
+
writel(reg_val, sunxi_iis.regs + SUNXI_IISFAT0);
/* PCM REGISTER setup */
- reg_val = sunxi_iis.pcm_txtype&0x3;
- reg_val |= sunxi_iis.pcm_rxtype<<2;
+ reg_val = 0;
+ //reg_val = sunxi_iis.pcm_txtype&0x3;
+ //reg_val |= sunxi_iis.pcm_rxtype<<2;
if(!sunxi_iis.pcm_sync_type)
+ {
reg_val |= SUNXI_IISFAT1_SSYNC; //short sync
+ printk("[IIS-0] sunxi_i2s_set_fmt: set pcm_sync_type = short sync\n");
+ }
if(sunxi_iis.pcm_sw == 16)
+ {
reg_val |= SUNXI_IISFAT1_SW;
+ printk("[IIS-0] sunxi_i2s_set_fmt: pcm_sw == 16\n");
+ }
reg_val |=((sunxi_iis.pcm_start_slot - 1)&0x3)<<6; //start slot index
reg_val |= sunxi_iis.pcm_lsb_first<<9; //MSB or LSB first
if(sunxi_iis.pcm_sync_period == 256)
- reg_val |= 0x4<<12;
+ reg_val |= SUNXI_IISFAT1_SYNCLEN_256BCLK;
else if (sunxi_iis.pcm_sync_period == 128)
- reg_val |= 0x3<<12;
+ reg_val |= SUNXI_IISFAT1_SYNCLEN_128BCLK;
else if (sunxi_iis.pcm_sync_period == 64)
- reg_val |= 0x2<<12;
+ reg_val |= SUNXI_IISFAT1_SYNCLEN_64BCLK;
else if (sunxi_iis.pcm_sync_period == 32)
- reg_val |= 0x1<<12;
+ reg_val |= SUNXI_IISFAT1_SYNCLEN_32BCLK;
writel(reg_val, sunxi_iis.regs + SUNXI_IISFAT1);
/* set FIFO control register */
- reg_val = 0 & 0x3;
- reg_val |= (1 & 0x1)<<2;
- reg_val |= SUNXI_IISFCTL_RXTL(0xf); //RX FIFO trigger level
- reg_val |= SUNXI_IISFCTL_TXTL(0x40); //TX FIFO empty trigger level
+ reg_val = 0;
+ reg_val |= SUNXI_IISFCTL_RXTL(0xf); //RX FIFO trigger level
+ reg_val |= SUNXI_IISFCTL_TXTL(0x40); //TX FIFO empty trigger level
writel(reg_val, sunxi_iis.regs + SUNXI_IISFCTL);
return 0;
}
static int sunxi_i2s_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)
{
+ u32 reg_val;
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct sunxi_dma_params *dma_data;
+ printk("[IIS-0] sunxi_i2s_hw_params: %s\n", substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? "playback" : "recording");
/* play or record */
if(substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
@@ -358,7 +398,48 @@ static int sunxi_i2s_hw_params(struct snd_pcm_substream *substream,
else
dma_data = &sunxi_i2s_pcm_stereo_in;
+ /* set format info */
+ reg_val = readl(sunxi_iis.regs + SUNXI_IISFAT0);
+ /* clear sample resolution select size */
+ reg_val &= ~SUNXI_IISFAT0_SR_RVD;
+
+ switch (params_format(params))
+ {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ reg_val |= SUNXI_IISFAT0_SR_16BIT;
+ sunxi_iis.samp_res = 16;
+ break;
+ case SNDRV_PCM_FORMAT_S20_3LE:
+ reg_val |= SUNXI_IISFAT0_SR_20BIT;
+ sunxi_iis.samp_res = 20;
+ break;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ reg_val |= SUNXI_IISFAT0_SR_24BIT;
+ sunxi_iis.samp_res = 24;
+ break;
+ default:
+ pr_err("[IIS-0] sunxi_i2s_hw_params: Unsupported format (%d)\n", (int)params_format(params));
+ return -EINVAL;
+ }
+ writel(reg_val, sunxi_iis.regs + SUNXI_IISFAT0);
+
+ /* set FIFO control register */
+ reg_val = readl(sunxi_iis.regs + SUNXI_IISFCTL);
+ reg_val |= SUNXI_IISFCTL_TXIM_MOD1; //1: Valid data at the LSB of TXFIFO register
+ //CHECK EXPANDING FORMAT!!!
+ if(sunxi_iis.samp_res == 24) {
+ reg_val &= ~SUNXI_IISFCTL_RXOM_MOD3; //00: Expanding 0 at LSB of DA_RXFIFO register
+ }
+ else {
+ reg_val |= SUNXI_IISFCTL_RXOM_MOD1; //00: Expanding 0 at LSB of DA_RXFIFO register
+ }
+ writel(reg_val, sunxi_iis.regs + SUNXI_IISFCTL);
+
snd_soc_dai_set_dma_data(rtd->cpu_dai, substream, dma_data);
+ sunxi_iis.samp_fs = params_rate(params);
+ sunxi_iis.channel_num = params_channels(params);
+ printk("[IIS-0] sunxi_i2s_hw_params: channel num %d, format %d bit, sample rate %d\n",
+ sunxi_iis.channel_num, sunxi_iis.samp_res, sunxi_iis.samp_fs);
return 0;
}
@@ -375,7 +456,7 @@ static int sunxi_i2s_trigger(struct snd_pcm_substream *substream,
case SNDRV_PCM_TRIGGER_RESUME:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
- sunxi_snd_rxctrl_i2s(1);
+ sunxi_snd_rxctrl_i2s(substream, 1);
} else {
sunxi_snd_txctrl_i2s(substream, 1);
}
@@ -385,7 +466,7 @@ static int sunxi_i2s_trigger(struct snd_pcm_substream *substream,
case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
- sunxi_snd_rxctrl_i2s(0);
+ sunxi_snd_rxctrl_i2s(substream, 0);
} else {
sunxi_snd_txctrl_i2s(substream, 0);
}
@@ -403,9 +484,17 @@ static int sunxi_i2s_set_sysclk(struct snd_soc_dai *cpu_dai, int clk_id,
unsigned int freq, int dir)
{
if (!freq) {
- clk_set_rate(i2s_pll2clk, 24576000);
+ /*printk("[IIS-0] sunxi_i2s_set_sysclk: set sysclk=24576000\n");*/
+ if(sunxi_iis.slave)
+ gpio_write_one_pin_value(i2s_handle, 0, "i2s_clk_sel");
+ else
+ clk_set_rate(i2s_pll2clk, 24576000);
} else {
- clk_set_rate(i2s_pll2clk, 22579200);
+ /*printk("[IIS-0] sunxi_i2s_set_sysclk: set sysclk=22579200\n");*/
+ if(sunxi_iis.slave)
+ gpio_write_one_pin_value(i2s_handle, 1, "i2s_clk_sel");
+ else
+ clk_set_rate(i2s_pll2clk, 22579200);
}
return 0;
@@ -414,6 +503,27 @@ static int sunxi_i2s_set_sysclk(struct snd_soc_dai *cpu_dai, int clk_id,
static int sunxi_i2s_set_clkdiv(struct snd_soc_dai *cpu_dai, int div_id, int div)
{
u32 reg;
+ /*printk("[IIS-0] sunxi_i2s_set_clkdiv: PLL clock div_id=(%s), div=(%d)\n",
+ div_id == SUNXI_DIV_MCLK ? "SUNXI_DIV_MCLK" :
+ (div_id == SUNXI_DIV_BCLK ? "SUNXI_DIV_BCLK" : "SUNXI_DIV_EXTCLK"), div);*/
+
+
+ if(sunxi_iis.slave) {
+ if(div_id != SUNXI_DIV_EXTCLK) {
+ pr_err("[I2S-0] try to set external clock divider failed\n");
+ return -EINVAL;
+ }
+ /*printk("[IIS-0] sunxi_i2s_set_clkdiv: external clock, div=(%d)\n", div);*/
+ }
+ else {
+ if(div_id != SUNXI_DIV_MCLK && div_id != SUNXI_DIV_BCLK) {
+ pr_err("[I2S-0] try to set PLL clock divider failed\n");
+ return -EINVAL;
+ }
+ /*printk("[IIS-0] sunxi_i2s_set_clkdiv: PLL clock div_id=(%s), div=(%d)\n",
+ div_id == SUNXI_DIV_MCLK ? "SUNXI_DIV_MCLK" : "SUNXI_DIV_BCLK", div);*/
+ }
+
switch (div_id) {
case SUNXI_DIV_MCLK:
if(div <= 8)
@@ -447,18 +557,43 @@ static int sunxi_i2s_set_clkdiv(struct snd_soc_dai *cpu_dai, int div_id, int div
reg = (readl(sunxi_iis.regs + SUNXI_IISCLKD) & ~SUNXI_IISCLKD_BCLK_MASK) | (div <<SUNXI_IISCLKD_BCLK_OFFS);
writel(reg, sunxi_iis.regs + SUNXI_IISCLKD);
break;
+ case SUNXI_DIV_EXTCLK:
+ /*printk("[IIS-0] sunxi_i2s_set_clkdiv set divider=(%d)\n", div);*/
+ if(div == 512) {
+ gpio_write_one_pin_value(i2s_handle, 1, "i2s_clk_div1");
+ gpio_write_one_pin_value(i2s_handle, 1, "i2s_clk_div0");
+ }
+ else if(div == 256) {
+ gpio_write_one_pin_value(i2s_handle, 0, "i2s_clk_div1");
+ gpio_write_one_pin_value(i2s_handle, 1, "i2s_clk_div0");
+ }
+ else if(div == 128) {
+ gpio_write_one_pin_value(i2s_handle, 0, "i2s_clk_div1");
+ gpio_write_one_pin_value(i2s_handle, 0, "i2s_clk_div0");
+ }
+ else if(div == 64) {
+ gpio_write_one_pin_value(i2s_handle, 1, "i2s_clk_div1");
+ gpio_write_one_pin_value(i2s_handle, 0, "i2s_clk_div0");
+ }
+ else {
+ pr_err("[I2S-0] try to set unsupported external clock divider div=(%d)\n", div);
+ return -EINVAL;
+ }
+ break;
default:
return -EINVAL;
}
- //diable MCLK output when high samplerate
+ //disable MCLK output when high samplerate or slave mode
reg = readl(sunxi_iis.regs + SUNXI_IISCLKD);
- if (!(reg & 0xF)) {
+ if (!(reg & 0xF) || sunxi_iis.slave) {
reg &= ~SUNXI_IISCLKD_MCLKOEN;
writel(reg, sunxi_iis.regs + SUNXI_IISCLKD);
+ /*printk("[IIS-0] sunxi_i2s_set_clkdiv: disable MCLK\n");*/
} else {
reg |= SUNXI_IISCLKD_MCLKOEN;
writel(reg, sunxi_iis.regs + SUNXI_IISCLKD);
+ /*printk("[IIS-0] sunxi_i2s_set_clkdiv: enable MCLK\n");*/
}
return 0;
@@ -483,6 +618,8 @@ static void iisregsave(void)
regsave[5] = readl(sunxi_iis.regs + SUNXI_IISCLKD);
regsave[6] = readl(sunxi_iis.regs + SUNXI_TXCHSEL);
regsave[7] = readl(sunxi_iis.regs + SUNXI_TXCHMAP);
+ regsave[8] = readl(sunxi_iis.regs + SUNXI_RXCHSEL);
+ regsave[9] = readl(sunxi_iis.regs + SUNXI_RXCHMAP);
}
static void iisregrestore(void)
@@ -495,57 +632,71 @@ static void iisregrestore(void)
writel(regsave[5], sunxi_iis.regs + SUNXI_IISCLKD);
writel(regsave[6], sunxi_iis.regs + SUNXI_TXCHSEL);
writel(regsave[7], sunxi_iis.regs + SUNXI_TXCHMAP);
+ writel(regsave[8], sunxi_iis.regs + SUNXI_RXCHSEL);
+ writel(regsave[9], sunxi_iis.regs + SUNXI_RXCHMAP);
}
static int sunxi_i2s_suspend(struct snd_soc_dai *cpu_dai)
{
u32 reg_val;
- printk("[IIS]Entered %s\n", __func__);
+ printk("[I2S-0] Entered %s\n", __func__);
- //Global Enable Digital Audio Interface
+ //Global Disable Digital Audio Interface
reg_val = readl(sunxi_iis.regs + SUNXI_IISCTL);
reg_val &= ~SUNXI_IISCTL_GEN;
writel(reg_val, sunxi_iis.regs + SUNXI_IISCTL);
iisregsave();
- //release the module clock
- clk_disable(i2s_moduleclk);
-
+ if(!sunxi_iis.slave) {
+ //release the module clock, only for master mode
+ clk_disable(i2s_moduleclk);
+ }
clk_disable(i2s_apbclk);
//printk("[IIS]PLL2 0x01c20008 = %#x\n", *(volatile int*)0xF1C20008);
- printk("[IIS]SPECIAL CLK 0x01c20068 = %#x, line= %d\n", *(volatile int*)0xF1C20068, __LINE__);
- printk("[IIS]SPECIAL CLK 0x01c200B8 = %#x, line = %d\n", *(volatile int*)0xF1C200B8, __LINE__);
+ printk("[I2S-0] SPECIAL CLK 0x01c20068 = %#x, line= %d\n", *(volatile int*)0xF1C20068, __LINE__);
+ printk("[I2S-0] SPECIAL CLK 0x01c200B8 = %#x, line = %d\n", *(volatile int*)0xF1C200B8, __LINE__);
return 0;
}
static int sunxi_i2s_resume(struct snd_soc_dai *cpu_dai)
{
u32 reg_val;
- printk("[IIS]Entered %s\n", __func__);
+ printk("[I2S-0] Entered %s\n", __func__);
- //release the module clock
+ //enable the module clock
clk_enable(i2s_apbclk);
- //release the module clock
- clk_enable(i2s_moduleclk);
+ if(!sunxi_iis.slave) {
+
+ //enable the module clock
+ clk_enable(i2s_moduleclk);
+ }
iisregrestore();
//Global Enable Digital Audio Interface
reg_val = readl(sunxi_iis.regs + SUNXI_IISCTL);
+ if(sunxi_iis.slave)
+ reg_val |= SUNXI_IISCTL_MS; // 1: Slave!
+ else
+ reg_val &= ~SUNXI_IISCTL_MS; // 0: Master!
reg_val |= SUNXI_IISCTL_GEN;
writel(reg_val, sunxi_iis.regs + SUNXI_IISCTL);
//printk("[IIS]PLL2 0x01c20008 = %#x\n", *(volatile int*)0xF1C20008);
- printk("[IIS]SPECIAL CLK 0x01c20068 = %#x, line= %d\n", *(volatile int*)0xF1C20068, __LINE__);
- printk("[IIS]SPECIAL CLK 0x01c200B8 = %#x, line = %d\n", *(volatile int*)0xF1C200B8, __LINE__);
+ printk("[I2S-0] SPECIAL CLK 0x01c20068 = %#x, line= %d\n", *(volatile int*)0xF1C20068, __LINE__);
+ printk("[I2S-0] SPECIAL CLK 0x01c200B8 = %#x, line = %d\n", *(volatile int*)0xF1C200B8, __LINE__);
return 0;
}
-#define SUNXI_I2S_RATES (SNDRV_PCM_RATE_8000_192000 | SNDRV_PCM_RATE_KNOT)
+#define SUNXI_I2S_RATES_MASTER (SNDRV_PCM_RATE_8000_192000 | SNDRV_PCM_RATE_KNOT)
+#define SUNXI_I2S_RATES_SLAVE (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |\
+ SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |\
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000 |\
+ SNDRV_PCM_RATE_352800 | SNDRV_PCM_RATE_384000)
static struct snd_soc_dai_ops sunxi_iis_dai_ops = {
.trigger = sunxi_i2s_trigger,
.hw_params = sunxi_i2s_hw_params,
@@ -562,14 +713,14 @@ static struct snd_soc_dai_driver sunxi_iis_dai = {
.playback = {
.channels_min = 1,
.channels_max = 2,
- .rates = SUNXI_I2S_RATES,
- .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE,
+ .rates = SUNXI_I2S_RATES_MASTER,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE,
},
.capture = {
.channels_min = 1,
.channels_max = 2,
- .rates = SUNXI_I2S_RATES,
- .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE,
+ .rates = SUNXI_I2S_RATES_MASTER,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE,
},
.symmetric_rates = 1,
.ops = &sunxi_iis_dai_ops,
@@ -579,42 +730,65 @@ static int __devinit sunxi_i2s_dev_probe(struct platform_device *pdev)
{
int reg_val = 0;
int ret;
+ printk("[I2S-0] Entered %s\n", __func__);
sunxi_iis.regs = ioremap(SUNXI_IISBASE, 0x100);
if (sunxi_iis.regs == NULL)
return -ENXIO;
//i2s apbclk
- i2s_apbclk = clk_get(NULL, "apb_i2s");
+ i2s_apbclk = clk_get(NULL,
+#if defined CONFIG_ARCH_SUN7I
+ "apb_i2s0"
+#else
+ "apb_i2s"
+#endif
+ );
+
if(-1 == clk_enable(i2s_apbclk)){
- printk("i2s_apbclk failed! line = %d\n", __LINE__);
+ pr_err("[I2S-0] i2s_apbclk failed! line = %d\n", __LINE__);
goto out;
}
- i2s_pllx8 = clk_get(NULL, "audio_pllx8");
-
- //i2s pll2clk
- i2s_pll2clk = clk_get(NULL, "audio_pll");
-
- //i2s module clk
- i2s_moduleclk = clk_get(NULL, "i2s");
+ if(!sunxi_iis.slave) {
+
+ i2s_pllx8 = clk_get(NULL, "audio_pllx8");
+ //i2s pll2clk
+ i2s_pll2clk = clk_get(NULL, "audio_pll");
+ //i2s module clk
+ i2s_moduleclk = clk_get(NULL,
+#if defined CONFIG_ARCH_SUN7I
+ "i2s0"
+#else
+ "i2s"
+#endif
+ );
- if(clk_set_parent(i2s_moduleclk, i2s_pll2clk)){
- printk("try to set parent of i2s_moduleclk to i2s_pll2ck failed! line = %d\n",__LINE__);
- goto out1;
- }
+ if(clk_set_parent(i2s_moduleclk, i2s_pll2clk)){
+ pr_err("[I2S-0] try to set parent of i2s_moduleclk to i2s_pll2ck failed! line = %d\n",__LINE__);
+ goto out1;
+ }
- if(clk_set_rate(i2s_moduleclk, 24576000/8)){
- printk("set i2s_moduleclk clock freq to 24576000 failed! line = %d\n", __LINE__);
- goto out1;
- }
+ if(clk_set_rate(i2s_moduleclk, 24576000/8)){
+ pr_err("[I2S-0] set i2s_moduleclk clock freq to 24576000 failed! line = %d\n", __LINE__);
+ goto out1;
+ }
- if(-1 == clk_enable(i2s_moduleclk)){
- printk("open i2s_moduleclk failed! line = %d\n", __LINE__);
- goto out1;
- }
+ if(-1 == clk_enable(i2s_moduleclk)){
+ pr_err("[I2S-0] open i2s_moduleclk failed! line = %d\n", __LINE__);
+ goto out1;
+ }
+ } else
+ {
+ sunxi_iis_dai.playback.rates = SUNXI_I2S_RATES_SLAVE;
+ sunxi_iis_dai.capture.rates = SUNXI_I2S_RATES_SLAVE;
+ }
reg_val = readl(sunxi_iis.regs + SUNXI_IISCTL);
+ if(sunxi_iis.slave)
+ reg_val |= SUNXI_IISCTL_MS; // 1: Slave!
+ else
+ reg_val &= ~SUNXI_IISCTL_MS; // 0: Master!
reg_val |= SUNXI_IISCTL_GEN;
writel(reg_val, sunxi_iis.regs + SUNXI_IISCTL);
@@ -627,7 +801,8 @@ static int __devinit sunxi_i2s_dev_probe(struct platform_device *pdev)
goto out;
out2:
- clk_disable(i2s_moduleclk);
+ if(!sunxi_iis.slave)
+ clk_disable(i2s_moduleclk);
out1:
clk_disable(i2s_apbclk);
out:
@@ -636,17 +811,26 @@ static int __devinit sunxi_i2s_dev_probe(struct platform_device *pdev)
static int __devexit sunxi_i2s_dev_remove(struct platform_device *pdev)
{
+ int reg_val = 0;
+ printk("[I2S-0] Entered %s\n", __func__);
+
if(i2s_used) {
- i2s_used = 0;
- //release the module clock
- clk_disable(i2s_moduleclk);
+ //Global disable Digital Audio Interface
+ reg_val = readl(sunxi_iis.regs + SUNXI_IISCTL);
+ reg_val &= ~SUNXI_IISCTL_GEN;
+ writel(reg_val, sunxi_iis.regs + SUNXI_IISCTL);
- //release pllx8clk
- clk_put(i2s_pllx8);
+ i2s_used = 0;
+ if(!sunxi_iis.slave) {
+ //release the module clock
+ clk_disable(i2s_moduleclk);
- //release pll2clk
- clk_put(i2s_pll2clk);
+ //release pllx8clk
+ clk_put(i2s_pllx8);
+ //release pll2clk
+ clk_put(i2s_pll2clk);
+ }
//release apbclk
clk_put(i2s_apbclk);
@@ -674,15 +858,26 @@ static struct platform_driver sunxi_i2s_driver = {
static int __init sunxi_i2s_init(void)
{
- int err = 0;
+ int err = 0, i2s_slave = 0;
int ret;
+ printk("[I2S-0] Entered %s\n", __func__);
+
ret = script_parser_fetch("i2s_para","i2s_used", &i2s_used, sizeof(int));
if (ret) {
- printk("[I2S]sunxi_i2s_init fetch i2s using configuration failed\n");
- }
+ printk("[I2S-0] sunxi_i2s_init fetch i2s using configuration failed\n");
+ }
if (i2s_used) {
+ ret = script_parser_fetch("i2s_para","i2s_slave", &i2s_slave, sizeof(int));
+ if (ret == 0 && i2s_slave) {
+ sunxi_iis.slave = 1;
+ printk("[I2S-0] sunxi_i2s_init I2S used in slave mode\n");
+ } else {
+ sunxi_iis.slave = 0;
+ printk("[I2S-0] sunxi_i2s_init I2S used in master mode\n");
+ }
+
i2s_handle = gpio_request_ex("i2s_para", NULL);
if((err = platform_device_register(&sunxi_i2s_device)) < 0)
@@ -691,7 +886,7 @@ static int __init sunxi_i2s_init(void)
if ((err = platform_driver_register(&sunxi_i2s_driver)) < 0)
return err;
} else {
- printk("[I2S]sunxi-i2s cannot find any using configuration for controllers, return directly!\n");
+ printk("[I2S-0] sunxi-i2s cannot find any using configuration for controllers, return directly!\n");
return 0;
}
return 0;
@@ -700,6 +895,7 @@ module_init(sunxi_i2s_init);
static void __exit sunxi_i2s_exit(void)
{
+ printk("[I2S-0] Entered %s\n", __func__);
platform_driver_unregister(&sunxi_i2s_driver);
}
module_exit(sunxi_i2s_exit);
diff --git a/sound/soc/sunxi/i2s/sunxi-i2s.h b/sound/soc/sunxi/i2s/sunxi-i2s.h
index f12d6d5..ba6ac32 100644
--- a/sound/soc/sunxi/i2s/sunxi-i2s.h
+++ b/sound/soc/sunxi/i2s/sunxi-i2s.h
@@ -20,71 +20,71 @@
/* REGISTER definition */
/* IIS REGISTER */
-#define SUNXI_IISBASE (0x01C22400)
+#define SUNXI_IISBASE (0x01C22400)
-#define SUNXI_IISCTL (0x00)
+#define SUNXI_IISCTL (0x00)
#define SUNXI_IISCTL_SDO3EN (1<<11)
#define SUNXI_IISCTL_SDO2EN (1<<10)
#define SUNXI_IISCTL_SDO1EN (1<<9)
#define SUNXI_IISCTL_SDO0EN (1<<8)
- #define SUNXI_IISCTL_ASS (1<<6)
+ #define SUNXI_IISCTL_ASS (1<<6)
#define SUNXI_IISCTL_MS (1<<5)
- #define SUNXI_IISCTL_PCM (1<<4)
- #define SUNXI_IISCTL_LOOP (1<<3)
- #define SUNXI_IISCTL_TXEN (1<<2)
- #define SUNXI_IISCTL_RXEN (1<<1)
- #define SUNXI_IISCTL_GEN (1<<0)
-
-#define SUNXI_IISFAT0 (0x04)
- #define SUNXI_IISFAT0_LRCP (1<<7)
- #define SUNXI_IISFAT0_BCP (1<<6)
- #define SUNXI_IISFAT0_SR_RVD (3<<4)
- #define SUNXI_IISFAT0_SR_16BIT (0<<4)
- #define SUNXI_IISFAT0_SR_20BIT (1<<4)
- #define SUNXI_IISFAT0_SR_24BIT (2<<4)
- #define SUNXI_IISFAT0_WSS_16BCLK (0<<2)
- #define SUNXI_IISFAT0_WSS_20BCLK (1<<2)
- #define SUNXI_IISFAT0_WSS_24BCLK (2<<2)
- #define SUNXI_IISFAT0_WSS_32BCLK (3<<2)
- #define SUNXI_IISFAT0_FMT_I2S (0<<0)
- #define SUNXI_IISFAT0_FMT_LFT (1<<0)
- #define SUNXI_IISFAT0_FMT_RGT (2<<0)
- #define SUNXI_IISFAT0_FMT_RVD (3<<0)
-
-#define SUNXI_IISFAT1 (0x08)
- #define SUNXI_IISFAT1_SYNCLEN_16BCLK (0<<12)
- #define SUNXI_IISFAT1_SYNCLEN_32BCLK (1<<12)
- #define SUNXI_IISFAT1_SYNCLEN_64BCLK (2<<12)
- #define SUNXI_IISFAT1_SYNCLEN_128BCLK (3<<12)
- #define SUNXI_IISFAT1_SYNCLEN_256BCLK (4<<12)
- #define SUNXI_IISFAT1_SYNCOUTEN (1<<11)
- #define SUNXI_IISFAT1_OUTMUTE (1<<10)
- #define SUNXI_IISFAT1_MLS (1<<9)
- #define SUNXI_IISFAT1_SEXT (1<<8)
- #define SUNXI_IISFAT1_SI_1ST (0<<6)
- #define SUNXI_IISFAT1_SI_2ND (1<<6)
- #define SUNXI_IISFAT1_SI_3RD (2<<6)
- #define SUNXI_IISFAT1_SI_4TH (3<<6)
- #define SUNXI_IISFAT1_SW (1<<5)
- #define SUNXI_IISFAT1_SSYNC (1<<4)
- #define SUNXI_IISFAT1_RXPDM_16PCM (0<<2)
- #define SUNXI_IISFAT1_RXPDM_8PCM (1<<2)
- #define SUNXI_IISFAT1_RXPDM_8ULAW (2<<2)
- #define SUNXI_IISFAT1_RXPDM_8ALAW (3<<2)
- #define SUNXI_IISFAT1_TXPDM_16PCM (0<<0)
- #define SUNXI_IISFAT1_TXPDM_8PCM (1<<0)
- #define SUNXI_IISFAT1_TXPDM_8ULAW (2<<0)
- #define SUNXI_IISFAT1_TXPDM_8ALAW (3<<0)
-
-#define SUNXI_IISTXFIFO (0x0C)
-
-#define SUNXI_IISRXFIFO (0x10)
-
-#define SUNXI_IISFCTL (0x14)
- #define SUNXI_IISFCTL_FIFOSRC (1<<31)
- #define SUNXI_IISFCTL_FTX (1<<25)
- #define SUNXI_IISFCTL_FRX (1<<24)
- #define SUNXI_IISFCTL_TXTL(v) ((v)<<12)
+ #define SUNXI_IISCTL_PCM (1<<4)
+ #define SUNXI_IISCTL_LOOP (1<<3)
+ #define SUNXI_IISCTL_TXEN (1<<2)
+ #define SUNXI_IISCTL_RXEN (1<<1)
+ #define SUNXI_IISCTL_GEN (1<<0)
+
+#define SUNXI_IISFAT0 (0x04)
+ #define SUNXI_IISFAT0_LRCP (1<<7)
+ #define SUNXI_IISFAT0_BCP (1<<6)
+ #define SUNXI_IISFAT0_SR_RVD (3<<4)
+ #define SUNXI_IISFAT0_SR_16BIT (0<<4)
+ #define SUNXI_IISFAT0_SR_20BIT (1<<4)
+ #define SUNXI_IISFAT0_SR_24BIT (2<<4)
+ #define SUNXI_IISFAT0_WSS_16BCLK (0<<2)
+ #define SUNXI_IISFAT0_WSS_20BCLK (1<<2)
+ #define SUNXI_IISFAT0_WSS_24BCLK (2<<2)
+ #define SUNXI_IISFAT0_WSS_32BCLK (3<<2)
+ #define SUNXI_IISFAT0_FMT_I2S (0<<0)
+ #define SUNXI_IISFAT0_FMT_LFT (1<<0)
+ #define SUNXI_IISFAT0_FMT_RGT (2<<0)
+ #define SUNXI_IISFAT0_FMT_RVD (3<<0)
+
+#define SUNXI_IISFAT1 (0x08)
+ #define SUNXI_IISFAT1_SYNCLEN_16BCLK (0<<12)
+ #define SUNXI_IISFAT1_SYNCLEN_32BCLK (1<<12)
+ #define SUNXI_IISFAT1_SYNCLEN_64BCLK (2<<12)
+ #define SUNXI_IISFAT1_SYNCLEN_128BCLK (3<<12)
+ #define SUNXI_IISFAT1_SYNCLEN_256BCLK (4<<12)
+ #define SUNXI_IISFAT1_SYNCOUTEN (1<<11)
+ #define SUNXI_IISFAT1_OUTMUTE (1<<10)
+ #define SUNXI_IISFAT1_MLS (1<<9)
+ #define SUNXI_IISFAT1_SEXT (1<<8)
+ #define SUNXI_IISFAT1_SI_1ST (0<<6)
+ #define SUNXI_IISFAT1_SI_2ND (1<<6)
+ #define SUNXI_IISFAT1_SI_3RD (2<<6)
+ #define SUNXI_IISFAT1_SI_4TH (3<<6)
+ #define SUNXI_IISFAT1_SW (1<<5)
+ #define SUNXI_IISFAT1_SSYNC (1<<4)
+ #define SUNXI_IISFAT1_RXPDM_16PCM (0<<2)
+ #define SUNXI_IISFAT1_RXPDM_8PCM (1<<2)
+ #define SUNXI_IISFAT1_RXPDM_8ULAW (2<<2)
+ #define SUNXI_IISFAT1_RXPDM_8ALAW (3<<2)
+ #define SUNXI_IISFAT1_TXPDM_16PCM (0<<0)
+ #define SUNXI_IISFAT1_TXPDM_8PCM (1<<0)
+ #define SUNXI_IISFAT1_TXPDM_8ULAW (2<<0)
+ #define SUNXI_IISFAT1_TXPDM_8ALAW (3<<0)
+
+#define SUNXI_IISTXFIFO (0x0C)
+
+#define SUNXI_IISRXFIFO (0x10)
+
+#define SUNXI_IISFCTL (0x14)
+ #define SUNXI_IISFCTL_FIFOSRC (1<<31)
+ #define SUNXI_IISFCTL_FTX (1<<25)
+ #define SUNXI_IISFCTL_FRX (1<<24)
+ #define SUNXI_IISFCTL_TXTL(v) ((v)<<12)
#define SUNXI_IISFCTL_RXTL(v) ((v)<<4)
#define SUNXI_IISFCTL_TXIM_MOD0 (0<<2)
#define SUNXI_IISFCTL_TXIM_MOD1 (1<<2)
@@ -93,174 +93,101 @@
#define SUNXI_IISFCTL_RXOM_MOD2 (2<<0)
#define SUNXI_IISFCTL_RXOM_MOD3 (3<<0)
-#define SUNXI_IISFSTA (0x18)
- #define SUNXI_IISFSTA_TXE (1<<28)
+#define SUNXI_IISFSTA (0x18)
+ #define SUNXI_IISFSTA_TXE (1<<28)
#define SUNXI_IISFSTA_TXECNT(v) ((v)<<16)
- #define SUNXI_IISFSTA_RXA (1<<8)
+ #define SUNXI_IISFSTA_RXA (1<<8)
#define SUNXI_IISFSTA_RXACNT(v) ((v)<<0)
-#define SUNXI_IISINT (0x1C)
- #define SUNXI_IISINT_TXDRQEN (1<<7)
- #define SUNXI_IISINT_TXUIEN (1<<6)
- #define SUNXI_IISINT_TXOIEN (1<<5)
- #define SUNXI_IISINT_TXEIEN (1<<4)
- #define SUNXI_IISINT_RXDRQEN (1<<2)
- #define SUNXI_IISINT_RXOIEN (1<<1)
- #define SUNXI_IISINT_RXAIEN (1<<0)
-
-#define SUNXI_IISISTA (0x20)
- #define SUNXI_IISISTA_TXUISTA (1<<6)
- #define SUNXI_IISISTA_TXOISTA (1<<5)
- #define SUNXI_IISISTA_TXEISTA (1<<4)
- #define SUNXI_IISISTA_RXOISTA (1<<1)
- #define SUNXI_IISISTA_RXAISTA (1<<0)
-
-#define SUNXI_IISCLKD (0x24)
- #define SUNXI_IISCLKD_MCLKOEN (1<<7)
+#define SUNXI_IISINT (0x1C)
+ #define SUNXI_IISINT_TXDRQEN (1<<7)
+ #define SUNXI_IISINT_TXUIEN (1<<6)
+ #define SUNXI_IISINT_TXOIEN (1<<5)
+ #define SUNXI_IISINT_TXEIEN (1<<4)
+ #define SUNXI_IISINT_RXDRQEN (1<<3)
+ #define SUNXI_IISINT_RXUIEN (1<<2)
+ #define SUNXI_IISINT_RXOIEN (1<<1)
+ #define SUNXI_IISINT_RXAIEN (1<<0)
+
+#define SUNXI_IISISTA (0x20)
+ #define SUNXI_IISISTA_TXUISTA (1<<6)
+ #define SUNXI_IISISTA_TXOISTA (1<<5)
+ #define SUNXI_IISISTA_TXEISTA (1<<4)
+ #define SUNXI_IISISTA_RXUISTA (1<<2)
+ #define SUNXI_IISISTA_RXOISTA (1<<1)
+ #define SUNXI_IISISTA_RXAISTA (1<<0)
+
+#define SUNXI_IISCLKD (0x24)
+ #define SUNXI_IISCLKD_MCLKOEN (1<<7)
#define SUNXI_IISCLKD_BCLKDIV_2 (0<<4)
#define SUNXI_IISCLKD_BCLKDIV_4 (1<<4)
#define SUNXI_IISCLKD_BCLKDIV_6 (2<<4)
#define SUNXI_IISCLKD_BCLKDIV_8 (3<<4)
- #define SUNXI_IISCLKD_BCLKDIV_12 (4<<4)
- #define SUNXI_IISCLKD_BCLKDIV_16 (5<<4)
- #define SUNXI_IISCLKD_BCLKDIV_32 (6<<4)
- #define SUNXI_IISCLKD_BCLKDIV_64 (7<<4)
+ #define SUNXI_IISCLKD_BCLKDIV_12 (4<<4)
+ #define SUNXI_IISCLKD_BCLKDIV_16 (5<<4)
+ #define SUNXI_IISCLKD_BCLKDIV_32 (6<<4)
+ #define SUNXI_IISCLKD_BCLKDIV_64 (7<<4)
#define SUNXI_IISCLKD_MCLKDIV_1 (0<<0)
#define SUNXI_IISCLKD_MCLKDIV_2 (1<<0)
#define SUNXI_IISCLKD_MCLKDIV_4 (2<<0)
#define SUNXI_IISCLKD_MCLKDIV_6 (3<<0)
#define SUNXI_IISCLKD_MCLKDIV_8 (4<<0)
- #define SUNXI_IISCLKD_MCLKDIV_12 (5<<0)
- #define SUNXI_IISCLKD_MCLKDIV_16 (6<<0)
- #define SUNXI_IISCLKD_MCLKDIV_24 (7<<0)
- #define SUNXI_IISCLKD_MCLKDIV_32 (8<<0)
- #define SUNXI_IISCLKD_MCLKDIV_48 (9<<0)
- #define SUNXI_IISCLKD_MCLKDIV_64 (10<<0)
-
-#define SUNXI_IISTXCNT (0x28)
-
-#define SUNXI_IISRXCNT (0x2C)
-
-#define SUNXI_TXCHSEL (0x30)
- #define SUNXI_TXCHSEL_CHNUM(v) (((v)-1)<<0)
-
-#define SUNXI_TXCHMAP (0x34)
- #define SUNXI_TXCHMAP_CH7(v) (((v)-1)<<28)
- #define SUNXI_TXCHMAP_CH6(v) (((v)-1)<<24)
- #define SUNXI_TXCHMAP_CH5(v) (((v)-1)<<20)
- #define SUNXI_TXCHMAP_CH4(v) (((v)-1)<<16)
- #define SUNXI_TXCHMAP_CH3(v) (((v)-1)<<12)
- #define SUNXI_TXCHMAP_CH2(v) (((v)-1)<<8)
- #define SUNXI_TXCHMAP_CH1(v) (((v)-1)<<4)
- #define SUNXI_TXCHMAP_CH0(v) (((v)-1)<<0)
-
-#define SUNXI_RXCHSEL (0x38)
- #define SUNXI_RXCHSEL_CHNUM(v) (((v)-1)<<0)
-
-#define SUNXI_RXCHMAP (0x3C)
- #define SUNXI_RXCHMAP_CH3(v) (((v)-1)<<12)
- #define SUNXI_RXCHMAP_CH2(v) (((v)-1)<<8)
- #define SUNXI_RXCHMAP_CH1(v) (((v)-1)<<4)
- #define SUNXI_RXCHMAP_CH0(v) (((v)-1)<<0)
-
-
-/* DMA REGISTER */
-#define SUNXI_DMABASE (0x01C02000)
-
-#define SUNXI_DMAIRQEN (0x0)
- #define SUNXI_DMAIRQEN_NDMA_FULLEN(v) (1<<((v)*2+1))
- #define SUNXI_DMAIRQEN_NDMA_HALFEN(v) (1<<((v)*2))
-
-#define SUNXI_DMAIRQPENDING (0x4)
- #define SUNXI_DMAIRQPENGDING_NDMA_FULLPEND(v) (1<<((v)*2+1))
- #define SUNXI_DMAIRQPENGDING_NDMA_HALFPEND(v) (1<<((v)*2))
-
-#define SUNXI_NDMACFG(v) ((v)*0x20+0x100)
- #define SUNXI_NDMACFG_DMALOAD (1<<31)
- #define SUNXI_NDMACFG_BUSY (1<<30)
- #define SUNXI_NDMACFG_CONTINUOUS (1<<29)
- #define SUNXI_NDMACFG_WAIT(v) (((v)-1)<<26) //wait clock = 2^n example: 8 clocks = 2^3
- #define SUNXI_NDMACFG_DSTDATAWIDTH_8BIT (0<<24)
- #define SUNXI_NDMACFG_DSTDATAWIDTH_16BIT (1<<24)
- #define SUNXI_NDMACFG_DSTDATAWIDTH_32BIT (2<<24)
- #define SUNXI_NDMACFG_DSTDATAWIDTH_RVD (3<<24)
- #define SUNXI_NDMACFG_DSTBURST4 (1<<23)
- #define SUNXI_NDMACFG_DSTADDRTYPE_INC (0<<21)
- #define SUNXI_NDMACFG_DSTADDRTYPE_CON (1<<21)
- #define SUNXI_NDMACFG_DSTTYPE_IRTX (0x0<<16)
- #define SUNXI_NDMACFG_DSTTYPE_SPDIFTX (0x1<<16)
- #define SUNXI_NDMACFG_DSTTYPE_IISTX (0x2<<16)
- #define SUNXI_NDMACFG_DSTTYPE_AC97TX (0x3<<16)
- #define SUNXI_NDMACFG_DSTTYPE_SPI0TX (0x4<<16)
- #define SUNXI_NDMACFG_DSTTYPE_SPI1TX (0x5<<16)
- #define SUNXI_NDMACFG_DSTTYPE_SPI2TX (0x6<<16)
- #define SUNXI_NDMACFG_DSTTYPE_UART0TX (0x8<<16)
- #define SUNXI_NDMACFG_DSTTYPE_UART1TX (0x9<<16)
- #define SUNXI_NDMACFG_DSTTYPE_UART2TX (0xA<<16)
- #define SUNXI_NDMACFG_DSTTYPE_UART3TX (0xB<<16)
- #define SUNXI_NDMACFG_DSTTYPE_AUDIODA (0xC<<16)
- #define SUNXI_NDMACFG_DSTTYPE_NFC (0xF<<16)
- #define SUNXI_NDMACFG_DSTTYPE_SRAM (0x10<<16)
- #define SUNXI_NDMACFG_DSTTYPE_DRAM (0x11<<16)
- #define SUNXI_NDMACFG_DSTTYPE_UART4TX (0x12<<16)
- #define SUNXI_NDMACFG_DSTTYPE_UART5TX (0x13<<16)
- #define SUNXI_NDMACFG_DSTTYPE_UART6TX (0x14<<16)
- #define SUNXI_NDMACFG_DSTTYPE_UART7TX (0x15<<16)
- #define SUNXI_NDMACFG_SRCDATAWIDTH_8BIT (0<<8)
- #define SUNXI_NDMACFG_SRCDATAWIDTH_16BIT (1<<8)
- #define SUNXI_NDMACFG_SRCDATAWIDTH_32BIT (2<<8)
- #define SUNXI_NDMACFG_SRCDATAWIDTH_RVD (3<<8)
- #define SUNXI_NDMACFG_SRCBURST4 (1<<7)
- #define SUNXI_NDMACFG_SRCADDRTYPE_INC (0<<5)
- #define SUNXI_NDMACFG_SRCADDRTYPE_CON (1<<5)
- #define SUNXI_NDMACFG_SRCTYPE_IRRX (0x0<<0)
- #define SUNXI_NDMACFG_SRCTYPE_SPDIFRX (0x1<<0)
- #define SUNXI_NDMACFG_SRCTYPE_IISRX (0x2<<0)
- #define SUNXI_NDMACFG_SRCTYPE_AC97RX (0x3<<0)
- #define SUNXI_NDMACFG_SRCTYPE_SPI0RX (0x4<<0)
- #define SUNXI_NDMACFG_SRCTYPE_SPI1RX (0x5<<0)
- #define SUNXI_NDMACFG_SRCTYPE_SPI2RX (0x6<<0)
- #define SUNXI_NDMACFG_SRCTYPE_UART0RX (0x8<<0)
- #define SUNXI_NDMACFG_SRCTYPE_UART1RX (0x9<<0)
- #define SUNXI_NDMACFG_SRCTYPE_UART2RX (0xA<<0)
- #define SUNXI_NDMACFG_SRCTYPE_UART3RX (0xB<<0)
- #define SUNXI_NDMACFG_SRCTYPE_AUDIOAD (0xC<<0)
- #define SUNXI_NDMACFG_SRCTYPE_TPAD (0xD<<0)
- #define SUNXI_NDMACFG_SRCTYPE_NFC (0xF<<0)
- #define SUNXI_NDMACFG_SRCTYPE_SRAM (0x10<<0)
- #define SUNXI_NDMACFG_SRCTYPE_DRAM (0x11<<0)
- #define SUNXI_NDMACFG_SRCTYPE_UART4RX (0x12<<0)
- #define SUNXI_NDMACFG_SRCTYPE_UART5RX (0x13<<0)
- #define SUNXI_NDMACFG_SRCTYPE_UART6RX (0x14<<0)
- #define SUNXI_NDMACFG_SRCTYPE_UART7RX (0x15<<0)
-
-#define SUNXI_NDMASRCADDR(v) ((v)*0x20 + 0x100 + 4)
-
-#define SUNXI_NDMADSTADDR(v) ((v)*0x20 + 0x100 + 8)
-
-#define SUNXI_NDMACNT(v) ((v)*0x20 + 0x100 + 0xC)
+ #define SUNXI_IISCLKD_MCLKDIV_12 (5<<0)
+ #define SUNXI_IISCLKD_MCLKDIV_16 (6<<0)
+ #define SUNXI_IISCLKD_MCLKDIV_24 (7<<0)
+ #define SUNXI_IISCLKD_MCLKDIV_32 (8<<0)
+ #define SUNXI_IISCLKD_MCLKDIV_48 (9<<0)
+ #define SUNXI_IISCLKD_MCLKDIV_64 (10<<0)
+
+#define SUNXI_IISTXCNT (0x28)
+
+#define SUNXI_IISRXCNT (0x2C)
+
+#define SUNXI_TXCHSEL (0x30)
+ #define SUNXI_TXCHSEL_CHNUM(v) (((v)-1)<<0)
+
+#define SUNXI_TXCHMAP (0x34)
+ #define SUNXI_TXCHMAP_CH7(v) (((v)-1)<<28)
+ #define SUNXI_TXCHMAP_CH6(v) (((v)-1)<<24)
+ #define SUNXI_TXCHMAP_CH5(v) (((v)-1)<<20)
+ #define SUNXI_TXCHMAP_CH4(v) (((v)-1)<<16)
+ #define SUNXI_TXCHMAP_CH3(v) (((v)-1)<<12)
+ #define SUNXI_TXCHMAP_CH2(v) (((v)-1)<<8)
+ #define SUNXI_TXCHMAP_CH1(v) (((v)-1)<<4)
+ #define SUNXI_TXCHMAP_CH0(v) (((v)-1)<<0)
+
+#define SUNXI_RXCHSEL (0x38)
+ #define SUNXI_RXCHSEL_CHNUM(v) (((v)-1)<<0)
+
+#define SUNXI_RXCHMAP (0x3C)
+ #define SUNXI_RXCHMAP_CH3(v) (((v)-1)<<12)
+ #define SUNXI_RXCHMAP_CH2(v) (((v)-1)<<8)
+ #define SUNXI_RXCHMAP_CH1(v) (((v)-1)<<4)
+ #define SUNXI_RXCHMAP_CH0(v) (((v)-1)<<0)
+
/* CCM REGISTER */
-#define SUNXI_CCMBASE (0x01C20000)
+#define SUNXI_CCMBASE (0x01C20000)
-#define SUNXI_CCM_AUDIO_HOSC_PLL_REG (0x08)
+#define SUNXI_CCM_AUDIO_HOSC_PLL_REG (0x08)
#define SUNXI_CCM_AUDIO_HOSC_PLL_REG_AUDIOEN (1<<31)
#define SUNXI_CCM_AUDIO_HOSC_PLL_REG_FRE225792MHZ (0<<27)
#define SUNXI_CCM_AUDIO_HOSC_PLL_REG_FRE24576MHZ (1<<27)
-#define SUNXI_CCM_APB_GATE_REG (0x68)
- #define SUNXI_CCM_APB_GATE_REG_IISGATE (1<<3)
+#define SUNXI_CCM_APB_GATE_REG (0x68)
+ #define SUNXI_CCM_APB_GATE_REG_IISGATE (1<<3)
-#define SUNXI_CCM_AUDIO_CLK_REG (0xb8)
+#define SUNXI_CCM_AUDIO_CLK_REG (0xb8)
#define SUNXI_CCM_AUDIO_CLK_REG_IISSPECIALGATE (1<<31)
- #define SUNXI_CCM_AUDIO_CLK_REG_DIV(v) ((v)<<16)
+ #define SUNXI_CCM_AUDIO_CLK_REG_DIV(v) ((v)<<16)
/*------------------------------------------------------------*/
/*------------------------------------------------------------*/
/* Clock dividers */
-#define SUNXI_DIV_MCLK 0
-#define SUNXI_DIV_BCLK 1
+#define SUNXI_DIV_MCLK 0
+#define SUNXI_DIV_BCLK 1
+#define SUNXI_DIV_EXTCLK 2
#define SUNXI_IISCLKD_MCLK_MASK 0x0f
#define SUNXI_IISCLKD_MCLK_OFFS 0
@@ -269,36 +196,34 @@
#define SUNXI_IISCLKD_MCLKEN_OFFS 7
unsigned int sunxi_i2s_get_clockrate(void);
-extern struct sunxi_i2s_info sunxi_i2s;
-//extern struct snd_soc_dai sunxi_iis_dai;
extern void sunxi_snd_txctrl_i2s(struct snd_pcm_substream *substream, int on);
-extern void sunxi_snd_rxctrl_i2s(int on);
+extern void sunxi_snd_rxctrl_i2s(struct snd_pcm_substream *substream, int on);
struct sunxi_i2s_info {
- void __iomem *regs; /* IIS BASE */
- void __iomem *ccmregs; //CCM BASE
- void __iomem *ioregs; //IO BASE
+ void __iomem *regs; //IIS BASE
+ void __iomem *ccmregs; //CCM BASE
+ void __iomem *ioregs; //IO BASE
- u32 slave; //0: master, 1: slave
- u32 mono; //0: stereo, 1: mono
- u32 samp_fs; //audio sample rate (unit in kHz)
+ u32 slave; //0: master, 1: slave
+ u32 channel_num; //
+ u32 samp_fs; //audio sample rate (unit in kHz)
u32 samp_res; //16 bits, 20 bits , 24 bits, 32 bits)
u32 samp_format; //audio sample format (0: standard I2S, 1: left-justified, 2: right-justified, 3: pcm)
- u32 ws_size; //16 BCLK, 20 BCLK, 24 BCLK, 32 BCLK)
+ u32 ws_size; //16 BCLK, 20 BCLK, 24 BCLK, 32 BCLK)
u32 mclk_rate; //mclk frequency divide by fs (128fs, 192fs, 256fs, 384fs, 512fs, 768fs)
- u32 lrc_pol; //LRC clock polarity (0: normal ,1: inverted)
+ u32 lrc_pol; //LRC clock polarity (0: normal ,1: inverted)
u32 bclk_pol; //BCLK polarity (0: normal, 1: inverted)
- u32 pcm_txtype; //PCM transmitter type (0: 16-bits linear mode, 1: 8-bits linear mode, 2: u-law, 3: A-law)
- u32 pcm_rxtype; //PCM receiver type (0: 16-bits linear mode, 1: 8-bits linear mode, 2: u-law, 3: A-law)
- u32 pcm_sw; //PCM slot width (8: 8 bits, 16: 16 bits)
- u32 pcm_sync_period;//PCM sync period (16/32/64/128/256)
- u32 pcm_sync_type; //PCM sync symbol size (0: short sync, 1: long sync)
- u32 pcm_start_slot;//PCM start slot index (1--4)
- u32 pcm_lsb_first; //0: MSB first, 1: LSB first
- u32 pcm_ch_num; //PCM channel number (1: one channel, 2: two channel)
+ u32 pcm_txtype; //PCM transmitter type (0: 16-bits linear mode, 1: 8-bits linear mode, 2: u-law, 3: A-law)
+ u32 pcm_rxtype; //PCM receiver type (0: 16-bits linear mode, 1: 8-bits linear mode, 2: u-law, 3: A-law)
+ u32 pcm_sw; //PCM slot width (8: 8 bits, 16: 16 bits)
+ u32 pcm_sync_period; //PCM sync period (16/32/64/128/256)
+ u32 pcm_sync_type; //PCM sync symbol size (0: short sync, 1: long sync)
+ u32 pcm_start_slot; //PCM start slot index (1--4)
+ u32 pcm_lsb_first; //0: MSB first, 1: LSB first
+ u32 pcm_ch_num; //PCM channel number (1: one channel, 2: two channel)
};
-extern struct sunxi_i2s_info sunxi_i2s;
+//extern struct sunxi_i2s_info sunxi_iis;
#endif
diff --git a/sound/soc/sunxi/i2s/sunxi-i2sdma.c b/sound/soc/sunxi/i2s/sunxi-i2sdma.c
index 488ef4d..ad50f52 100644
--- a/sound/soc/sunxi/i2s/sunxi-i2sdma.c
+++ b/sound/soc/sunxi/i2s/sunxi-i2sdma.c
@@ -32,17 +32,32 @@
#include "sunxi-i2s.h"
#include "sunxi-i2sdma.h"
-static volatile unsigned int dmasrc = 0;
-static volatile unsigned int dmadst = 0;
+static const struct snd_pcm_hardware sunxi_pcm_out_hardware = {
+ .info = SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
+ SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
+ SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE,
+ .rates = SNDRV_PCM_RATE_8000_384000 | SNDRV_PCM_RATE_KNOT,
+ .rate_min = 8000,
+ .rate_max = 384000,
+ .channels_min = 1,
+ .channels_max = 2,
+ .buffer_bytes_max = 128*1024, /* value must be (2^n)Kbyte size */
+ .period_bytes_min = 1024*4,//1024*4,
+ .period_bytes_max = 1024*32,//1024*32,
+ .periods_min = 4,//4,
+ .periods_max = 8,//8,
+ .fifo_size = 128,
+};
-static const struct snd_pcm_hardware sunxi_pcm_hardware = {
+static const struct snd_pcm_hardware sunxi_pcm_in_hardware = {
.info = SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME,
- .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE,
- .rates = SNDRV_PCM_RATE_8000_192000 | SNDRV_PCM_RATE_KNOT,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE,
+ .rates = SNDRV_PCM_RATE_8000_384000 | SNDRV_PCM_RATE_KNOT,
.rate_min = 8000,
- .rate_max = 192000,
+ .rate_max = 384000,
.channels_min = 1,
.channels_max = 2,
.buffer_bytes_max = 128*1024, /* value must be (2^n)Kbyte size */
@@ -50,7 +65,7 @@ static const struct snd_pcm_hardware sunxi_pcm_hardware = {
.period_bytes_max = 1024*32,//1024*32,
.periods_min = 4,//4,
.periods_max = 8,//8,
- .fifo_size = 128,//32,
+ .fifo_size = 64,
};
struct sunxi_runtime_data {
@@ -63,32 +78,32 @@ struct sunxi_runtime_data {
dma_addr_t dma_pos;
dma_addr_t dma_end;
struct sunxi_dma_params *params;
+ /*DMA data width*/
+ unsigned int dma_width;
};
static void sunxi_pcm_enqueue(struct snd_pcm_substream *substream)
{
+ int ret = 0;
struct sunxi_runtime_data *prtd = substream->runtime->private_data;
dma_addr_t pos = prtd->dma_pos;
- unsigned int limit;
- int ret;
-
unsigned long len = prtd->dma_period;
- limit = prtd->dma_limit;
- while(prtd->dma_loaded < limit) {
- if((pos + len) > prtd->dma_end) {
+ unsigned int limit = prtd->dma_limit;
+ int read = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0 : 1;
+
+ while(prtd->dma_loaded < limit){
+ if((pos + len) > prtd->dma_end){
len = prtd->dma_end - pos;
}
-
- ret = sunxi_dma_enqueue(prtd->params, pos, len, 0);
- if(ret == 0) {
+ ret = sunxi_dma_enqueue(prtd->params, pos, len, read);
+ if(ret == 0){
prtd->dma_loaded++;
pos += prtd->dma_period;
if(pos >= prtd->dma_end)
pos = prtd->dma_start;
- }else {
+ }else{
break;
}
-
}
prtd->dma_pos = pos;
}
@@ -125,17 +140,32 @@ static int sunxi_pcm_hw_params(struct snd_pcm_substream *substream,
if (!dma)
return 0;
+ prtd->dma_width = 16;
+ /* set DMA width for using in sunxi_pcm_prepare*/
+ switch(params_format(params)) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ prtd->dma_width = 16;
+ break;
+ case SNDRV_PCM_FORMAT_S20_3LE:
+ prtd->dma_width = 32;
+ break;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ prtd->dma_width = 32;
+ break;
+ }
if (prtd->params == NULL) {
prtd->params = dma;
ret = sunxi_dma_request(prtd->params, 0);
if (ret < 0) {
- return ret;
+ printk("[IIS-0] sunxi_dma_request failed! ret == %d\n", ret);
+ return ret;
}
}
if (sunxi_dma_set_callback(prtd->params, sunxi_audio_buffdone,
substream) != 0) {
sunxi_dma_release(prtd->params);
+ printk("[IIS-0] sunxi_dma_set_callback failed! ret == %d\n", ret);
prtd->params = NULL;
return -EINVAL;
}
@@ -151,6 +181,7 @@ static int sunxi_pcm_hw_params(struct snd_pcm_substream *substream,
prtd->dma_start = runtime->dma_addr;
prtd->dma_pos = prtd->dma_start;
prtd->dma_end = prtd->dma_start + totbytes;
+
spin_unlock_irq(&prtd->lock);
return 0;
}
@@ -196,16 +227,54 @@ static int sunxi_pcm_prepare(struct snd_pcm_substream *substream)
#else
dma_config_t codec_dma_conf;
memset(&codec_dma_conf, 0, sizeof(codec_dma_conf));
- codec_dma_conf.xfer_type.src_data_width = DATA_WIDTH_16BIT;
- codec_dma_conf.xfer_type.src_bst_len = DATA_BRST_1;
- codec_dma_conf.xfer_type.dst_data_width = DATA_WIDTH_16BIT;
- codec_dma_conf.xfer_type.dst_bst_len = DATA_BRST_1;
+
+ printk("[IIS-0] sunxi_pcm_prepare: playback DMA data width=(%d)\n", prtd->dma_width);
+ if(prtd->dma_width > 16)
+ {
+ codec_dma_conf.xfer_type.src_data_width = DATA_WIDTH_32BIT;
+ codec_dma_conf.xfer_type.dst_data_width = DATA_WIDTH_32BIT;
+ }
+ else
+ {
+ codec_dma_conf.xfer_type.src_data_width = DATA_WIDTH_16BIT;
+ codec_dma_conf.xfer_type.dst_data_width = DATA_WIDTH_16BIT;
+ }
+ codec_dma_conf.xfer_type.src_bst_len = DATA_BRST_4;
+ codec_dma_conf.xfer_type.dst_bst_len = DATA_BRST_4;
codec_dma_conf.address_type.src_addr_mode = NDMA_ADDR_INCREMENT;
codec_dma_conf.address_type.dst_addr_mode = NDMA_ADDR_NOCHANGE;
codec_dma_conf.src_drq_type = N_SRC_SDRAM;
codec_dma_conf.dst_drq_type = N_DST_IIS0_TX;
codec_dma_conf.bconti_mode = false;
- codec_dma_conf.irq_spt = CHAN_IRQ_FD;
+ codec_dma_conf.irq_spt = CHAN_IRQ_FD; //buf full done irq
+#endif
+ ret = sunxi_dma_config(prtd->params, &codec_dma_conf, 0);
+ }
+ else {
+#if defined CONFIG_ARCH_SUN4I || defined CONFIG_ARCH_SUN5I
+#else
+ dma_config_t codec_dma_conf;
+ memset(&codec_dma_conf, 0, sizeof(codec_dma_conf));
+
+ printk("[IIS-0] sunxi_pcm_prepare: capture DMA data width=(%d)\n", prtd->dma_width);
+ if(prtd->dma_width > 16)
+ {
+ codec_dma_conf.xfer_type.src_data_width = DATA_WIDTH_32BIT;
+ codec_dma_conf.xfer_type.dst_data_width = DATA_WIDTH_32BIT;
+ }
+ else
+ {
+ codec_dma_conf.xfer_type.src_data_width = DATA_WIDTH_16BIT;
+ codec_dma_conf.xfer_type.dst_data_width = DATA_WIDTH_16BIT;
+ }
+ codec_dma_conf.xfer_type.src_bst_len = DATA_BRST_4;
+ codec_dma_conf.xfer_type.dst_bst_len = DATA_BRST_4;
+ codec_dma_conf.address_type.src_addr_mode = NDMA_ADDR_NOCHANGE;
+ codec_dma_conf.address_type.dst_addr_mode = NDMA_ADDR_INCREMENT;
+ codec_dma_conf.src_drq_type = N_SRC_IIS0_RX;
+ codec_dma_conf.dst_drq_type = N_DST_SDRAM;
+ codec_dma_conf.bconti_mode = false;
+ codec_dma_conf.irq_spt = CHAN_IRQ_FD; //buf full done irq
#endif
ret = sunxi_dma_config(prtd->params, &codec_dma_conf, 0);
}
@@ -231,15 +300,16 @@ static int sunxi_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
- printk("[IIS] dma trigger start\n");
- printk("[IIS] 0x01c22400+0x24 = %#x, line= %d\n", readl(0xf1c22400+0x24), __LINE__);
+ printk("[IIS-0] dma trigger start\n");
+ prtd->state |= ST_RUNNING;
sunxi_dma_start(prtd->params);
break;
case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
- printk("[IIS] dma trigger stop\n");
+ printk("[IIS-0] dma trigger stop\n");
+ prtd->state &= ~ST_RUNNING;
sunxi_dma_stop(prtd->params);
break;
@@ -258,31 +328,42 @@ static snd_pcm_uframes_t sunxi_pcm_pointer(struct snd_pcm_substream *substream)
struct sunxi_runtime_data *prtd = runtime->private_data;
unsigned long res = 0;
snd_pcm_uframes_t offset = 0;
+ unsigned int dmasrc = 0;
+ unsigned int dmadst = 0;
spin_lock(&prtd->lock);
sunxi_dma_getcurposition(prtd->params,
- (dma_addr_t*)&dmasrc, (dma_addr_t*)&dmadst);
+ (dma_addr_t*)&dmasrc, (dma_addr_t*)&dmadst);
- if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
- res = dmadst - prtd->dma_start;
- else
- {
- offset = bytes_to_frames(runtime, dmasrc + prtd->dma_period - runtime->dma_addr);
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ res = dmasrc + prtd->dma_period - prtd->dma_start;
+ }
+ else {
+ res = dmadst + prtd->dma_period - prtd->dma_start;
+ //res = dmadst - prtd->dma_start;
}
+ offset = bytes_to_frames(runtime, res);
spin_unlock(&prtd->lock);
if(offset >= runtime->buffer_size)
offset = 0;
- return offset;
+
+ return offset;
}
+
static int sunxi_pcm_open(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct sunxi_runtime_data *prtd;
snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
- snd_soc_set_runtime_hwparams(substream, &sunxi_pcm_hardware);
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ snd_soc_set_runtime_hwparams(substream, &sunxi_pcm_out_hardware);
+ }
+ else {
+ snd_soc_set_runtime_hwparams(substream, &sunxi_pcm_in_hardware);
+ }
prtd = kzalloc(sizeof(struct sunxi_runtime_data), GFP_KERNEL);
if (prtd == NULL)
@@ -331,13 +412,19 @@ static int sunxi_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
{
struct snd_pcm_substream *substream = pcm->streams[stream].substream;
struct snd_dma_buffer *buf = &substream->dma_buffer;
- size_t size = sunxi_pcm_hardware.buffer_bytes_max;
-
+ size_t size = 0;
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ size = sunxi_pcm_out_hardware.buffer_bytes_max;
+ }
+ else {
+ size = sunxi_pcm_in_hardware.buffer_bytes_max;
+ }
buf->dev.type = SNDRV_DMA_TYPE_DEV;
buf->dev.dev = pcm->card->dev;
buf->private_data = NULL;
buf->area = dma_alloc_writecombine(pcm->card->dev, size,
&buf->addr, GFP_KERNEL);
+
if (!buf->area)
return -ENOMEM;
buf->bytes = size;
diff --git a/sound/soc/sunxi/i2s/sunxi-i2sdma.h b/sound/soc/sunxi/i2s/sunxi-i2sdma.h
index 50418a58..8f0b029 100644
--- a/sound/soc/sunxi/i2s/sunxi-i2sdma.h
+++ b/sound/soc/sunxi/i2s/sunxi-i2sdma.h
@@ -29,7 +29,7 @@ enum sunxi_dma_buffresult {
};
/* platform data */
-extern struct snd_soc_platform sunxi_soc_platform_i2s;
-extern struct sunxi_i2s_info sunxi_iis;
+//extern struct snd_soc_platform sunxi_soc_platform_i2s;
+//extern struct sunxi_i2s_info sunxi_iis;
#endif //SUNXI_PCM_H_
diff --git a/sound/soc/sunxi/i2s/sunxi-sndi2s.c b/sound/soc/sunxi/i2s/sunxi-sndi2s.c
index 7c1a3d4b..ab10c86 100644
--- a/sound/soc/sunxi/i2s/sunxi-sndi2s.c
+++ b/sound/soc/sunxi/i2s/sunxi-sndi2s.c
@@ -29,9 +29,8 @@
#include "sndi2s.h"
-static struct clk *xtal;
-static int clk_users;
-static DEFINE_MUTEX(clk_lock);
+/* slave mode flag*/
+static int sunxi_i2s_slave = 0;
#ifdef ENFORCE_RATES
static struct snd_pcm_hw_constraint_list hw_constraints_rates = {
@@ -45,7 +44,7 @@ static int sunxi_sndi2s_startup(struct snd_pcm_substream *substream)
{
int ret = 0;
#ifdef ENFORCE_RATES
- struct snd_pcm_runtime *runtime = substream->runtime;;
+ struct snd_pcm_runtime *runtime = substream->runtime;
#endif
if (!ret) {
@@ -62,14 +61,6 @@ static int sunxi_sndi2s_startup(struct snd_pcm_substream *substream)
static void sunxi_sndi2s_shutdown(struct snd_pcm_substream *substream)
{
- mutex_lock(&clk_lock);
- clk_users -= 1;
- if (clk_users == 0) {
- clk_put(xtal);
- xtal = NULL;
-
- }
- mutex_unlock(&clk_lock);
}
typedef struct __MCLK_SET_INF
@@ -91,6 +82,14 @@ typedef struct __BCLK_SET_INF
} __bclk_set_inf;
+typedef struct __EXTCLK_SET_INF
+{
+ __u32 samp_rate; // sample rate
+ __u16 clk_div; // masterclock division
+ __u16 mpll; // select mpll, 0 - 24.576 Mhz, 1 - 22.5792 Mhz
+
+} __extclk_set_inf;
+
static __bclk_set_inf BCLK_INF[] =
{
@@ -164,7 +163,50 @@ static __mclk_set_inf MCLK_INF[] =
{0xffffffff, 0, 0, 0},
};
-static s32 get_clock_divder(u32 sample_rate, u32 sample_width, u32 * mclk_div, u32* mpll, u32* bclk_div, u32* mult_fs)
+static __extclk_set_inf EXTCLK_INF[] =
+{
+ //44.1k bitrate
+ { 44100, 512, 1},
+ //48k bitrate
+ { 48000, 512, 0},
+ //88.2k bitrate
+ { 88200, 256, 1},
+ //96k bitrate
+ { 96000, 256, 0},
+ //176.4k bitrate
+ { 176400, 128, 1},
+ //192k bitrate
+ { 192000, 128, 0},
+
+ //352.8k bitrate
+ { 352800, 64, 1},
+ //384 bitrate
+ { 384000, 64, 0},
+
+ //end flag 0xffffffff
+ {0xffffffff, 0, 0}
+};
+
+
+static s32 get_clock_divder_slave(u32 sample_rate, u32 sample_width, u32* bclk_div, u32* mpll, u32* mult_fs)
+{
+ u32 i, ret = -EINVAL;
+
+ for(i=0; i< 100; i++) {
+ if(EXTCLK_INF[i].samp_rate == sample_rate) {
+ //set mpll and bclk division
+ *mpll = EXTCLK_INF[i].mpll;
+ *bclk_div = EXTCLK_INF[i].clk_div;
+ ret = 0;
+ break;
+ }
+ else if(EXTCLK_INF[i].samp_rate == 0xffffffff)
+ break;
+ }
+ return ret;
+}
+
+static s32 get_clock_divder_master(u32 sample_rate, u32 sample_width, u32 * mclk_div, u32* mpll, u32* bclk_div, u32* mult_fs)
{
u32 i, j, ret = -EINVAL;
@@ -201,34 +243,56 @@ static int sunxi_sndi2s_hw_params(struct snd_pcm_substream *substream,
unsigned long rate = params_rate(params);
u32 mclk_div=0, mpll=0, bclk_div=0, mult_fs=0;
- get_clock_divder(rate, 32, &mclk_div, &mpll, &bclk_div, &mult_fs);
+ if(!sunxi_i2s_slave) {
+ get_clock_divder_master(rate, /*fixed sample width*/32, &mclk_div, &mpll, &bclk_div, &mult_fs);
+ printk("[IIS-0] get_clock_divder_master: rate=(%lu), mclk_div=(%d), mpll=(%d), bclk_div=(%d), mult_fs=(%d)\n",
+ rate, mclk_div, mpll, bclk_div, mult_fs);
+ } else {
+ get_clock_divder_slave(rate, /*fixed sample width*/32, &bclk_div, &mpll, &mult_fs);
+ printk("[IIS-0] get_clock_divder_slave: rate=(%lu), bclk_div=(%d), mpll=(%d), mult_fs=(%d)\n",
+ rate, bclk_div, mpll, mult_fs);
+ }
+ //call sunxi_iis_set_fmt
ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
- SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
+ SND_SOC_DAIFMT_NB_NF/* | SND_SOC_DAIFMT_CBM_CFM*/);
if (ret < 0)
return ret;
+ //call sunxi_iis_set_fmt
ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
- SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
+ SND_SOC_DAIFMT_NB_NF/* | SND_SOC_DAIFMT_CBM_CFM*/);
if (ret < 0)
return ret;
+ //call sunxi_iis_set_sysclk
ret = snd_soc_dai_set_sysclk(cpu_dai, 0 , mpll, 0);
if (ret < 0)
return ret;
+ //call sndi2s_set_dai_sysclk
ret = snd_soc_dai_set_sysclk(codec_dai, 0 , mpll, 0);
if (ret < 0)
return ret;
- ret = snd_soc_dai_set_clkdiv(cpu_dai, SUNXI_DIV_MCLK, mclk_div);
- if (ret < 0)
- return ret;
+ if(!sunxi_i2s_slave) {
+ //call sunxi_iis_set_clkdiv
+ ret = snd_soc_dai_set_clkdiv(cpu_dai, SUNXI_DIV_MCLK, mclk_div);
+ if (ret < 0)
+ return ret;
- ret = snd_soc_dai_set_clkdiv(cpu_dai, SUNXI_DIV_BCLK, bclk_div);
- if (ret < 0)
- return ret;
+ //call sunxi_iis_set_clkdiv
+ ret = snd_soc_dai_set_clkdiv(cpu_dai, SUNXI_DIV_BCLK, bclk_div);
+ if (ret < 0)
+ return ret;
+ } else {
+ //call sunxi_iis_set_clkdiv
+ ret = snd_soc_dai_set_clkdiv(cpu_dai, SUNXI_DIV_EXTCLK, bclk_div);
+ if (ret < 0)
+ return ret;
+ }
+ //call sndi2s_set_dai_clkdiv
ret = snd_soc_dai_set_clkdiv(codec_dai, 0, mult_fs);
if (ret < 0)
return ret;
@@ -243,7 +307,7 @@ static struct snd_soc_ops sunxi_sndi2s_ops = {
};
static struct snd_soc_dai_link sunxi_sndi2s_dai_link = {
- .name = "I2S",
+ .name = "I2S",
.stream_name = "SUNXI-I2S",
.cpu_dai_name = "sunxi-i2s.0",
.codec_dai_name = "sndi2s",
@@ -286,12 +350,26 @@ static struct platform_driver sunxi_sndi2s_driver = {
static int __init sunxi_sndi2s_init(void)
{
- int ret, i2s_used = 0;
+ int ret, i2s_used = 0, i2s_slave = 0;
+
+ printk("[I2S-0] Entered %s\n", __func__);
ret = script_parser_fetch("i2s_para", "i2s_used", &i2s_used, 1);
if (ret != 0 || !i2s_used)
return -ENODEV;
+ script_parser_fetch("i2s_para","i2s_slave", &i2s_slave, sizeof(int));
+ if (i2s_slave)
+ {
+ sunxi_i2s_slave = 1;
+ printk("[I2S-0] sunxi_sndi2s_init I2S used in slave mode\n");
+ }
+ else
+ {
+ sunxi_i2s_slave = 0;
+ printk("[I2S-0] sunxi_sndi2s_init I2S used in master mode\n");
+ }
+
ret = platform_device_register(&sunxi_sndi2s_device);
if (ret < 0)
return ret;
diff --git a/sound/soc/sunxi/i2s/sunxi-sndi2s.h b/sound/soc/sunxi/i2s/sunxi-sndi2s.h
index 47f0961..89cc71a 100644
--- a/sound/soc/sunxi/i2s/sunxi-sndi2s.h
+++ b/sound/soc/sunxi/i2s/sunxi-sndi2s.h
@@ -14,7 +14,7 @@
*/
#ifndef SUNXI_SNDI2S_H_
#define SUNXI_SNDI2S_H_
-
+/* cleaning code
struct sunxi_sndi2s_platform_data {
int iis_bclk;
int iis_ws;
@@ -22,4 +22,5 @@ struct sunxi_sndi2s_platform_data {
void (*power)(int);
int model;
}
+*/
#endif
diff --git a/sound/soc/sunxi/spdif/sndspdif.c b/sound/soc/sunxi/spdif/sndspdif.c
index 73e4a95..667e5bb 100644
--- a/sound/soc/sunxi/spdif/sndspdif.c
+++ b/sound/soc/sunxi/spdif/sndspdif.c
@@ -26,7 +26,7 @@
#include "sndspdif.h"
#define SNDSPDIF_RATES (SNDRV_PCM_RATE_8000_192000|SNDRV_PCM_RATE_KNOT)
-#define SNDSPDIF_FORMATS (SNDRV_PCM_FMTBIT_S16_LE)
+#define SNDSPDIF_FORMATS (SNDRV_PCM_FMTBIT_S16_LE|SNDRV_PCM_FMTBIT_S20_3LE| SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
struct sndspdif_priv {
int sysclk;
@@ -94,9 +94,18 @@ struct snd_soc_dai_driver sndspdif_dai = {
.rates = SNDSPDIF_RATES,
.formats = SNDSPDIF_FORMATS,
},
+ .capture = {
+ .stream_name = "Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDSPDIF_RATES,
+ .formats = SNDSPDIF_FORMATS,
+ },
/* pcm operations */
.ops = &sndspdif_dai_ops,
+ //clear start?
.symmetric_rates = 1,
+ //clear end?
};
EXPORT_SYMBOL(sndspdif_dai);
@@ -106,7 +115,7 @@ static int sndspdif_soc_probe(struct snd_soc_codec *codec)
sndspdif = kzalloc(sizeof(struct sndspdif_priv), GFP_KERNEL);
if(sndspdif == NULL){
- printk("%s,%d\n",__func__,__LINE__);
+ pr_err("[SPDIF] try to alloc sndspdif failed %s,%d\n", __func__,__LINE__);
return -ENOMEM;
}
snd_soc_codec_set_drvdata(codec, sndspdif);
@@ -161,22 +170,27 @@ static int __init sndspdif_codec_init(void)
int ret, spdif_used = 0;
ret = script_parser_fetch("spdif_para", "spdif_used", &spdif_used, 1);
- if (ret != 0 || !spdif_used)
+ if (ret != 0 || !spdif_used) {
+ printk("[SPDIF] [spdif_para] isn't defined or spdif_used=0\n");
return -ENODEV;
+ }
spd_gpio_hdle = gpio_request_ex("spdif_para", "spdif_dout");
if (0 == spd_gpio_hdle) {
- pr_err("try to request spdif_para gpio failed\n");
+ pr_err("[SPDIF] try to request spdif_para gpio failed %s,%d\n", __func__,__LINE__);
return -1;
}
ret = platform_device_register(&sndspdif_codec_device);
- if (ret < 0)
+ if (ret < 0) {
+ pr_err("[SPDIF] try to SPDIF platform_device_register failed (ret=(%d)) failed %s,%d\n", ret, __func__,__LINE__);
return ret;
+ }
ret = platform_driver_register(&sndspdif_codec_driver);
if (ret < 0) {
platform_device_unregister(&sndspdif_codec_device);
+ pr_err("[SPDIF] try to SPDIF platform_driver_register failed (ret=(%d)) failed %s,%d\n", ret, __func__,__LINE__);
return ret;
}
diff --git a/sound/soc/sunxi/spdif/sunxi_sndspdif.c b/sound/soc/sunxi/spdif/sunxi_sndspdif.c
index 885e7ae..f088e0f 100644
--- a/sound/soc/sunxi/spdif/sunxi_sndspdif.c
+++ b/sound/soc/sunxi/spdif/sunxi_sndspdif.c
@@ -45,7 +45,7 @@ static int sunxi_sndspdif_startup(struct snd_pcm_substream *substream)
{
int ret = 0;
#ifdef ENFORCE_RATES
- struct snd_pcm_runtime *runtime = substream->runtime;;
+ struct snd_pcm_runtime *runtime = substream->runtime;
#endif
if (!ret) {
#ifdef ENFORCE_RATES
@@ -71,7 +71,7 @@ static void sunxi_sndspdif_shutdown(struct snd_pcm_substream *substream)
typedef struct __MCLK_SET_INF
{
__u32 samp_rate; // sample rate
- __u16 mult_fs; // multiply of smaple rate
+ __u16 mult_fs; // multiply of smaple rate
__u8 clk_div; // mpll division
__u8 mpll; // select mpll, 0 - 24.576 Mhz, 1 - 22.5792 Mhz
@@ -83,7 +83,7 @@ typedef struct __BCLK_SET_INF
{
__u8 bitpersamp; // bits per sample
__u8 clk_div; // clock division
- __u16 mult_fs; // multiplay of sample rate
+ __u16 mult_fs; // multiply of sample rate
} __bclk_set_inf;
@@ -218,13 +218,13 @@ static struct snd_soc_ops sunxi_sndspdif_ops = {
};
static struct snd_soc_dai_link sunxi_sndspdif_dai_link = {
- .name = "SPDIF",
+ .name = "SPDIF",
.stream_name = "SUNXI-SPDIF",
.cpu_dai_name = "sunxi-spdif.0",
.codec_dai_name = "sndspdif",
.platform_name = "sunxi-spdif-pcm-audio.0",
.codec_name = "sunxi-spdif-codec.0",
- .ops = &sunxi_sndspdif_ops,
+ .ops = &sunxi_sndspdif_ops,
};
static struct snd_soc_card snd_soc_sunxi_sndspdif = {
@@ -236,6 +236,12 @@ static struct snd_soc_card snd_soc_sunxi_sndspdif = {
static int __devinit sunxi_sndspdif_probe(struct platform_device *pdev)
{
+ int ret, spdif_used = 0;
+
+ ret = script_parser_fetch("spdif_para", "spdif_used", &spdif_used, 1);
+ if (ret != 0 || !spdif_used)
+ return -ENODEV;
+
snd_soc_sunxi_sndspdif.dev = &pdev->dev;
return snd_soc_register_card(&snd_soc_sunxi_sndspdif);
}
diff --git a/sound/soc/sunxi/spdif/sunxi_spdif.c b/sound/soc/sunxi/spdif/sunxi_spdif.c
index 88389ae..47efb02 100644
--- a/sound/soc/sunxi/spdif/sunxi_spdif.c
+++ b/sound/soc/sunxi/spdif/sunxi_spdif.c
@@ -37,7 +37,7 @@
#include "sunxi_spdma.h"
#include "sunxi_spdif.h"
-static int regsave[6];
+static int regsave[9];
static struct sunxi_dma_params sunxi_spdif_stereo_out = {
.client.name = "SPDIF out",
@@ -48,9 +48,9 @@ static struct sunxi_dma_params sunxi_spdif_stereo_out = {
};
static struct sunxi_dma_params sunxi_spdif_stereo_in = {
- .client.name = "SPDIF out",
+ .client.name = "SPDIF in",
#if defined CONFIG_ARCH_SUN4I || defined CONFIG_ARCH_SUN5I
- .channel = DMACH_NSPDIF,
+ .channel = DMACH_NSPDIF, //???
#endif
.dma_addr = SUNXI_SPDIFBASE + SUNXI_SPDIF_RXFIFO,
};
@@ -63,34 +63,33 @@ void sunxi_snd_txctrl(struct snd_pcm_substream *substream, int on)
{
u32 reg_val;
+ reg_val = readl(sunxi_spdif.regs + SUNXI_SPDIF_TXCFG);
if (substream->runtime->channels == 1) {
- reg_val = readl(sunxi_spdif.regs + SUNXI_SPDIF_TXCFG);
reg_val |= SUNXI_SPDIF_TXCFG_SINGLEMOD;
- writel(reg_val, sunxi_spdif.regs + SUNXI_SPDIF_TXCFG);
}
+ else {
+ reg_val &= ~SUNXI_SPDIF_TXCFG_SINGLEMOD;
+ }
+ reg_val |= SUNXI_SPDIF_TXCFG_ASS; //Sending the last audio (may be 0?)
+ reg_val |= SUNXI_SPDIF_TXCFG_CHSTMODE; //Channel status A&B generated form TX_CHSTA
+ writel(reg_val, sunxi_spdif.regs + SUNXI_SPDIF_TXCFG);
- //soft reset SPDIF
- writel(0x1, sunxi_spdif.regs + SUNXI_SPDIF_CTL);
-
- //MCLK OUTPUT enable
- reg_val = readl(sunxi_spdif.regs + SUNXI_SPDIF_CTL);
- reg_val |= SUNXI_SPDIF_CTL_MCLKOUTEN;
- writel(reg_val, sunxi_spdif.regs + SUNXI_SPDIF_CTL);
-
- //flush TX FIFO
+ /*flush TX FIFO and set FIFO empty trigger level*/
reg_val = readl(sunxi_spdif.regs + SUNXI_SPDIF_FCTL);
- reg_val |= SUNXI_SPDIF_FCTL_FTX;
+ reg_val |= SUNXI_SPDIF_FCTL_TXTL(0x10); //TX FIFO empty Trigger Level
+ reg_val |= SUNXI_SPDIF_FCTL_FTX; //flush TX FIFO
writel(reg_val, sunxi_spdif.regs + SUNXI_SPDIF_FCTL);
- //clear interrupt status
+ /*clear interrupt status*/
reg_val = readl(sunxi_spdif.regs + SUNXI_SPDIF_ISTA);
+ reg_val |= SUNXI_SPDIF_ISTA_TXCLR;
writel(reg_val, sunxi_spdif.regs + SUNXI_SPDIF_ISTA);
- //clear TX counter
+ /*clear TX counter*/
writel(0, sunxi_spdif.regs + SUNXI_SPDIF_TXCNT);
if (on) {
- //SPDIF TX ENBALE
+ //SPDIF TX ENABLE
reg_val = readl(sunxi_spdif.regs + SUNXI_SPDIF_TXCFG);
reg_val |= SUNXI_SPDIF_TXCFG_TXEN;
writel(reg_val, sunxi_spdif.regs + SUNXI_SPDIF_TXCFG);
@@ -99,13 +98,8 @@ void sunxi_snd_txctrl(struct snd_pcm_substream *substream, int on)
reg_val = readl(sunxi_spdif.regs + SUNXI_SPDIF_INT);
reg_val |= SUNXI_SPDIF_INT_TXDRQEN;
writel(reg_val, sunxi_spdif.regs + SUNXI_SPDIF_INT);
-
- //global enable
- reg_val = readl(sunxi_spdif.regs + SUNXI_SPDIF_CTL);
- reg_val |= SUNXI_SPDIF_CTL_GEN;
- writel(reg_val, sunxi_spdif.regs + SUNXI_SPDIF_CTL);
} else {
- //SPDIF TX DISABALE
+ //SPDIF TX DISABLE
reg_val = readl(sunxi_spdif.regs + SUNXI_SPDIF_TXCFG);
reg_val &= ~SUNXI_SPDIF_TXCFG_TXEN;
writel(reg_val, sunxi_spdif.regs + SUNXI_SPDIF_TXCFG);
@@ -114,16 +108,48 @@ void sunxi_snd_txctrl(struct snd_pcm_substream *substream, int on)
reg_val = readl(sunxi_spdif.regs + SUNXI_SPDIF_INT);
reg_val &= ~SUNXI_SPDIF_INT_TXDRQEN;
writel(reg_val, sunxi_spdif.regs + SUNXI_SPDIF_INT);
-
- //global disable
- reg_val = readl(sunxi_spdif.regs + SUNXI_SPDIF_CTL);
- reg_val &= ~SUNXI_SPDIF_CTL_GEN;
- writel(reg_val, sunxi_spdif.regs + SUNXI_SPDIF_CTL);
}
}
-void sunxi_snd_rxctrl(int on)
+void sunxi_snd_rxctrl(struct snd_pcm_substream *substream, int on)
{
+ u32 reg_val;
+
+ /*flush RX FIFO and set FIFO empty trigger level*/
+ reg_val = readl(sunxi_spdif.regs + SUNXI_SPDIF_FCTL);
+ reg_val |= SUNXI_SPDIF_FCTL_RXTL(0x0F); //RX FIFO Trigger Level
+ reg_val |= SUNXI_SPDIF_FCTL_FRX; //flush RX FIFO
+ writel(reg_val, sunxi_spdif.regs + SUNXI_SPDIF_FCTL);
+
+ /*clear interrupt status*/
+ reg_val = readl(sunxi_spdif.regs + SUNXI_SPDIF_ISTA);
+ reg_val |= SUNXI_SPDIF_ISTA_RXCLR;
+ writel(reg_val, sunxi_spdif.regs + SUNXI_SPDIF_ISTA);
+
+ /*clear RX counter*/
+ writel(0, sunxi_spdif.regs + SUNXI_SPDIF_RXCNT);
+
+ if (on) {
+ /*SPDIF RX ENABLE*/
+ reg_val = readl(sunxi_spdif.regs + SUNXI_SPDIF_RXCFG);
+ reg_val |= SUNXI_SPDIF_RXCFG_RXEN;
+ writel(reg_val, sunxi_spdif.regs + SUNXI_SPDIF_RXCFG);
+
+ /*DRQ ENABLE*/
+ reg_val = readl(sunxi_spdif.regs + SUNXI_SPDIF_INT);
+ reg_val |= SUNXI_SPDIF_INT_RXDRQEN;
+ writel(reg_val, sunxi_spdif.regs + SUNXI_SPDIF_INT);
+ } else {
+ /*SPDIF TX DISABLE*/
+ reg_val = readl(sunxi_spdif.regs + SUNXI_SPDIF_RXCFG);
+ reg_val &= ~SUNXI_SPDIF_RXCFG_RXEN;
+ writel(reg_val, sunxi_spdif.regs + SUNXI_SPDIF_RXCFG);
+
+ /*DRQ DISABLE*/
+ reg_val = readl(sunxi_spdif.regs + SUNXI_SPDIF_INT);
+ reg_val &= ~SUNXI_SPDIF_INT_RXDRQEN;
+ writel(reg_val, sunxi_spdif.regs + SUNXI_SPDIF_INT);
+ }
}
static inline int sunxi_snd_is_clkmaster(void)
@@ -135,63 +161,122 @@ static int sunxi_spdif_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
{
u32 reg_val;
- reg_val = 0;
- reg_val &= ~SUNXI_SPDIF_TXCFG_SINGLEMOD;
- reg_val |= SUNXI_SPDIF_TXCFG_ASS;
- reg_val &= ~SUNXI_SPDIF_TXCFG_NONAUDIO;
- reg_val |= SUNXI_SPDIF_TXCFG_FMT16BIT;
- reg_val |= SUNXI_SPDIF_TXCFG_CHSTMODE;
- writel(reg_val, sunxi_spdif.regs + SUNXI_SPDIF_TXCFG);
-
- reg_val = 0;
- reg_val &= ~SUNXI_SPDIF_FCTL_FIFOSRC;
- reg_val |= SUNXI_SPDIF_FCTL_TXTL(16);
- reg_val |= SUNXI_SPDIF_FCTL_RXTL(15);
- reg_val |= SUNXI_SPDIF_FCTL_TXIM(1);
- reg_val |= SUNXI_SPDIF_FCTL_RXOM(3);
- writel(reg_val, sunxi_spdif.regs + SUNXI_SPDIF_FCTL);
-
if (!fmt) {//PCM
- reg_val = 0;
+ reg_val = readl(sunxi_spdif.regs + SUNXI_SPDIF_TXCFG);
+ reg_val &= ~SUNXI_SPDIF_TXCFG_NONAUDIO;
+ writel(reg_val, sunxi_spdif.regs + SUNXI_SPDIF_TXCFG);
+
+ reg_val = readl(sunxi_spdif.regs + SUNXI_SPDIF_TXCHSTA0);
reg_val |= (SUNXI_SPDIF_TXCHSTA0_CHNUM(2));
+ reg_val &= ~SUNXI_SPDIF_TXCHSTA0_AUDIO;
writel(reg_val, sunxi_spdif.regs + SUNXI_SPDIF_TXCHSTA0);
- reg_val = 0;
- reg_val |= (SUNXI_SPDIF_TXCHSTA1_SAMWORDLEN(1));
- writel(reg_val, sunxi_spdif.regs + SUNXI_SPDIF_TXCHSTA1);
+ reg_val = readl(sunxi_spdif.regs + SUNXI_SPDIF_RXCHSTA0);
+ reg_val |= (SUNXI_SPDIF_RXCHSTA0_CHNUM(2));
+ reg_val &= ~SUNXI_SPDIF_RXCHSTA0_AUDIO;
+ writel(reg_val, sunxi_spdif.regs + SUNXI_SPDIF_RXCHSTA0);
} else { //non PCM
reg_val = readl(sunxi_spdif.regs + SUNXI_SPDIF_TXCFG);
reg_val |= SUNXI_SPDIF_TXCFG_NONAUDIO;
writel(reg_val, sunxi_spdif.regs + SUNXI_SPDIF_TXCFG);
- reg_val = 0;
+ reg_val = readl(sunxi_spdif.regs + SUNXI_SPDIF_TXCHSTA0);
reg_val |= (SUNXI_SPDIF_TXCHSTA0_CHNUM(2));
reg_val |= SUNXI_SPDIF_TXCHSTA0_AUDIO;
writel(reg_val, sunxi_spdif.regs + SUNXI_SPDIF_TXCHSTA0);
- reg_val = 0;
- reg_val |= (SUNXI_SPDIF_TXCHSTA1_SAMWORDLEN(1));
- writel(reg_val, sunxi_spdif.regs + SUNXI_SPDIF_TXCHSTA1);
+ reg_val = readl(sunxi_spdif.regs + SUNXI_SPDIF_RXCHSTA0);
+ reg_val |= (SUNXI_SPDIF_RXCHSTA0_CHNUM(2));
+ reg_val |= SUNXI_SPDIF_RXCHSTA0_AUDIO;
+ writel(reg_val, sunxi_spdif.regs + SUNXI_SPDIF_RXCHSTA0);
}
return 0;
}
static int sunxi_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 snd_soc_pcm_runtime *rtd = substream->private_data;
struct sunxi_dma_params *dma_data;
+ u32 reg_val, reg_val1;
+ int format;
+ switch (params_format(params))
+ {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ format = 16;
+ break;
+ case SNDRV_PCM_FORMAT_S20_3LE:
+ format = 20;
+ break;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ format = 24;
+ break;
+ case SNDRV_PCM_FORMAT_S32_LE:
+ format = 24;
+ break;
+ default:
+ return -EINVAL;
+ }
- /* play or record */
- if(substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ /* playback or capture */
+ if(substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
dma_data = &sunxi_spdif_stereo_out;
- else
+
+ reg_val1 = readl(sunxi_spdif.regs + SUNXI_SPDIF_TXCHSTA1);
+ reg_val = readl(sunxi_spdif.regs + SUNXI_SPDIF_TXCFG);
+ reg_val &= ~SUNXI_SPDIF_TXCFG_FMTRVD;
+ reg_val1 &= ~SUNXI_SPDIF_TXCHSTA1_MAXWORDLEN;
+ reg_val1 &= ~(SUNXI_SPDIF_TXCHSTA1_SAMWORDLEN(7));
+ if(format == 16) {
+ reg_val |= SUNXI_SPDIF_TXCFG_FMT16BIT;
+ reg_val1 |= (SUNXI_SPDIF_TXCHSTA1_SAMWORDLEN(1));
+ }
+ else if(format == 20) {
+ reg_val |= SUNXI_SPDIF_TXCFG_FMT20BIT;
+ reg_val1 |= SUNXI_SPDIF_TXCHSTA1_MAXWORDLEN;
+ reg_val1 |= (SUNXI_SPDIF_TXCHSTA1_SAMWORDLEN(1));
+ }
+ else {
+ reg_val |= SUNXI_SPDIF_TXCFG_FMT24BIT;
+ reg_val1 |= SUNXI_SPDIF_TXCHSTA1_MAXWORDLEN;
+ reg_val1 |= (SUNXI_SPDIF_TXCHSTA1_SAMWORDLEN(5));
+ }
+ writel(reg_val, sunxi_spdif.regs + SUNXI_SPDIF_TXCFG);
+ writel(reg_val1, sunxi_spdif.regs + SUNXI_SPDIF_TXCHSTA1);
+
+ /* Set TX FIFO Input Mode */
+ reg_val = readl(sunxi_spdif.regs + SUNXI_SPDIF_FCTL);
+ reg_val &= ~SUNXI_SPDIF_FCTL_TXIM1; //0. Valid data at the MSB of OWA_TXFIFO register
+ writel(reg_val, sunxi_spdif.regs + SUNXI_SPDIF_FCTL);
+ }
+ else {
dma_data = &sunxi_spdif_stereo_in;
+ /* Set TX FIFO Input Mode */
+ reg_val1 = readl(sunxi_spdif.regs + SUNXI_SPDIF_RXCHSTA1);
+ reg_val = readl(sunxi_spdif.regs + SUNXI_SPDIF_FCTL);
+ reg_val &= ~SUNXI_SPDIF_FCTL_RXOM3;
+ reg_val1 &= ~SUNXI_SPDIF_RXCHSTA1_MAXWORDLEN;
+ reg_val1 &= ~(SUNXI_SPDIF_RXCHSTA1_SAMWORDLEN(7));
+
+ if(format == 16) {
+ reg_val |= SUNXI_SPDIF_FCTL_RXOM3;
+ reg_val1 |= (SUNXI_SPDIF_RXCHSTA1_SAMWORDLEN(1));
+ }
+ else if(format == 20) {
+ reg_val1 |= SUNXI_SPDIF_RXCHSTA1_MAXWORDLEN;
+ reg_val1 |= (SUNXI_SPDIF_RXCHSTA1_SAMWORDLEN(1));
+ }
+ else {
+ reg_val1 |= SUNXI_SPDIF_RXCHSTA1_MAXWORDLEN;
+ reg_val1 |= (SUNXI_SPDIF_RXCHSTA1_SAMWORDLEN(5));
+ }
+ writel(reg_val, sunxi_spdif.regs + SUNXI_SPDIF_FCTL);
+ writel(reg_val1, sunxi_spdif.regs + SUNXI_SPDIF_RXCHSTA1);
+ }
snd_soc_dai_set_dma_data(rtd->cpu_dai, substream, dma_data);
-
return 0;
}
@@ -208,7 +293,7 @@ static int sunxi_spdif_trigger(struct snd_pcm_substream *substream,
case SNDRV_PCM_TRIGGER_RESUME:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
- sunxi_snd_rxctrl(1);
+ sunxi_snd_rxctrl(substream, 1);
} else {
sunxi_snd_txctrl(substream, 1);
}
@@ -218,9 +303,9 @@ static int sunxi_spdif_trigger(struct snd_pcm_substream *substream,
case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
- sunxi_snd_rxctrl(0);
+ sunxi_snd_rxctrl(substream, 0);
} else {
- sunxi_snd_txctrl(substream, 0);
+ sunxi_snd_txctrl(substream, 0);
}
break;
default:
@@ -246,23 +331,31 @@ static int sunxi_spdif_set_sysclk(struct snd_soc_dai *cpu_dai, int clk_id,
static int sunxi_spdif_set_clkdiv(struct snd_soc_dai *cpu_dai, int div_id, int div)
{
- u32 reg_val = 0;
-
- reg_val = readl(sunxi_spdif.regs + SUNXI_SPDIF_TXCHSTA0);
- reg_val &= ~(SUNXI_SPDIF_TXCHSTA0_SAMFREQ(0xf));
- writel(reg_val, sunxi_spdif.regs + SUNXI_SPDIF_TXCHSTA0);
-
- reg_val = readl(sunxi_spdif.regs + SUNXI_SPDIF_TXCHSTA1);
- reg_val &= ~(SUNXI_SPDIF_TXCHSTA1_ORISAMFREQ(0xf));
- writel(reg_val, sunxi_spdif.regs + SUNXI_SPDIF_TXCHSTA1);
+ u32 reg_val_txchsta0 = 0;
+ u32 reg_val_txchsta1 = 0;
+ u32 reg_val_rxchsta0 = 0;
+ u32 reg_val_rxchsta1 = 0;
+ u32 reg_val_txcfg = 0;
switch(div_id) {
case SUNXI_DIV_MCLK:
{
- reg_val = readl(sunxi_spdif.regs + SUNXI_SPDIF_TXCFG);
- reg_val &= ~SUNXI_SPDIF_TXCFG_TXRATIO(0x1F);
- reg_val |= SUNXI_SPDIF_TXCFG_TXRATIO(div-1);
- writel(reg_val, sunxi_spdif.regs + SUNXI_SPDIF_TXCFG);
+ reg_val_txchsta0 = readl(sunxi_spdif.regs + SUNXI_SPDIF_TXCHSTA0);
+ reg_val_txchsta0 &= ~(SUNXI_SPDIF_TXCHSTA0_SAMFREQ(0xf));
+
+ reg_val_txchsta1 = readl(sunxi_spdif.regs + SUNXI_SPDIF_TXCHSTA1);
+ reg_val_txchsta1 &= ~(SUNXI_SPDIF_TXCHSTA1_ORISAMFREQ(0xf));
+
+ reg_val_rxchsta0 = readl(sunxi_spdif.regs + SUNXI_SPDIF_RXCHSTA0);
+ reg_val_rxchsta0 &= ~(SUNXI_SPDIF_RXCHSTA0_SAMFREQ(0xf));
+
+ reg_val_rxchsta1 = readl(sunxi_spdif.regs + SUNXI_SPDIF_RXCHSTA1);
+ reg_val_rxchsta1 &= ~(SUNXI_SPDIF_RXCHSTA1_ORISAMFREQ(0xf));
+
+ reg_val_txcfg = readl(sunxi_spdif.regs + SUNXI_SPDIF_TXCFG);
+ reg_val_txcfg &= ~SUNXI_SPDIF_TXCFG_TXRATIO(0x1F);
+ reg_val_txcfg |= SUNXI_SPDIF_TXCFG_TXRATIO(div-1);
+ writel(reg_val_txcfg, sunxi_spdif.regs + SUNXI_SPDIF_TXCFG);
if(clk_get_rate(spdif_pll2clk) == 24576000)
{
@@ -270,67 +363,49 @@ static int sunxi_spdif_set_clkdiv(struct snd_soc_dai *cpu_dai, int div_id, int d
{
//24KHZ
case 8:
- reg_val = readl(sunxi_spdif.regs + SUNXI_SPDIF_TXCHSTA0);
- reg_val |= (SUNXI_SPDIF_TXCHSTA0_SAMFREQ(0x6));
- writel(reg_val, sunxi_spdif.regs + SUNXI_SPDIF_TXCHSTA0);
-
- reg_val = readl(sunxi_spdif.regs + SUNXI_SPDIF_TXCHSTA1);
- reg_val |= (SUNXI_SPDIF_TXCHSTA1_ORISAMFREQ(0x9));
- writel(reg_val, sunxi_spdif.regs + SUNXI_SPDIF_TXCHSTA1);
+ reg_val_txchsta0 |= (SUNXI_SPDIF_TXCHSTA0_SAMFREQ(0x6));
+ reg_val_txchsta1 |= (SUNXI_SPDIF_TXCHSTA1_ORISAMFREQ(0x9));
+ reg_val_rxchsta0 |= (SUNXI_SPDIF_RXCHSTA0_SAMFREQ(0x6));
+ reg_val_rxchsta1 |= (SUNXI_SPDIF_RXCHSTA1_ORISAMFREQ(0x9));
break;
//32KHZ
case 6:
- reg_val = readl(sunxi_spdif.regs + SUNXI_SPDIF_TXCHSTA0);
- reg_val |= (SUNXI_SPDIF_TXCHSTA0_SAMFREQ(0x3));
- writel(reg_val, sunxi_spdif.regs + SUNXI_SPDIF_TXCHSTA0);
-
- reg_val = readl(sunxi_spdif.regs + SUNXI_SPDIF_TXCHSTA1);
- reg_val |= (SUNXI_SPDIF_TXCHSTA1_ORISAMFREQ(0xC));
- writel(reg_val, sunxi_spdif.regs + SUNXI_SPDIF_TXCHSTA1);
+ reg_val_txchsta0 |= (SUNXI_SPDIF_TXCHSTA0_SAMFREQ(0x3));
+ reg_val_txchsta1 |= (SUNXI_SPDIF_TXCHSTA1_ORISAMFREQ(0xC));
+ reg_val_rxchsta0 |= (SUNXI_SPDIF_RXCHSTA0_SAMFREQ(0x3));
+ reg_val_rxchsta1 |= (SUNXI_SPDIF_RXCHSTA1_ORISAMFREQ(0xC));
break;
//48KHZ
case 4:
- reg_val = readl(sunxi_spdif.regs + SUNXI_SPDIF_TXCHSTA0);
- reg_val |= (SUNXI_SPDIF_TXCHSTA0_SAMFREQ(0x2));
- writel(reg_val, sunxi_spdif.regs + SUNXI_SPDIF_TXCHSTA0);
-
- reg_val = readl(sunxi_spdif.regs + SUNXI_SPDIF_TXCHSTA1);
- reg_val |= (SUNXI_SPDIF_TXCHSTA1_ORISAMFREQ(0xD));
- writel(reg_val, sunxi_spdif.regs + SUNXI_SPDIF_TXCHSTA1);
+ reg_val_txchsta0 |= (SUNXI_SPDIF_TXCHSTA0_SAMFREQ(0x2));
+ reg_val_txchsta1 |= (SUNXI_SPDIF_TXCHSTA1_ORISAMFREQ(0xD));
+ reg_val_rxchsta0 |= (SUNXI_SPDIF_RXCHSTA0_SAMFREQ(0x2));
+ reg_val_rxchsta1 |= (SUNXI_SPDIF_RXCHSTA1_ORISAMFREQ(0xD));
break;
//96KHZ
case 2:
- reg_val = readl(sunxi_spdif.regs + SUNXI_SPDIF_TXCHSTA0);
- reg_val |= (SUNXI_SPDIF_TXCHSTA0_SAMFREQ(0xA));
- writel(reg_val, sunxi_spdif.regs + SUNXI_SPDIF_TXCHSTA0);
-
- reg_val = readl(sunxi_spdif.regs + SUNXI_SPDIF_TXCHSTA1);
- reg_val |= (SUNXI_SPDIF_TXCHSTA1_ORISAMFREQ(0x5));
- writel(reg_val, sunxi_spdif.regs + SUNXI_SPDIF_TXCHSTA1);
+ reg_val_txchsta0 |= (SUNXI_SPDIF_TXCHSTA0_SAMFREQ(0xA));
+ reg_val_txchsta1 |= (SUNXI_SPDIF_TXCHSTA1_ORISAMFREQ(0x5));
+ reg_val_rxchsta0 |= (SUNXI_SPDIF_RXCHSTA0_SAMFREQ(0xA));
+ reg_val_rxchsta1 |= (SUNXI_SPDIF_RXCHSTA1_ORISAMFREQ(0x5));
break;
//192KHZ
case 1:
- reg_val = readl(sunxi_spdif.regs + SUNXI_SPDIF_TXCHSTA0);
- reg_val |= (SUNXI_SPDIF_TXCHSTA0_SAMFREQ(0xE));
- writel(reg_val, sunxi_spdif.regs + SUNXI_SPDIF_TXCHSTA0);
-
- reg_val = readl(sunxi_spdif.regs + SUNXI_SPDIF_TXCHSTA1);
- reg_val |= (SUNXI_SPDIF_TXCHSTA1_ORISAMFREQ(0x1));
- writel(reg_val, sunxi_spdif.regs + SUNXI_SPDIF_TXCHSTA1);
+ reg_val_txchsta0 |= (SUNXI_SPDIF_TXCHSTA0_SAMFREQ(0xE));
+ reg_val_txchsta1 |= (SUNXI_SPDIF_TXCHSTA1_ORISAMFREQ(0x1));
+ reg_val_rxchsta0 |= (SUNXI_SPDIF_RXCHSTA0_SAMFREQ(0xE));
+ reg_val_rxchsta1 |= (SUNXI_SPDIF_RXCHSTA1_ORISAMFREQ(0x1));
break;
default:
- reg_val = readl(sunxi_spdif.regs + SUNXI_SPDIF_TXCHSTA0);
- reg_val |= (SUNXI_SPDIF_TXCHSTA0_SAMFREQ(1));
- writel(reg_val, sunxi_spdif.regs + SUNXI_SPDIF_TXCHSTA0);
-
- reg_val = readl(sunxi_spdif.regs + SUNXI_SPDIF_TXCHSTA1);
- reg_val |= (SUNXI_SPDIF_TXCHSTA1_ORISAMFREQ(0));
- writel(reg_val, sunxi_spdif.regs + SUNXI_SPDIF_TXCHSTA1);
+ reg_val_txchsta0 |= (SUNXI_SPDIF_TXCHSTA0_SAMFREQ(1));
+ reg_val_txchsta1 |= (SUNXI_SPDIF_TXCHSTA1_ORISAMFREQ(0));
+ reg_val_rxchsta0 |= (SUNXI_SPDIF_RXCHSTA0_SAMFREQ(1));
+ reg_val_rxchsta1 |= (SUNXI_SPDIF_RXCHSTA1_ORISAMFREQ(0));
break;
}
}else{ //22.5792MHz
@@ -338,59 +413,50 @@ static int sunxi_spdif_set_clkdiv(struct snd_soc_dai *cpu_dai, int div_id, int d
{
//22.05khz
case 8:
- reg_val = readl(sunxi_spdif.regs + SUNXI_SPDIF_TXCHSTA0);
- reg_val |= (SUNXI_SPDIF_TXCHSTA0_SAMFREQ(0x4));
- writel(reg_val, sunxi_spdif.regs + SUNXI_SPDIF_TXCHSTA0);
-
- reg_val = readl(sunxi_spdif.regs + SUNXI_SPDIF_TXCHSTA1);
- reg_val |= (SUNXI_SPDIF_TXCHSTA1_ORISAMFREQ(0xb));
- writel(reg_val, sunxi_spdif.regs + SUNXI_SPDIF_TXCHSTA1);
+ reg_val_txchsta0 |= (SUNXI_SPDIF_TXCHSTA0_SAMFREQ(0x4));
+ reg_val_txchsta1 |= (SUNXI_SPDIF_TXCHSTA1_ORISAMFREQ(0xb));
+ reg_val_rxchsta0 |= (SUNXI_SPDIF_RXCHSTA0_SAMFREQ(0x4));
+ reg_val_rxchsta1 |= (SUNXI_SPDIF_RXCHSTA1_ORISAMFREQ(0xb));
break;
//44.1KHZ
case 4:
- reg_val = readl(sunxi_spdif.regs + SUNXI_SPDIF_TXCHSTA0);
- reg_val |= (SUNXI_SPDIF_TXCHSTA0_SAMFREQ(0x0));
- writel(reg_val, sunxi_spdif.regs + SUNXI_SPDIF_TXCHSTA0);
-
- reg_val = readl(sunxi_spdif.regs + SUNXI_SPDIF_TXCHSTA1);
- reg_val |= (SUNXI_SPDIF_TXCHSTA1_ORISAMFREQ(0xF));
- writel(reg_val, sunxi_spdif.regs + SUNXI_SPDIF_TXCHSTA1);
+ reg_val_txchsta0 |= (SUNXI_SPDIF_TXCHSTA0_SAMFREQ(0x0));
+ reg_val_txchsta1 |= (SUNXI_SPDIF_TXCHSTA1_ORISAMFREQ(0xF));
+ reg_val_rxchsta0 |= (SUNXI_SPDIF_RXCHSTA0_SAMFREQ(0x0));
+ reg_val_rxchsta1 |= (SUNXI_SPDIF_RXCHSTA1_ORISAMFREQ(0xF));
break;
//88.2khz
case 2:
- reg_val = readl(sunxi_spdif.regs + SUNXI_SPDIF_TXCHSTA0);
- reg_val |= (SUNXI_SPDIF_TXCHSTA0_SAMFREQ(0x8));
- writel(reg_val, sunxi_spdif.regs + SUNXI_SPDIF_TXCHSTA0);
-
- reg_val = readl(sunxi_spdif.regs + SUNXI_SPDIF_TXCHSTA1);
- reg_val |= (SUNXI_SPDIF_TXCHSTA1_ORISAMFREQ(0x7));
- writel(reg_val, sunxi_spdif.regs + SUNXI_SPDIF_TXCHSTA1);
+ reg_val_txchsta0 |= (SUNXI_SPDIF_TXCHSTA0_SAMFREQ(0x8));
+ reg_val_txchsta1 |= (SUNXI_SPDIF_TXCHSTA1_ORISAMFREQ(0x7));
+ reg_val_rxchsta0 |= (SUNXI_SPDIF_RXCHSTA0_SAMFREQ(0x8));
+ reg_val_rxchsta1 |= (SUNXI_SPDIF_RXCHSTA1_ORISAMFREQ(0x7));
break;
//176.4KHZ
case 1:
- reg_val = readl(sunxi_spdif.regs + SUNXI_SPDIF_TXCHSTA0);
- reg_val |= (SUNXI_SPDIF_TXCHSTA0_SAMFREQ(0xC));
- writel(reg_val, sunxi_spdif.regs + SUNXI_SPDIF_TXCHSTA0);
-
- reg_val = readl(sunxi_spdif.regs + SUNXI_SPDIF_TXCHSTA1);
- reg_val |= (SUNXI_SPDIF_TXCHSTA1_ORISAMFREQ(0x3));
- writel(reg_val, sunxi_spdif.regs + SUNXI_SPDIF_TXCHSTA1);
+ reg_val_txchsta0 |= (SUNXI_SPDIF_TXCHSTA0_SAMFREQ(0xC));
+ reg_val_txchsta1 |= (SUNXI_SPDIF_TXCHSTA1_ORISAMFREQ(0x3));
+ reg_val_rxchsta0 |= (SUNXI_SPDIF_RXCHSTA0_SAMFREQ(0xC));
+ reg_val_rxchsta1 |= (SUNXI_SPDIF_RXCHSTA1_ORISAMFREQ(0x3));
break;
default:
- reg_val = readl(sunxi_spdif.regs + SUNXI_SPDIF_TXCHSTA0);
- reg_val |= (SUNXI_SPDIF_TXCHSTA0_SAMFREQ(1));
- writel(reg_val, sunxi_spdif.regs + SUNXI_SPDIF_TXCHSTA0);
-
- reg_val = readl(sunxi_spdif.regs + SUNXI_SPDIF_TXCHSTA1);
- reg_val |= (SUNXI_SPDIF_TXCHSTA1_ORISAMFREQ(0));
- writel(reg_val, sunxi_spdif.regs + SUNXI_SPDIF_TXCHSTA1);
+ reg_val_txchsta0 |= (SUNXI_SPDIF_TXCHSTA0_SAMFREQ(1));
+ reg_val_txchsta1 |= (SUNXI_SPDIF_TXCHSTA1_ORISAMFREQ(0));
+ reg_val_rxchsta0 |= (SUNXI_SPDIF_RXCHSTA0_SAMFREQ(1));
+ reg_val_rxchsta1 |= (SUNXI_SPDIF_RXCHSTA1_ORISAMFREQ(0));
+
break;
}
}
+ writel(reg_val_txchsta0, sunxi_spdif.regs + SUNXI_SPDIF_TXCHSTA0);
+ writel(reg_val_txchsta1, sunxi_spdif.regs + SUNXI_SPDIF_TXCHSTA1);
+
+ writel(reg_val_rxchsta0, sunxi_spdif.regs + SUNXI_SPDIF_RXCHSTA0);
+ writel(reg_val_rxchsta1, sunxi_spdif.regs + SUNXI_SPDIF_RXCHSTA1);
}
break;
case SUNXI_DIV_BCLK:
@@ -399,7 +465,6 @@ static int sunxi_spdif_set_clkdiv(struct snd_soc_dai *cpu_dai, int div_id, int d
default:
return -EINVAL;
}
-
return 0;
}
@@ -422,10 +487,13 @@ static void spdifregsave(void)
{
regsave[0] = readl(sunxi_spdif.regs + SUNXI_SPDIF_CTL);
regsave[1] = readl(sunxi_spdif.regs + SUNXI_SPDIF_TXCFG);
- regsave[2] = readl(sunxi_spdif.regs + SUNXI_SPDIF_FCTL) | (0x3<<16);
+ regsave[2] = readl(sunxi_spdif.regs + SUNXI_SPDIF_FCTL) | (0x3<<16); //clear TX, RX fifo
regsave[3] = readl(sunxi_spdif.regs + SUNXI_SPDIF_INT);
regsave[4] = readl(sunxi_spdif.regs + SUNXI_SPDIF_TXCHSTA0);
regsave[5] = readl(sunxi_spdif.regs + SUNXI_SPDIF_TXCHSTA1);
+ regsave[6] = readl(sunxi_spdif.regs + SUNXI_SPDIF_RXCFG);
+ regsave[7] = readl(sunxi_spdif.regs + SUNXI_SPDIF_RXCHSTA0);
+ regsave[8] = readl(sunxi_spdif.regs + SUNXI_SPDIF_RXCHSTA1);
}
static void spdifregrestore(void)
@@ -436,14 +504,18 @@ static void spdifregrestore(void)
writel(regsave[3], sunxi_spdif.regs + SUNXI_SPDIF_INT);
writel(regsave[4], sunxi_spdif.regs + SUNXI_SPDIF_TXCHSTA0);
writel(regsave[5], sunxi_spdif.regs + SUNXI_SPDIF_TXCHSTA1);
+ writel(regsave[6], sunxi_spdif.regs + SUNXI_SPDIF_RXCFG);
+ writel(regsave[7], sunxi_spdif.regs + SUNXI_SPDIF_RXCHSTA0);
+ writel(regsave[8], sunxi_spdif.regs + SUNXI_SPDIF_RXCHSTA1);
}
//#ifdef CONFIG_PM
static int sunxi_spdif_suspend(struct snd_soc_dai *cpu_dai)
{
u32 reg_val;
- printk("[SPDIF]Enter %s\n", __func__);
+ printk("[SPDIF] Enter %s\n", __func__);
+ //global disable
reg_val = readl(sunxi_spdif.regs + SUNXI_SPDIF_CTL);
reg_val &= ~SUNXI_SPDIF_CTL_GEN;
writel(reg_val, sunxi_spdif.regs + SUNXI_SPDIF_CTL);
@@ -453,7 +525,9 @@ static int sunxi_spdif_suspend(struct snd_soc_dai *cpu_dai)
//disable the module clock
clk_disable(spdif_moduleclk);
+ //clear start?
clk_disable(spdif_apbclk);
+ //clear end?
printk("[SPDIF]SPECIAL CLK 0x01c20068 = %#x, line= %d\n", *(volatile int*)0xF1C20068, __LINE__);
printk("[SPDIF]SPECIAL CLK 0x01c200C0 = %#x, line= %d\n", *(volatile int*)0xF1C200C0, __LINE__);
@@ -464,9 +538,9 @@ static int sunxi_spdif_suspend(struct snd_soc_dai *cpu_dai)
static int sunxi_spdif_resume(struct snd_soc_dai *cpu_dai)
{
u32 reg_val;
- printk("[SPDIF]Enter %s\n", __func__);
+ printk("[SPDIF] Enter %s\n", __func__);
- //disable the module clock
+ //enable the module clock
clk_enable(spdif_apbclk);
//enable the module clock
@@ -474,11 +548,18 @@ static int sunxi_spdif_resume(struct snd_soc_dai *cpu_dai)
spdifregrestore();
+ reg_val = readl(sunxi_spdif.regs + SUNXI_SPDIF_FCTL);
+ reg_val &= ~SUNXI_SPDIF_FCTL_FIFOSRC; //set TX FIFO source select as APB bus
+ writel(reg_val, sunxi_spdif.regs + SUNXI_SPDIF_FCTL);
+
reg_val = readl(sunxi_spdif.regs + SUNXI_SPDIF_CTL);
+ //soft reset SPDIF
+ reg_val |= SUNXI_SPDIF_CTL_RESET;
+ //global enable
reg_val |= SUNXI_SPDIF_CTL_GEN;
writel(reg_val, sunxi_spdif.regs + SUNXI_SPDIF_CTL);
- //printk("[SPDIF]PLL2 0x01c20008 = %#x\n", *(volatile int*)0xF1C20008);
+ printk("[SPDIF]PLL2 0x01c20008 = %#x\n", *(volatile int*)0xF1C20008);
printk("[SPDIF]SPECIAL CLK 0x01c20068 = %#x, line= %d\n", *(volatile int*)0xF1C20068, __LINE__);
printk("[SPDIF]SPECIAL CLK 0x01c200C0 = %#x, line = %d\n", *(volatile int*)0xF1C200C0, __LINE__);
@@ -487,11 +568,11 @@ static int sunxi_spdif_resume(struct snd_soc_dai *cpu_dai)
#define SUNXI_SPDIF_RATES (SNDRV_PCM_RATE_8000_192000 | SNDRV_PCM_RATE_KNOT)
static struct snd_soc_dai_ops sunxi_spdif_dai_ops = {
- .trigger = sunxi_spdif_trigger,
+ .trigger = sunxi_spdif_trigger,
.hw_params = sunxi_spdif_hw_params,
- .set_fmt = sunxi_spdif_set_fmt,
- .set_clkdiv = sunxi_spdif_set_clkdiv,
- .set_sysclk = sunxi_spdif_set_sysclk,
+ .set_fmt = sunxi_spdif_set_fmt,
+ .set_clkdiv = sunxi_spdif_set_clkdiv,
+ .set_sysclk = sunxi_spdif_set_sysclk,
};
static struct snd_soc_dai_driver sunxi_spdif_dai = {
.probe = sunxi_spdif_dai_probe,
@@ -502,14 +583,14 @@ static struct snd_soc_dai_driver sunxi_spdif_dai = {
.channels_min = 1,
.channels_max = 2,
.rates = SUNXI_SPDIF_RATES,
- .formats = SNDRV_PCM_FMTBIT_S16_LE,},
+ .formats = SNDRV_PCM_FMTBIT_S16_LE|SNDRV_PCM_FMTBIT_S20_3LE| SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE,},
.capture = {
.channels_min = 1,
.channels_max = 2,
.rates = SUNXI_SPDIF_RATES,
- .formats = SNDRV_PCM_FMTBIT_S16_LE,},
- .symmetric_rates = 1,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE|SNDRV_PCM_FMTBIT_S20_3LE| SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE,},
.ops = &sunxi_spdif_dai_ops,
+ .symmetric_rates = 1,
};
static int __devinit sunxi_spdif_dev_probe(struct platform_device *pdev)
@@ -521,46 +602,58 @@ static int __devinit sunxi_spdif_dev_probe(struct platform_device *pdev)
if(sunxi_spdif.regs == NULL)
return -ENXIO;
- //spdif apbclk
- spdif_apbclk = clk_get(NULL, "apb_spdif");
- if(-1 == clk_enable(spdif_apbclk)){
- printk("spdif_apbclk failed! line = %d\n", __LINE__);
- }
+ //spdif apbclk
+ spdif_apbclk = clk_get(NULL, "apb_spdif");
+ if(-1 == clk_enable(spdif_apbclk)){
+ printk("spdif_apbclk failed! line = %d\n", __LINE__);
+ }
- spdif_pllx8 = clk_get(NULL, "audio_pllx8");
+ spdif_pllx8 = clk_get(NULL, "audio_pllx8");
- //spdif pll2clk
- spdif_pll2clk = clk_get(NULL, "audio_pll");
+ //spdif pll2clk
+ spdif_pll2clk = clk_get(NULL, "audio_pll");
- //spdif module clk
- spdif_moduleclk = clk_get(NULL, "spdif");
+ //spdif module clk
+ spdif_moduleclk = clk_get(NULL, "spdif");
- if(clk_set_parent(spdif_moduleclk, spdif_pll2clk)){
- printk("try to set parent of spdif_moduleclk to spdif_pll2ck failed! line = %d\n",__LINE__);
- }
+ if(clk_set_parent(spdif_moduleclk, spdif_pll2clk)){
+ printk("try to set parent of spdif_moduleclk to spdif_pll2ck failed! line = %d\n",__LINE__);
+ }
- if(clk_set_rate(spdif_moduleclk, 24576000/8)){
- printk("set spdif_moduleclk clock freq to 24576000 failed! line = %d\n", __LINE__);
- }
+ if(clk_set_rate(spdif_moduleclk, 24576000/8)){
+ printk("set spdif_moduleclk clock freq to 24576000 failed! line = %d\n", __LINE__);
+ }
- if(-1 == clk_enable(spdif_moduleclk)){
- printk("open spdif_moduleclk failed! line = %d\n", __LINE__);
- }
+ if(-1 == clk_enable(spdif_moduleclk)){
+ printk("open spdif_moduleclk failed! line = %d\n", __LINE__);
+ }
- //global enbale
- reg_val = readl(sunxi_spdif.regs + SUNXI_SPDIF_CTL);
- reg_val |= SUNXI_SPDIF_CTL_GEN;
- writel(reg_val, sunxi_spdif.regs + SUNXI_SPDIF_CTL);
+ reg_val = readl(sunxi_spdif.regs + SUNXI_SPDIF_FCTL);
+ reg_val &= ~SUNXI_SPDIF_FCTL_FIFOSRC; //set TX FIFO source select as APB bus
+ writel(reg_val, sunxi_spdif.regs + SUNXI_SPDIF_FCTL);
+
+ reg_val = readl(sunxi_spdif.regs + SUNXI_SPDIF_CTL);
+ //soft reset SPDIF
+ reg_val |= SUNXI_SPDIF_CTL_RESET;
+ //global enable
+ reg_val |= SUNXI_SPDIF_CTL_GEN;
+ writel(reg_val, sunxi_spdif.regs + SUNXI_SPDIF_CTL);
- ret = snd_soc_register_dai(&pdev->dev, &sunxi_spdif_dai);
+ ret = snd_soc_register_dai(&pdev->dev, &sunxi_spdif_dai);
- iounmap(sunxi_spdif.ioregs);
+ iounmap(sunxi_spdif.ioregs);
return 0;
}
static int __devexit sunxi_spdif_dev_remove(struct platform_device *pdev)
{
+ int reg_val = 0;
+ //global disable
+ reg_val = readl(sunxi_spdif.regs + SUNXI_SPDIF_CTL);
+ reg_val &= ~SUNXI_SPDIF_CTL_GEN;
+ writel(reg_val, sunxi_spdif.regs + SUNXI_SPDIF_CTL);
+
/* release the module clock */
clk_disable(spdif_moduleclk);
diff --git a/sound/soc/sunxi/spdif/sunxi_spdif.h b/sound/soc/sunxi/spdif/sunxi_spdif.h
index 67955d8..08630c9 100644
--- a/sound/soc/sunxi/spdif/sunxi_spdif.h
+++ b/sound/soc/sunxi/spdif/sunxi_spdif.h
@@ -17,127 +17,134 @@
#define SUNXI_SPDIF_H_
/*------------------SPDIF register definition--------------------*/
-#define SUNXI_SPDIFBASE 0x01C21000
+#define SUNXI_SPDIFBASE 0x01C21000
-#define SUNXI_SPDIF_CTL (0x00)
+#define SUNXI_SPDIF_CTL (0x00)
#define SUNXI_SPDIF_CTL_MCLKDIV(v) ((v)<<4) //v even
- #define SUNXI_SPDIF_CTL_MCLKOUTEN (1<<2)
- #define SUNXI_SPDIF_CTL_GEN (1<<1)
- #define SUNXI_SPDIF_CTL_RESET (1<<0)
+ #define SUNXI_SPDIF_CTL_MCLKOUTEN (1<<2)
+ #define SUNXI_SPDIF_CTL_GEN (1<<1)
+ #define SUNXI_SPDIF_CTL_RESET (1<<0)
-#define SUNXI_SPDIF_TXCFG (0x04)
+#define SUNXI_SPDIF_TXCFG (0x04)
#define SUNXI_SPDIF_TXCFG_SINGLEMOD (1<<31)
- #define SUNXI_SPDIF_TXCFG_ASS (1<<17)
+ #define SUNXI_SPDIF_TXCFG_ASS (1<<17)
#define SUNXI_SPDIF_TXCFG_NONAUDIO (1<<16)
- #define SUNXI_SPDIF_TXCFG_TXRATIO(v) ((v)<<4)
- #define SUNXI_SPDIF_TXCFG_FMTRVD (3<<2)
+ #define SUNXI_SPDIF_TXCFG_TXRATIO(v) ((v)<<4)
+ #define SUNXI_SPDIF_TXCFG_FMTRVD (3<<2)
#define SUNXI_SPDIF_TXCFG_FMT16BIT (0<<2)
#define SUNXI_SPDIF_TXCFG_FMT20BIT (1<<2)
#define SUNXI_SPDIF_TXCFG_FMT24BIT (2<<2)
#define SUNXI_SPDIF_TXCFG_CHSTMODE (1<<1)
- #define SUNXI_SPDIF_TXCFG_TXEN (1<<0)
+ #define SUNXI_SPDIF_TXCFG_TXEN (1<<0)
#define SUNXI_SPDIF_RXCFG (0x08)
#define SUNXI_SPDIF_RXCFG_LOCKFLAG (1<<4)
- #define SUNXI_SPDIF_RXCFG_CHSTSRC (1<<3)
- #define SUNXI_SPDIF_RXCFG_CHSTCP (1<<1)
- #define SUNXI_SPDIF_RXCFG_RXEN (1<<0)
-
-#define SUNXI_SPDIF_TXFIFO (0x0C)
-
-#define SUNXI_SPDIF_RXFIFO (0x10)
-
-#define SUNXI_SPDIF_FCTL (0x14)
- #define SUNXI_SPDIF_FCTL_FIFOSRC (1<<31)
- #define SUNXI_SPDIF_FCTL_FTX (1<<17)
- #define SUNXI_SPDIF_FCTL_FRX (1<<16)
- #define SUNXI_SPDIF_FCTL_TXTL(v) ((v)<<8)
- #define SUNXI_SPDIF_FCTL_RXTL(v) (((v))<<3)
- #define SUNXI_SPDIF_FCTL_TXIM(v) ((v)<<2)
- #define SUNXI_SPDIF_FCTL_RXOM(v) ((v)<<0)
-
-#define SUNXI_SPDIF_FSTA (0x18)
- #define SUNXI_SPDIF_FSTA_TXE (1<<14)
+ #define SUNXI_SPDIF_RXCFG_CHSTSRC (1<<3)
+ #define SUNXI_SPDIF_RXCFG_CHSTCP (1<<1)
+ #define SUNXI_SPDIF_RXCFG_RXEN (1<<0)
+
+#define SUNXI_SPDIF_TXFIFO (0x0C)
+
+#define SUNXI_SPDIF_RXFIFO (0x10)
+
+#define SUNXI_SPDIF_FCTL (0x14)
+ #define SUNXI_SPDIF_FCTL_FIFOSRC (1<<31)
+ #define SUNXI_SPDIF_FCTL_FTX (1<<17)
+ #define SUNXI_SPDIF_FCTL_FRX (1<<16)
+ #define SUNXI_SPDIF_FCTL_TXTL(v) ((v)<<8)
+ #define SUNXI_SPDIF_FCTL_RXTL(v) ((v)<<3)
+ #define SUNXI_SPDIF_FCTL_TXIM0 (0<<2)
+ #define SUNXI_SPDIF_FCTL_TXIM1 (1<<2)
+ #define SUNXI_SPDIF_FCTL_RXOM0 (0<<0)
+ #define SUNXI_SPDIF_FCTL_RXOM1 (1<<0)
+ #define SUNXI_SPDIF_FCTL_RXOM2 (2<<0)
+ #define SUNXI_SPDIF_FCTL_RXOM3 (3<<0)
+
+#define SUNXI_SPDIF_FSTA (0x18)
+ #define SUNXI_SPDIF_FSTA_TXE (1<<14)
#define SUNXI_SPDIF_FSTA_TXECNTSHT (8)
- #define SUNXI_SPDIF_FSTA_RXA (1<<6)
+ #define SUNXI_SPDIF_FSTA_RXA (1<<6)
#define SUNXI_SPDIF_FSTA_RXACNTSHT (0)
-#define SUNXI_SPDIF_INT (0x1C)
- #define SUNXI_SPDIF_INT_RXLOCKEN (1<<18)
+#define SUNXI_SPDIF_INT (0x1C)
+ #define SUNXI_SPDIF_INT_RXLOCKEN (1<<18)
#define SUNXI_SPDIF_INT_RXUNLOCKEN (1<<17)
#define SUNXI_SPDIF_INT_RXPARERREN (1<<16)
- #define SUNXI_SPDIF_INT_TXDRQEN (1<<7)
- #define SUNXI_SPDIF_INT_TXUIEN (1<<6)
- #define SUNXI_SPDIF_INT_TXOIEN (1<<5)
- #define SUNXI_SPDIF_INT_TXEIEN (1<<4)
- #define SUNXI_SPDIF_INT_RXDRQEN (1<<2)
- #define SUNXI_SPDIF_INT_RXOIEN (1<<1)
- #define SUNXI_SPDIF_INT_RXAIEN (1<<0)
-
-#define SUNXI_SPDIF_ISTA (0x20)
+ #define SUNXI_SPDIF_INT_TXDRQEN (1<<7)
+ #define SUNXI_SPDIF_INT_TXUIEN (1<<6)
+ #define SUNXI_SPDIF_INT_TXOIEN (1<<5)
+ #define SUNXI_SPDIF_INT_TXEIEN (1<<4)
+ #define SUNXI_SPDIF_INT_RXDRQEN (1<<2)
+ #define SUNXI_SPDIF_INT_RXOIEN (1<<1)
+ #define SUNXI_SPDIF_INT_RXAIEN (1<<0)
+
+#define SUNXI_SPDIF_ISTA (0x20)
#define SUNXI_SPDIF_ISTA_RXLOCKSTA (1<<18)
- #define SUNXI_SPDIF_ISTA_RXUNLOCKSTA (1<<17)
- #define SUNXI_SPDIF_ISTA_RXPARERRSTA (1<<16)
- #define SUNXI_SPDIF_ISTA_TXUSTA (1<<6)
- #define SUNXI_SPDIF_ISTA_TXOSTA (1<<5)
- #define SUNXI_SPDIF_ISTA_TXESTA (1<<4)
- #define SUNXI_SPDIF_ISTA_RXOSTA (1<<1)
- #define SUNXI_SPDIF_ISTA_RXASTA (1<<0)
-
-#define SUNXI_SPDIF_TXCNT (0x24)
-
-#define SUNXI_SPDIF_RXCNT (0x28)
-
-#define SUNXI_SPDIF_TXCHSTA0 (0x2C)
- #define SUNXI_SPDIF_TXCHSTA0_CLK(v) ((v)<<28)
- #define SUNXI_SPDIF_TXCHSTA0_SAMFREQ(v) ((v)<<24)
- #define SUNXI_SPDIF_TXCHSTA0_CHNUM(v) ((v)<<20)
- #define SUNXI_SPDIF_TXCHSTA0_SRCNUM(v) ((v)<<16)
- #define SUNXI_SPDIF_TXCHSTA0_CATACOD(v) ((v)<<8)
- #define SUNXI_SPDIF_TXCHSTA0_MODE(v) ((v)<<6)
- #define SUNXI_SPDIF_TXCHSTA0_EMPHASIS(v) ((v)<<3)
- #define SUNXI_SPDIF_TXCHSTA0_CP (1<<2)
- #define SUNXI_SPDIF_TXCHSTA0_AUDIO (1<<1)
- #define SUNXI_SPDIF_TXCHSTA0_PRO (1<<0)
-
-#define SUNXI_SPDIF_TXCHSTA1 (0x30)
- #define SUNXI_SPDIF_TXCHSTA1_CGMSA(v) ((v)<<8)
+ #define SUNXI_SPDIF_ISTA_RXUNLOCKSTA (1<<17)
+ #define SUNXI_SPDIF_ISTA_RXPARERRSTA (1<<16)
+ #define SUNXI_SPDIF_ISTA_TXUSTA (1<<6)
+ #define SUNXI_SPDIF_ISTA_TXOSTA (1<<5)
+ #define SUNXI_SPDIF_ISTA_TXESTA (1<<4)
+ #define SUNXI_SPDIF_ISTA_RXOSTA (1<<1)
+ #define SUNXI_SPDIF_ISTA_RXASTA (1<<0)
+ #define SUNXI_SPDIF_ISTA_RXCLR (SUNXI_SPDIF_ISTA_RXLOCKSTA | SUNXI_SPDIF_ISTA_RXUNLOCKSTA | SUNXI_SPDIF_ISTA_RXPARERRSTA | SUNXI_SPDIF_ISTA_RXOSTA | SUNXI_SPDIF_ISTA_RXASTA)
+ #define SUNXI_SPDIF_ISTA_TXCLR (SUNXI_SPDIF_ISTA_TXUSTA | SUNXI_SPDIF_ISTA_TXOSTA | SUNXI_SPDIF_ISTA_TXESTA)
+
+
+#define SUNXI_SPDIF_TXCNT (0x24)
+
+#define SUNXI_SPDIF_RXCNT (0x28)
+
+#define SUNXI_SPDIF_TXCHSTA0 (0x2C)
+ #define SUNXI_SPDIF_TXCHSTA0_CLK(v) ((v)<<28)
+ #define SUNXI_SPDIF_TXCHSTA0_SAMFREQ(v) ((v)<<24)
+ #define SUNXI_SPDIF_TXCHSTA0_CHNUM(v) ((v)<<20)
+ #define SUNXI_SPDIF_TXCHSTA0_SRCNUM(v) ((v)<<16)
+ #define SUNXI_SPDIF_TXCHSTA0_CATACOD(v) ((v)<<8)
+ #define SUNXI_SPDIF_TXCHSTA0_MODE(v) ((v)<<6)
+ #define SUNXI_SPDIF_TXCHSTA0_EMPHASIS(v) ((v)<<3)
+ #define SUNXI_SPDIF_TXCHSTA0_CP (1<<2)
+ #define SUNXI_SPDIF_TXCHSTA0_AUDIO (1<<1)
+ #define SUNXI_SPDIF_TXCHSTA0_PRO (1<<0)
+
+#define SUNXI_SPDIF_TXCHSTA1 (0x30)
+ #define SUNXI_SPDIF_TXCHSTA1_CGMSA(v) ((v)<<8)
#define SUNXI_SPDIF_TXCHSTA1_ORISAMFREQ(v) ((v)<<4)
#define SUNXI_SPDIF_TXCHSTA1_SAMWORDLEN(v) ((v)<<1)
- #define SUNXI_SPDIF_TXCHSTA1_MAXWORDLEN (1<<0)
-
-#define SUNXI_SPDIF_RXCHSTA0 (0x34)
- #define SUNXI_SPDIF_RXCHSTA0_CLK(v) ((v)<<28)
- #define SUNXI_SPDIF_RXCHSTA0_SAMFREQ(v) ((v)<<24)
- #define SUNXI_SPDIF_RXCHSTA0_CHNUM(v) ((v)<<20)
- #define SUNXI_SPDIF_RXCHSTA0_SRCNUM(v) ((v)<<16)
- #define SUNXI_SPDIF_RXCHSTA0_CATACOD(v) ((v)<<8)
- #define SUNXI_SPDIF_RXCHSTA0_MODE(v) ((v)<<6)
- #define SUNXI_SPDIF_RXCHSTA0_EMPHASIS(v) ((v)<<3)
- #define SUNXI_SPDIF_RXCHSTA0_CP (1<<2)
- #define SUNXI_SPDIF_RXCHSTA0_AUDIO (1<<1)
- #define SUNXI_SPDIF_RXCHSTA0_PRO (1<<0)
-
-#define SUNXI_SPDIF_RXCHSTA1 (0x38)
- #define SUNXI_SPDIF_RXCHSTA1_CGMSA(v) ((v)<<8)
+ #define SUNXI_SPDIF_TXCHSTA1_MAXWORDLEN (1<<0)
+
+#define SUNXI_SPDIF_RXCHSTA0 (0x34)
+ #define SUNXI_SPDIF_RXCHSTA0_CLK(v) ((v)<<28)
+ #define SUNXI_SPDIF_RXCHSTA0_SAMFREQ(v) ((v)<<24)
+ #define SUNXI_SPDIF_RXCHSTA0_CHNUM(v) ((v)<<20)
+ #define SUNXI_SPDIF_RXCHSTA0_SRCNUM(v) ((v)<<16)
+ #define SUNXI_SPDIF_RXCHSTA0_CATACOD(v) ((v)<<8)
+ #define SUNXI_SPDIF_RXCHSTA0_MODE(v) ((v)<<6)
+ #define SUNXI_SPDIF_RXCHSTA0_EMPHASIS(v) ((v)<<3)
+ #define SUNXI_SPDIF_RXCHSTA0_CP (1<<2)
+ #define SUNXI_SPDIF_RXCHSTA0_AUDIO (1<<1)
+ #define SUNXI_SPDIF_RXCHSTA0_PRO (1<<0)
+
+#define SUNXI_SPDIF_RXCHSTA1 (0x38)
+ #define SUNXI_SPDIF_RXCHSTA1_CGMSA(v) ((v)<<8)
#define SUNXI_SPDIF_RXCHSTA1_ORISAMFREQ(v) ((v)<<4)
#define SUNXI_SPDIF_RXCHSTA1_SAMWORDLEN(v) ((v)<<1)
- #define SUNXI_SPDIF_RXCHSTA1_MAXWORDLEN (1<<0)
+ #define SUNXI_SPDIF_RXCHSTA1_MAXWORDLEN (1<<0)
/*--------------------------------CCM register definition---------------------*/
-#define SUNXI_CCMBASE (0x01C20000)
+#define SUNXI_CCMBASE (0x01C20000)
-#define SUNXI_CCMBASE_AUDIOHOSCPLL (0x08)
- #define SUNXI_CCMBASE_AUDIOHOSCPLL_EN (1<<31)
- #define SUNXI_CCMBASE_AUDIOHOSCPLL_24576M (1<<27)
- #define SUNXI_CCMBASE_AUDIOHOSCPLL_225792M (0<<27)
+#define SUNXI_CCMBASE_AUDIOHOSCPLL (0x08)
+ #define SUNXI_CCMBASE_AUDIOHOSCPLL_EN (1<<31)
+ #define SUNXI_CCMBASE_AUDIOHOSCPLL_24576M (1<<27)
+ #define SUNXI_CCMBASE_AUDIOHOSCPLL_225792M (0<<27)
-#define SUNXI_CCMBASE_APBGATE (0x68)
- #define SUNXI_CCMBASE_APBGATE_SPDIFGATE (1<<1)
+#define SUNXI_CCMBASE_APBGATE (0x68)
+ #define SUNXI_CCMBASE_APBGATE_SPDIFGATE (1<<1)
-#define SUNXI_CCMBASE_AUDIOCLK (0xC0)
+#define SUNXI_CCMBASE_AUDIOCLK (0xC0)
#define SUNXI_CCMBASE_AUDIOCLK_SPDIFSPEGATE (1<<31)
- #define SUNXI_CCMBASE_AUDIOCLK_DIV(v) ((v)<<16)
+ #define SUNXI_CCMBASE_AUDIOCLK_DIV(v) ((v)<<16)
/* Clock dividers */
#define SUNXI_DIV_MCLK 0
@@ -156,6 +163,6 @@ extern struct sunxi_spdif_info sunxi_spdif;
unsigned int sunxi_spdif_get_clockrate(void);
extern void sunxi_snd_txctrl(struct snd_pcm_substream *substream, int on);
-extern void sunxi_snd_rxctrl(int on);
+extern void sunxi_snd_rxctrl(struct snd_pcm_substream *substream, int on);
#endif
diff --git a/sound/soc/sunxi/spdif/sunxi_spdma.c b/sound/soc/sunxi/spdif/sunxi_spdma.c
index ec4ac99..038903d 100644
--- a/sound/soc/sunxi/spdif/sunxi_spdma.c
+++ b/sound/soc/sunxi/spdif/sunxi_spdma.c
@@ -34,25 +34,40 @@
#include "sunxi_spdif.h"
#include "sunxi_spdma.h"
-static volatile unsigned int dmasrc = 0;
-static volatile unsigned int dmadst = 0;
+static const struct snd_pcm_hardware sunxi_pcm_out_hardware = {
+ .info = SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
+ SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
+ SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |SNDRV_PCM_FMTBIT_S20_3LE| SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE,
+ .rates = SNDRV_PCM_RATE_8000_192000 | SNDRV_PCM_RATE_KNOT,
+ .rate_min = 8000,
+ .rate_max = 192000,
+ .channels_min = 1,
+ .channels_max = 2,
+ .buffer_bytes_max = 128*1024, /* value must be (2^n)Kbyte size */
+ .period_bytes_min = 1024,//1024*4,
+ .period_bytes_max = 1024*32,//1024*128,
+ .periods_min = 4,
+ .periods_max = 8,
+ .fifo_size = 32,
+};
-static const struct snd_pcm_hardware sunxi_pcm_hardware = {
+static const struct snd_pcm_hardware sunxi_pcm_in_hardware = {
.info = SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME,
- .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |SNDRV_PCM_FMTBIT_S20_3LE| SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE,
.rates = SNDRV_PCM_RATE_8000_192000 | SNDRV_PCM_RATE_KNOT,
.rate_min = 8000,
.rate_max = 192000,
.channels_min = 1,
.channels_max = 2,
- .buffer_bytes_max = 128*1024, //1024*1024 /* value must be (2^n)Kbyte size */
- .period_bytes_min = 1024*4,//1024*4,
+ .buffer_bytes_max = 128*1024, /* value must be (2^n)Kbyte size */
+ .period_bytes_min = 1024,//1024*4,
.period_bytes_max = 1024*32,//1024*128,
- .periods_min = 4,//8,
- .periods_max = 8,//8,
- .fifo_size = 32,//32,
+ .periods_min = 4,
+ .periods_max = 8,
+ .fifo_size = 32,
};
struct sunxi_runtime_data {
@@ -65,6 +80,8 @@ struct sunxi_runtime_data {
dma_addr_t dma_pos;
dma_addr_t dma_end;
struct sunxi_dma_params *params;
+ /*DMA data width*/
+ unsigned int dma_width;
};
static void sunxi_pcm_enqueue(struct snd_pcm_substream *substream)
@@ -73,8 +90,8 @@ static void sunxi_pcm_enqueue(struct snd_pcm_substream *substream)
dma_addr_t pos = prtd->dma_pos;
unsigned int limit;
int ret;
-
unsigned long len = prtd->dma_period;
+ int read = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? 0 : 1;
limit = prtd->dma_limit;
while(prtd->dma_loaded < limit){
@@ -82,7 +99,7 @@ static void sunxi_pcm_enqueue(struct snd_pcm_substream *substream)
len = prtd->dma_end - pos;
}
- ret = sunxi_dma_enqueue(prtd->params, pos, len, 0);
+ ret = sunxi_dma_enqueue(prtd->params, pos, len, read);
if (ret == 0) {
prtd->dma_loaded++;
pos += prtd->dma_period;
@@ -120,17 +137,24 @@ static int sunxi_pcm_hw_params(struct snd_pcm_substream *substream,
struct sunxi_runtime_data *prtd = runtime->private_data;
struct snd_soc_pcm_runtime *rtd = substream->private_data;
unsigned long totbytes = params_buffer_bytes(params);
- struct sunxi_dma_params *dma =
- snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
+ struct sunxi_dma_params *dma = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
int ret = 0;
if (!dma)
return 0;
+ if (SNDRV_PCM_FORMAT_S16_LE == params_format(params)) {
+ prtd->dma_width = 16;
+ }
+ else {
+ prtd->dma_width = 32;
+ }
+
if (prtd->params == NULL) {
prtd->params = dma;
ret = sunxi_dma_request(prtd->params, 0);
if (ret < 0) {
- return ret;
+ pr_err("[SPDIF] sunxi_dma_request failed! (ret=(%d)) failed %s,%d\n", ret, __func__,__LINE__);
+ return ret;
}
}
@@ -138,6 +162,7 @@ static int sunxi_pcm_hw_params(struct snd_pcm_substream *substream,
substream) != 0) {
sunxi_dma_release(prtd->params);
prtd->params = NULL;
+ pr_err("[SPDIF] sunxi_dma_set_callback failed! (ret=(%d)) failed %s,%d\n", ret, __func__,__LINE__);
return -EINVAL;
}
@@ -153,6 +178,7 @@ static int sunxi_pcm_hw_params(struct snd_pcm_substream *substream,
prtd->dma_pos = prtd->dma_start;
prtd->dma_end = prtd->dma_start + totbytes;
spin_unlock_irq(&prtd->lock);
+
return 0;
}
@@ -197,16 +223,22 @@ static int sunxi_pcm_prepare(struct snd_pcm_substream *substream)
#else
dma_config_t spdif_dma_conf;
memset(&spdif_dma_conf, 0, sizeof(spdif_dma_conf));
- spdif_dma_conf.xfer_type.src_data_width = DATA_WIDTH_16BIT;
+ if(prtd->dma_width > 16) {
+ spdif_dma_conf.xfer_type.src_data_width = DATA_WIDTH_32BIT;
+ spdif_dma_conf.xfer_type.dst_data_width = DATA_WIDTH_32BIT;
+ }
+ else {
+ spdif_dma_conf.xfer_type.src_data_width = DATA_WIDTH_16BIT;
+ spdif_dma_conf.xfer_type.dst_data_width = DATA_WIDTH_16BIT;
+ }
spdif_dma_conf.xfer_type.src_bst_len = DATA_BRST_4;
- spdif_dma_conf.xfer_type.dst_data_width = DATA_WIDTH_16BIT;
spdif_dma_conf.xfer_type.dst_bst_len = DATA_BRST_4;
spdif_dma_conf.address_type.src_addr_mode = NDMA_ADDR_INCREMENT;
spdif_dma_conf.address_type.dst_addr_mode = NDMA_ADDR_NOCHANGE;
spdif_dma_conf.bconti_mode = false;
spdif_dma_conf.irq_spt = CHAN_IRQ_FD;
spdif_dma_conf.src_drq_type = N_SRC_SDRAM;
- spdif_dma_conf.dst_drq_type = N_DST_SPDIF_TX;//DRQDST_SPDIFTX;
+ spdif_dma_conf.dst_drq_type = N_DST_SPDIF_TX;
#endif
ret = sunxi_dma_config(prtd->params, &spdif_dma_conf, 0);
} else {
@@ -221,10 +253,27 @@ static int sunxi_pcm_prepare(struct snd_pcm_substream *substream)
spdif_dma_conf.hf_irq = SW_DMA_IRQ_FULL|SW_DMA_IRQ_HALF;
spdif_dma_conf.from = prtd->params->dma_addr;
spdif_dma_conf.to = prtd->dma_start;
- ret = sunxi_dma_config(prtd->params, &spdif_dma_conf, 0);
#else
- return -EINVAL;
+ dma_config_t spdif_dma_conf;
+ memset(&spdif_dma_conf, 0, sizeof(spdif_dma_conf));
+ if(prtd->dma_width > 16) {
+ spdif_dma_conf.xfer_type.src_data_width = DATA_WIDTH_32BIT;
+ spdif_dma_conf.xfer_type.dst_data_width = DATA_WIDTH_32BIT;
+ }
+ else {
+ spdif_dma_conf.xfer_type.src_data_width = DATA_WIDTH_16BIT;
+ spdif_dma_conf.xfer_type.dst_data_width = DATA_WIDTH_16BIT;
+ }
+ spdif_dma_conf.xfer_type.src_bst_len = DATA_BRST_4;
+ spdif_dma_conf.xfer_type.dst_bst_len = DATA_BRST_4;
+ spdif_dma_conf.address_type.src_addr_mode = NDMA_ADDR_NOCHANGE;
+ spdif_dma_conf.address_type.dst_addr_mode = NDMA_ADDR_INCREMENT;
+ spdif_dma_conf.bconti_mode = false;
+ spdif_dma_conf.irq_spt = CHAN_IRQ_FD;
+ spdif_dma_conf.src_drq_type = N_SRC_SPDIF_RX;
+ spdif_dma_conf.dst_drq_type = N_DST_SDRAM;
#endif
+ ret = sunxi_dma_config(prtd->params, &spdif_dma_conf, 0);
}
/* flush the DMA channel */
prtd->dma_loaded = 0;
@@ -248,12 +297,14 @@ static int sunxi_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
case SNDRV_PCM_TRIGGER_RESUME:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
sunxi_dma_start(prtd->params);
+ prtd->state |= ST_RUNNING;
break;
case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
sunxi_dma_stop(prtd->params);
+ prtd->state &= ~ST_RUNNING;
break;
default:
@@ -271,21 +322,26 @@ static snd_pcm_uframes_t sunxi_pcm_pointer(struct snd_pcm_substream *substream)
struct sunxi_runtime_data *prtd = runtime->private_data;
unsigned long res = 0;
snd_pcm_uframes_t offset = 0;
+ dma_addr_t dmasrc = 0;
+ dma_addr_t dmadst = 0;
+
spin_lock(&prtd->lock);
sunxi_dma_getcurposition(prtd->params,
(dma_addr_t*)&dmasrc, (dma_addr_t*)&dmadst);
- if (substream->stream == SNDRV_PCM_STREAM_CAPTURE){
- res = dmadst - prtd->dma_start;
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK){
+ res = dmasrc + prtd->dma_period - prtd->dma_start;
} else {
- offset = bytes_to_frames(runtime, dmasrc + prtd->dma_period - runtime->dma_addr);
+ res = dmadst + prtd->dma_period - prtd->dma_start;
}
+ offset = bytes_to_frames(runtime, res);
spin_unlock(&prtd->lock);
if(offset >= runtime->buffer_size)
offset = 0;
- return offset;
+
+ return offset;
}
static int sunxi_pcm_open(struct snd_pcm_substream *substream)
@@ -294,11 +350,17 @@ static int sunxi_pcm_open(struct snd_pcm_substream *substream)
struct sunxi_runtime_data *prtd;
snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
- snd_soc_set_runtime_hwparams(substream, &sunxi_pcm_hardware);
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ snd_soc_set_runtime_hwparams(substream, &sunxi_pcm_out_hardware);
+ } else {
+ snd_soc_set_runtime_hwparams(substream, &sunxi_pcm_in_hardware);
+ }
prtd = kzalloc(sizeof(struct sunxi_runtime_data), GFP_KERNEL);
- if (prtd == NULL)
+ if (prtd == NULL) {
+ pr_err("[SPDIF] try to alloc sunxi_runtime_data failed %s,%d\n", __func__,__LINE__);
return -ENOMEM;
+ }
spin_lock_init(&prtd->lock);
@@ -311,7 +373,6 @@ static int sunxi_pcm_close(struct snd_pcm_substream *substream)
struct snd_pcm_runtime *runtime = substream->runtime;
struct sunxi_runtime_data *prtd = runtime->private_data;
kfree(prtd);
-
return 0;
}
@@ -342,8 +403,13 @@ static int sunxi_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
{
struct snd_pcm_substream *substream = pcm->streams[stream].substream;
struct snd_dma_buffer *buf = &substream->dma_buffer;
- size_t size = sunxi_pcm_hardware.buffer_bytes_max;
+ size_t size = 0;
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ size = sunxi_pcm_out_hardware.buffer_bytes_max;
+ } else {
+ size = sunxi_pcm_in_hardware.buffer_bytes_max;
+ }
buf->dev.type = SNDRV_DMA_TYPE_DEV;
buf->dev.dev = pcm->card->dev;
buf->private_data = NULL;
@@ -384,6 +450,7 @@ static int sunxi_pcm_new(struct snd_soc_pcm_runtime *rtd)
struct snd_pcm *pcm = rtd->pcm;
int ret = 0;
+
if (!card->dev->dma_mask)
card->dev->dma_mask = &sunxi_pcm_mask;
if (!card->dev->coherent_dma_mask)
@@ -443,16 +510,19 @@ static int __init sunxi_soc_platform_spdif_init(void)
int ret, spdif_used = 0;
ret = script_parser_fetch("spdif_para", "spdif_used", &spdif_used, 1);
- if (ret != 0 || !spdif_used)
+ if (ret != 0 || !spdif_used)
return -ENODEV;
ret = platform_device_register(&sunxi_spdif_pcm_device);
- if (ret < 0)
+ if (ret < 0) {
+ pr_err("[SPDIF] try to SPDIF platform_device_register failed (ret=(%d)) failed %s,%d\n", ret, __func__,__LINE__);
return ret;
+ }
ret = platform_driver_register(&sunxi_spdif_pcm_driver);
if (ret < 0) {
platform_device_unregister(&sunxi_spdif_pcm_device);
+ pr_err("[SPDIF] try to SPDIF platform_driver_register failed (ret=(%d)) failed %s,%d\n", ret, __func__,__LINE__);
return ret;
}
return 0;