mirror of
https://github.com/Fishwaldo/build.git
synced 2025-03-21 22:31:51 +00:00
3391 lines
118 KiB
Diff
3391 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
|
|
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;
|