build/patch/kernel/sun7i-default/0028-nikkov-i2s-spdif-2.0.patch

5319 lines
181 KiB
Diff
Raw Normal View History

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/hdmiaudio/sndhdmi.c b/sound/soc/sunxi/hdmiaudio/sndhdmi.c
index 1c306d2..f291c4b 100644
--- a/sound/soc/sunxi/hdmiaudio/sndhdmi.c
+++ b/sound/soc/sunxi/hdmiaudio/sndhdmi.c
@@ -22,12 +22,9 @@
#include <sound/initval.h>
#include <plat/sys_config.h>
#include <linux/io.h>
-#include <linux/drv_hdmi.h>
-static __audio_hdmi_func g_hdmi_func;
-static hdmi_audio_t hdmi_para;
+#include "sndhdmi.h"
-/* The struct is just for registering the hdmiaudio codec node */
struct sndhdmi_priv {
int sysclk;
int dai_fmt;
@@ -36,11 +33,15 @@ struct sndhdmi_priv {
struct snd_pcm_substream *slave_substream;
};
-void audio_set_hdmi_func(__audio_hdmi_func *hdmi_func)
+static hdmi_audio_t hdmi_para;
+static __audio_hdmi_func g_hdmi_func;
+
+void audio_set_hdmi_func(__audio_hdmi_func * hdmi_func)
{
g_hdmi_func.hdmi_audio_enable = hdmi_func->hdmi_audio_enable;
g_hdmi_func.hdmi_set_audio_para = hdmi_func->hdmi_set_audio_para;
}
+
EXPORT_SYMBOL(audio_set_hdmi_func);
#define SNDHDMI_RATES (SNDRV_PCM_RATE_8000_192000|SNDRV_PCM_RATE_KNOT)
@@ -53,25 +54,21 @@ static int sndhdmi_mute(struct snd_soc_dai *dai, int mute)
}
static int sndhdmi_startup(struct snd_pcm_substream *substream,
- struct snd_soc_dai *dai)
+ struct snd_soc_dai *dai)
{
return 0;
}
static void sndhdmi_shutdown(struct snd_pcm_substream *substream,
- struct snd_soc_dai *dai)
+ struct snd_soc_dai *dai)
{
}
static int sndhdmi_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)
{
- if ((!substream) || (!params)) {
- printk("error:%s,line:%d\n", __func__, __LINE__);
- return -EAGAIN;
- }
hdmi_para.sample_rate = params_rate(params);
hdmi_para.channel_num = params_channels(params);
switch (params_format(params)) {
@@ -94,14 +91,13 @@ static int sndhdmi_hw_params(struct snd_pcm_substream *substream,
return 0;
}
-static int sndhdmi_set_dai_sysclk(struct snd_soc_dai *codec_dai, int clk_id,
- unsigned int freq, int dir)
+static int sndhdmi_set_dai_sysclk(struct snd_soc_dai *codec_dai,
+ int clk_id, unsigned int freq, int dir)
{
return 0;
}
-static int sndhdmi_set_dai_clkdiv(struct snd_soc_dai *codec_dai, int div_id,
- int div)
+static int sndhdmi_set_dai_clkdiv(struct snd_soc_dai *codec_dai, int div_id, int div)
{
hdmi_para.fs_between = div;
@@ -110,12 +106,13 @@ static int sndhdmi_set_dai_clkdiv(struct snd_soc_dai *codec_dai, int div_id,
}
-static int sndhdmi_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
+static int sndhdmi_set_dai_fmt(struct snd_soc_dai *codec_dai,
+ unsigned int fmt)
{
return 0;
}
-/* codec dai operation */
+//codec dai operation
struct snd_soc_dai_ops sndhdmi_dai_ops = {
.startup = sndhdmi_startup,
.shutdown = sndhdmi_shutdown,
@@ -126,7 +123,7 @@ struct snd_soc_dai_ops sndhdmi_dai_ops = {
.set_fmt = sndhdmi_set_dai_fmt,
};
-/* codec dai */
+//codec dai
struct snd_soc_dai_driver sndhdmi_dai = {
.name = "sndhdmi",
/* playback capabilities */
@@ -147,17 +144,11 @@ static int sndhdmi_soc_probe(struct snd_soc_codec *codec)
{
struct sndhdmi_priv *sndhdmi;
- if (!codec) {
- printk("error:%s,line:%d\n", __func__, __LINE__);
- return -EAGAIN;
- }
-
sndhdmi = kzalloc(sizeof(struct sndhdmi_priv), GFP_KERNEL);
- if (sndhdmi == NULL) {
- printk("error at:%s,%d\n", __func__, __LINE__);
+ if(sndhdmi == NULL){
+ printk("error at:%s,%d\n",__func__,__LINE__);
return -ENOMEM;
}
-
snd_soc_codec_set_drvdata(codec, sndhdmi);
return 0;
@@ -165,13 +156,7 @@ static int sndhdmi_soc_probe(struct snd_soc_codec *codec)
static int sndhdmi_soc_remove(struct snd_soc_codec *codec)
{
- struct sndhdmi_priv *sndhdmi;
-
- if (!codec) {
- printk("error:%s,line:%d\n", __func__, __LINE__);
- return -EAGAIN;
- }
- sndhdmi = snd_soc_codec_get_drvdata(codec);
+ struct sndhdmi_priv *sndhdmi = snd_soc_codec_get_drvdata(codec);
kfree(sndhdmi);
@@ -179,26 +164,17 @@ static int sndhdmi_soc_remove(struct snd_soc_codec *codec)
}
static struct snd_soc_codec_driver soc_codec_dev_sndhdmi = {
- .probe = sndhdmi_soc_probe,
- .remove = sndhdmi_soc_remove,
+ .probe = sndhdmi_soc_probe,
+ .remove = sndhdmi_soc_remove,
};
static int __devinit sndhdmi_codec_probe(struct platform_device *pdev)
{
- if (!pdev) {
- printk("error:%s,line:%d\n", __func__, __LINE__);
- return -EAGAIN;
- }
- return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_sndhdmi,
- &sndhdmi_dai, 1);
+ return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_sndhdmi, &sndhdmi_dai, 1);
}
-static int __exit sndhdmi_codec_remove(struct platform_device *pdev)
+static int __devexit sndhdmi_codec_remove(struct platform_device *pdev)
{
- if (!pdev) {
- printk("error:%s,line:%d\n", __func__, __LINE__);
- return -EAGAIN;
- }
snd_soc_unregister_codec(&pdev->dev);
return 0;
}
@@ -209,15 +185,14 @@ static struct platform_driver sndhdmi_codec_driver = {
.owner = THIS_MODULE,
},
.probe = sndhdmi_codec_probe,
- .remove = __exit_p(sndhdmi_codec_remove),
+ .remove = __devexit_p(sndhdmi_codec_remove),
};
static int __init sndhdmi_codec_init(void)
{
int err = 0;
- err = platform_driver_register(&sndhdmi_codec_driver);
- if (err < 0)
+ if ((err = platform_driver_register(&sndhdmi_codec_driver)) < 0)
return err;
return 0;
@@ -233,3 +208,4 @@ module_exit(sndhdmi_codec_exit);
MODULE_DESCRIPTION("SNDHDMI ALSA soc codec driver");
MODULE_AUTHOR("Zoltan Devai, Christian Pellegrin <chripell@evolware.org>");
MODULE_LICENSE("GPL");
+
diff --git a/sound/soc/sunxi/hdmiaudio/sndhdmi.h b/sound/soc/sunxi/hdmiaudio/sndhdmi.h
new file mode 100644
index 0000000..346e587
--- /dev/null
+++ b/sound/soc/sunxi/hdmiaudio/sndhdmi.h
@@ -0,0 +1,36 @@
+/*
+ * sound\soc\sunxi\hdmiaudio\sndhdmi.h
+ * (C) Copyright 2007-2011
+ * Allwinner Technology Co., Ltd. <www.allwinnertech.com>
+ * chenpailin <chenpailin@allwinnertech.com>
+ *
+ * some simple description for this code
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ */
+#ifndef SNDHDMI_H
+#define SNDHDMI_H
+#include <linux/drv_hdmi.h>
+
+struct sndhdmi_platform_data {
+ void (*power) (int);
+ int model;
+ /*
+ ALSA SOC usually puts the device in standby mode when it's not used
+ for sometime. If you unset is_powered_on_standby the driver will
+ turn off the ADC/DAC when this callback is invoked and turn it back
+ on when needed. Unfortunately this will result in a very light bump
+ (it can be audible only with good earphones). If this bothers you
+ set is_powered_on_standby, you will have slightly higher power
+ consumption. Please note that sending the L3 command for ADC is
+ enough to make the bump, so it doesn't make difference if you
+ completely take off power from the codec.
+ */
+ int is_powered_on_standby;
+};
+
+#endif
diff --git a/sound/soc/sunxi/hdmiaudio/sunxi-hdmiaudio.c b/sound/soc/sunxi/hdmiaudio/sunxi-hdmiaudio.c
index 12da1a6..5080f10 100644
--- a/sound/soc/sunxi/hdmiaudio/sunxi-hdmiaudio.c
+++ b/sound/soc/sunxi/hdmiaudio/sunxi-hdmiaudio.c
@@ -34,43 +34,300 @@
#include <plat/sys_config.h>
#include <plat/dma_compat.h>
+#include "sunxi-hdmipcm.h"
+#include "sunxi-hdmiaudio.h"
+
+//save the register value
+static int regsave[8];
+
static struct sunxi_dma_params sunxi_hdmiaudio_pcm_stereo_out = {
.client.name = "HDMIAUDIO PCM Stereo out",
#if defined CONFIG_ARCH_SUN4I || defined CONFIG_ARCH_SUN5I
.channel = DMACH_HDMIAUDIO,
#endif
- .dma_addr = 0,
+ .dma_addr = 0,
+};
+
+static struct sunxi_dma_params sunxi_hdmiaudio_pcm_stereo_in = {
+ .client.name = "HDMIAUDIO PCM Stereo in",
+#if defined CONFIG_ARCH_SUN4I || defined CONFIG_ARCH_SUN5I
+ .channel = DMACH_HDMIAUDIO,
+#endif
+ .dma_addr = SUNXI_HDMIAUDIOBASE + SUNXI_HDMIAUDIORXFIFO,
};
+struct sunxi_hdmiaudio_info sunxi_hdmiaudio;
+
+//clock handle
+static struct clk *hdmiaudio_apbclk;
+static struct clk *hdmiaudio_pll2clk;
+static struct clk *hdmiaudio_pllx8;
+static struct clk *hdmiaudio_moduleclk;
+
void sunxi_snd_txctrl_hdmiaudio(struct snd_pcm_substream *substream, int on)
{
+ u32 reg_val;
+
+ reg_val = readl(sunxi_hdmiaudio.regs + SUNXI_TXCHSEL);
+ reg_val &= ~0x7;
+ reg_val |= SUNXI_TXCHSEL_CHNUM(substream->runtime->channels);
+ writel(reg_val, sunxi_hdmiaudio.regs + SUNXI_TXCHSEL);
+
+ reg_val = readl(sunxi_hdmiaudio.regs + SUNXI_TXCHMAP);
+ reg_val = 0;
+ if(substream->runtime->channels == 1) {
+ reg_val = 0x76543200;
+ } else {
+ reg_val = 0x76543210;
+ }
+ writel(reg_val, sunxi_hdmiaudio.regs + SUNXI_TXCHMAP);
+
+ reg_val = readl(sunxi_hdmiaudio.regs + SUNXI_HDMIAUDIOCTL);
+ reg_val &= ~SUNXI_HDMIAUDIOCTL_SDO3EN;
+ reg_val &= ~SUNXI_HDMIAUDIOCTL_SDO2EN;
+ reg_val &= ~SUNXI_HDMIAUDIOCTL_SDO1EN;
+ reg_val &= ~SUNXI_HDMIAUDIOCTL_SDO0EN;
+ switch(substream->runtime->channels) {
+ case 1:
+ case 2:
+ reg_val |= SUNXI_HDMIAUDIOCTL_SDO0EN; break;
+ case 3:
+ case 4:
+ reg_val |= SUNXI_HDMIAUDIOCTL_SDO0EN | SUNXI_HDMIAUDIOCTL_SDO1EN; break;
+ case 5:
+ case 6:
+ reg_val |= SUNXI_HDMIAUDIOCTL_SDO0EN | SUNXI_HDMIAUDIOCTL_SDO1EN | SUNXI_HDMIAUDIOCTL_SDO2EN; break;
+ case 7:
+ case 8:
+ reg_val |= SUNXI_HDMIAUDIOCTL_SDO0EN | SUNXI_HDMIAUDIOCTL_SDO1EN | SUNXI_HDMIAUDIOCTL_SDO2EN | SUNXI_HDMIAUDIOCTL_SDO3EN; break;
+ default:
+ reg_val |= SUNXI_HDMIAUDIOCTL_SDO0EN; break;
+ }
+ writel(reg_val, sunxi_hdmiaudio.regs + SUNXI_HDMIAUDIOCTL);
+
+ //flush TX FIFO
+ reg_val = readl(sunxi_hdmiaudio.regs + SUNXI_HDMIAUDIOFCTL);
+ reg_val |= SUNXI_HDMIAUDIOFCTL_FTX;
+ writel(reg_val, sunxi_hdmiaudio.regs + SUNXI_HDMIAUDIOFCTL);
+
+ //clear TX counter
+ writel(0, sunxi_hdmiaudio.regs + SUNXI_HDMIAUDIOTXCNT);
+
+ if (on) {
+ /* hdmiaudio TX ENABLE */
+ reg_val = readl(sunxi_hdmiaudio.regs + SUNXI_HDMIAUDIOCTL);
+ reg_val |= SUNXI_HDMIAUDIOCTL_TXEN;
+ writel(reg_val, sunxi_hdmiaudio.regs + SUNXI_HDMIAUDIOCTL);
+
+ /* enable DMA DRQ mode for play */
+ reg_val = readl(sunxi_hdmiaudio.regs + SUNXI_HDMIAUDIOINT);
+ reg_val |= SUNXI_HDMIAUDIOINT_TXDRQEN;
+ writel(reg_val, sunxi_hdmiaudio.regs + SUNXI_HDMIAUDIOINT);
+
+ //Global Enable Digital Audio Interface
+ reg_val = readl(sunxi_hdmiaudio.regs + SUNXI_HDMIAUDIOCTL);
+ reg_val |= SUNXI_HDMIAUDIOCTL_GEN;
+ writel(reg_val, sunxi_hdmiaudio.regs + SUNXI_HDMIAUDIOCTL);
+ }else{
+ /* HDMIAUDIO TX DISABLE */
+ reg_val = readl(sunxi_hdmiaudio.regs + SUNXI_HDMIAUDIOCTL);
+ reg_val &= ~SUNXI_HDMIAUDIOCTL_TXEN;
+ writel(reg_val, sunxi_hdmiaudio.regs + SUNXI_HDMIAUDIOCTL);
+
+ /* DISBALE dma DRQ mode */
+ reg_val = readl(sunxi_hdmiaudio.regs + SUNXI_HDMIAUDIOINT);
+ reg_val &= ~SUNXI_HDMIAUDIOINT_TXDRQEN;
+ writel(reg_val, sunxi_hdmiaudio.regs + SUNXI_HDMIAUDIOINT);
+
+ //Global disable Digital Audio Interface
+ reg_val = readl(sunxi_hdmiaudio.regs + SUNXI_HDMIAUDIOCTL);
+ reg_val &= ~SUNXI_HDMIAUDIOCTL_GEN;
+ writel(reg_val, sunxi_hdmiaudio.regs + SUNXI_HDMIAUDIOCTL);
+ }
}
-static int sunxi_hdmiaudio_set_fmt(struct snd_soc_dai *cpu_dai,
- unsigned int fmt)
+void sunxi_snd_rxctrl_hdmiaudio(struct snd_pcm_substream *substream, int on)
{
- return 0;
+ u32 reg_val;
+
+ //flush RX FIFO
+ reg_val = readl(sunxi_hdmiaudio.regs + SUNXI_HDMIAUDIOFCTL);
+ reg_val |= SUNXI_HDMIAUDIOFCTL_FRX;
+ writel(reg_val, sunxi_hdmiaudio.regs + SUNXI_HDMIAUDIOFCTL);
+
+ //clear RX counter
+ writel(0, sunxi_hdmiaudio.regs + SUNXI_HDMIAUDIORXCNT);
+
+ if (on) {
+ /* HDMIAUDIO RX ENABLE */
+ reg_val = readl(sunxi_hdmiaudio.regs + SUNXI_HDMIAUDIOCTL);
+ reg_val |= SUNXI_HDMIAUDIOCTL_RXEN;
+ writel(reg_val, sunxi_hdmiaudio.regs + SUNXI_HDMIAUDIOCTL);
+
+ /* enable DMA DRQ mode for record */
+ reg_val = readl(sunxi_hdmiaudio.regs + SUNXI_HDMIAUDIOINT);
+ reg_val |= SUNXI_HDMIAUDIOINT_RXDRQEN;
+ writel(reg_val, sunxi_hdmiaudio.regs + SUNXI_HDMIAUDIOINT);
+
+ //Global Enable Digital Audio Interface
+ reg_val = readl(sunxi_hdmiaudio.regs + SUNXI_HDMIAUDIOCTL);
+ reg_val |= SUNXI_HDMIAUDIOCTL_GEN;
+ writel(reg_val, sunxi_hdmiaudio.regs + SUNXI_HDMIAUDIOCTL);
+ } else {
+ /* HDMIAUDIO RX DISABLE */
+ reg_val = readl(sunxi_hdmiaudio.regs + SUNXI_HDMIAUDIOCTL);
+ reg_val &= ~SUNXI_HDMIAUDIOCTL_RXEN;
+ writel(reg_val, sunxi_hdmiaudio.regs + SUNXI_HDMIAUDIOCTL);
+
+ /* DISBALE dma DRQ mode */
+ reg_val = readl(sunxi_hdmiaudio.regs + SUNXI_HDMIAUDIOINT);
+ reg_val &= ~SUNXI_HDMIAUDIOINT_RXDRQEN;
+ writel(reg_val, sunxi_hdmiaudio.regs + SUNXI_HDMIAUDIOINT);
+
+ //Global disable Digital Audio Interface
+ reg_val = readl(sunxi_hdmiaudio.regs + SUNXI_HDMIAUDIOCTL);
+ reg_val &= ~SUNXI_HDMIAUDIOCTL_GEN;
+ writel(reg_val, sunxi_hdmiaudio.regs + SUNXI_HDMIAUDIOCTL);
+ }
}
-static int sunxi_hdmiaudio_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params,
- struct snd_soc_dai *dai)
+static int sunxi_hdmiaudio_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
{
- struct snd_soc_pcm_runtime *rtd;
- struct sunxi_dma_params *dma_data;
+ u32 reg_val;
+ u32 reg_val1;
- if (!substream) {
- printk("error:%s,line:%d\n", __func__, __LINE__);
- return -EAGAIN;
+ if (sunxi_is_sun7i())
+ return 0; /* No rx / tx control, etc. on sun7i() */
+
+ //SDO ON
+ reg_val = readl(sunxi_hdmiaudio.regs + SUNXI_HDMIAUDIOCTL);
+ reg_val |= (SUNXI_HDMIAUDIOCTL_SDO0EN | SUNXI_HDMIAUDIOCTL_SDO1EN | SUNXI_HDMIAUDIOCTL_SDO2EN | SUNXI_HDMIAUDIOCTL_SDO3EN);
+ writel(reg_val, sunxi_hdmiaudio.regs + SUNXI_HDMIAUDIOCTL);
+
+ /* master or slave selection */
+ reg_val = readl(sunxi_hdmiaudio.regs + SUNXI_HDMIAUDIOCTL);
+ switch(fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBM_CFM: /* codec clk & frm master */
+ reg_val |= SUNXI_HDMIAUDIOCTL_MS;
+ break;
+ case SND_SOC_DAIFMT_CBS_CFS: /* codec clk & frm slave */
+ reg_val &= ~SUNXI_HDMIAUDIOCTL_MS;
+ break;
+ default:
+ return -EINVAL;
+ }
+ writel(reg_val, sunxi_hdmiaudio.regs + SUNXI_HDMIAUDIOCTL);
+
+ /* pcm or hdmiaudio mode selection */
+ reg_val = readl(sunxi_hdmiaudio.regs + SUNXI_HDMIAUDIOCTL);
+ reg_val1 = readl(sunxi_hdmiaudio.regs + SUNXI_HDMIAUDIOFAT0);
+ reg_val1 &= ~SUNXI_HDMIAUDIOFAT0_FMT_RVD;
+ switch(fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S: /* I2S mode */
+ reg_val &= ~SUNXI_HDMIAUDIOCTL_PCM;
+ reg_val1 |= SUNXI_HDMIAUDIOFAT0_FMT_I2S;
+ break;
+ case SND_SOC_DAIFMT_RIGHT_J: /* Right Justified mode */
+ reg_val &= ~SUNXI_HDMIAUDIOCTL_PCM;
+ reg_val1 |= SUNXI_HDMIAUDIOFAT0_FMT_RGT;
+ break;
+ case SND_SOC_DAIFMT_LEFT_J: /* Left Justified mode */
+ reg_val &= ~SUNXI_HDMIAUDIOCTL_PCM;
+ reg_val1 |= SUNXI_HDMIAUDIOFAT0_FMT_LFT;
+ break;
+ case SND_SOC_DAIFMT_DSP_A: /* L data msb after FRM LRC */
+ reg_val |= SUNXI_HDMIAUDIOCTL_PCM;
+ reg_val1 &= ~SUNXI_HDMIAUDIOFAT0_LRCP;
+ break;
+ case SND_SOC_DAIFMT_DSP_B: /* L data msb during FRM LRC */
+ reg_val |= SUNXI_HDMIAUDIOCTL_PCM;
+ reg_val1 |= SUNXI_HDMIAUDIOFAT0_LRCP;
+ break;
+ default:
+ return -EINVAL;
}
+ writel(reg_val, sunxi_hdmiaudio.regs + SUNXI_HDMIAUDIOCTL);
+ writel(reg_val1, sunxi_hdmiaudio.regs + SUNXI_HDMIAUDIOFAT0);
+
+ /* DAI signal inversions */
+ reg_val1 = readl(sunxi_hdmiaudio.regs + SUNXI_HDMIAUDIOFAT0);
+ switch(fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF: /* normal bit clock + frame */
+ reg_val1 &= ~SUNXI_HDMIAUDIOFAT0_LRCP;
+ reg_val1 &= ~SUNXI_HDMIAUDIOFAT0_BCP;
+ break;
+ case SND_SOC_DAIFMT_NB_IF: /* normal bclk + inv frm */
+ reg_val1 |= SUNXI_HDMIAUDIOFAT0_LRCP;
+ reg_val1 &= ~SUNXI_HDMIAUDIOFAT0_BCP;
+ break;
+ case SND_SOC_DAIFMT_IB_NF: /* invert bclk + nor frm */
+ reg_val1 &= ~SUNXI_HDMIAUDIOFAT0_LRCP;
+ reg_val1 |= SUNXI_HDMIAUDIOFAT0_BCP;
+ break;
+ case SND_SOC_DAIFMT_IB_IF: /* invert bclk + frm */
+ reg_val1 |= SUNXI_HDMIAUDIOFAT0_LRCP;
+ reg_val1 |= SUNXI_HDMIAUDIOFAT0_BCP;
+ break;
+ }
+ writel(reg_val1, sunxi_hdmiaudio.regs + SUNXI_HDMIAUDIOFAT0);
+
+ /* word select size */
+ reg_val = readl(sunxi_hdmiaudio.regs + SUNXI_HDMIAUDIOFAT0);
+ reg_val &= ~SUNXI_HDMIAUDIOFAT0_WSS_32BCLK;
+ if(sunxi_hdmiaudio.ws_size == 16)
+ reg_val |= SUNXI_HDMIAUDIOFAT0_WSS_16BCLK;
+ else if(sunxi_hdmiaudio.ws_size == 20)
+ reg_val |= SUNXI_HDMIAUDIOFAT0_WSS_20BCLK;
+ else if(sunxi_hdmiaudio.ws_size == 24)
+ reg_val |= SUNXI_HDMIAUDIOFAT0_WSS_24BCLK;
+ else
+ reg_val |= SUNXI_HDMIAUDIOFAT0_WSS_32BCLK;
+ writel(reg_val, sunxi_hdmiaudio.regs + SUNXI_HDMIAUDIOFAT0);
+
+ /* PCM REGISTER setup */
+ reg_val = sunxi_hdmiaudio.pcm_txtype&0x3;
+ reg_val |= sunxi_hdmiaudio.pcm_rxtype<<2;
+
+ if(!sunxi_hdmiaudio.pcm_sync_type)
+ reg_val |= SUNXI_HDMIAUDIOFAT1_SSYNC; //short sync
+ if(sunxi_hdmiaudio.pcm_sw == 16)
+ reg_val |= SUNXI_HDMIAUDIOFAT1_SW;
+
+ reg_val |=((sunxi_hdmiaudio.pcm_start_slot - 1)&0x3)<<6; //start slot index
+
+ reg_val |= sunxi_hdmiaudio.pcm_lsb_first<<9; //MSB or LSB first
+
+ if(sunxi_hdmiaudio.pcm_sync_period == 256)
+ reg_val |= 0x4<<12;
+ else if (sunxi_hdmiaudio.pcm_sync_period == 128)
+ reg_val |= 0x3<<12;
+ else if (sunxi_hdmiaudio.pcm_sync_period == 64)
+ reg_val |= 0x2<<12;
+ else if (sunxi_hdmiaudio.pcm_sync_period == 32)
+ reg_val |= 0x1<<12;
+ writel(reg_val, sunxi_hdmiaudio.regs + SUNXI_HDMIAUDIOFAT1);
+
+ /* set FIFO control register */
+ reg_val = 0 & 0x3;
+ reg_val |= (0 & 0x1)<<2;
+ reg_val |= SUNXI_HDMIAUDIOFCTL_RXTL(0xf); //RX FIFO trigger level
+ reg_val |= SUNXI_HDMIAUDIOFCTL_TXTL(0x40); //TX FIFO empty trigger level
+ writel(reg_val, sunxi_hdmiaudio.regs + SUNXI_HDMIAUDIOFCTL);
+ return 0;
+}
- rtd = substream->private_data;
+static int sunxi_hdmiaudio_hw_params(struct snd_pcm_substream *substream,
+ 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;
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ /* play or record */
+ if(substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
dma_data = &sunxi_hdmiaudio_pcm_stereo_out;
else
- printk("error:hdmiaudio can't support capture:%s,line:%d\n",
- __func__, __LINE__);
+ dma_data = &sunxi_hdmiaudio_pcm_stereo_in;
snd_soc_dai_set_dma_data(rtd->cpu_dai, substream, dma_data);
@@ -78,7 +335,7 @@ static int sunxi_hdmiaudio_hw_params(struct snd_pcm_substream *substream,
}
static int sunxi_hdmiaudio_trigger(struct snd_pcm_substream *substream,
- int cmd, struct snd_soc_dai *dai)
+ int cmd, struct snd_soc_dai *dai)
{
int ret = 0;
struct snd_soc_pcm_runtime *rtd = substream->private_data;
@@ -89,34 +346,102 @@ static int sunxi_hdmiaudio_trigger(struct snd_pcm_substream *substream,
return 0; /* No rx / tx control, etc. on sun7i() */
switch (cmd) {
- case SNDRV_PCM_TRIGGER_START:
- case SNDRV_PCM_TRIGGER_RESUME:
- case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
- sunxi_snd_txctrl_hdmiaudio(substream, 1);
- sunxi_dma_started(dma_data);
- break;
- case SNDRV_PCM_TRIGGER_STOP:
- case SNDRV_PCM_TRIGGER_SUSPEND:
- case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
- sunxi_snd_txctrl_hdmiaudio(substream, 0);
- break;
- default:
- ret = -EINVAL;
- break;
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+ sunxi_snd_rxctrl_hdmiaudio(substream, 1);
+ } else {
+ sunxi_snd_txctrl_hdmiaudio(substream, 1);
+ }
+ sunxi_dma_started(dma_data);
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+ sunxi_snd_rxctrl_hdmiaudio(substream, 0);
+ } else {
+ sunxi_snd_txctrl_hdmiaudio(substream, 0);
+ }
+ break;
+ default:
+ ret = -EINVAL;
+ break;
}
return ret;
}
-/* freq: 1: 22.5792MHz 0: 24.576MHz */
+//freq: 1: 22.5792MHz 0: 24.576MHz
static int sunxi_hdmiaudio_set_sysclk(struct snd_soc_dai *cpu_dai, int clk_id,
- unsigned int freq, int dir)
+ unsigned int freq, int dir)
{
+ if (sunxi_is_sun7i())
+ return 0; /* No rx / tx control, etc. on sun7i() */
+
+ if (!freq) {
+ clk_set_rate(hdmiaudio_pll2clk, 24576000);
+ } else {
+ clk_set_rate(hdmiaudio_pll2clk, 22579200);
+ }
+
return 0;
}
-static int sunxi_hdmiaudio_set_clkdiv(struct snd_soc_dai *cpu_dai, int div_id,
- int div)
+static int sunxi_hdmiaudio_set_clkdiv(struct snd_soc_dai *cpu_dai, int div_id, int div)
{
+ u32 reg;
+
+ if (sunxi_is_sun7i())
+ return 0; /* No rx / tx control, etc. on sun7i() */
+
+ switch (div_id) {
+ case SUNXI_DIV_MCLK:
+ if(div <= 8)
+ div = (div >>1);
+ else if(div == 12)
+ div = 0x5;
+ else if(div == 16)
+ div = 0x6;
+ else if(div == 24)
+ div = 0x7;
+ else if(div == 32)
+ div = 0x8;
+ else if(div == 48)
+ div = 0x9;
+ else if(div == 64)
+ div = 0xa;
+ reg = (readl(sunxi_hdmiaudio.regs + SUNXI_HDMIAUDIOCLKD) & ~SUNXI_HDMIAUDIOCLKD_MCLK_MASK) | (div << SUNXI_HDMIAUDIOCLKD_MCLK_OFFS);
+ writel(reg, sunxi_hdmiaudio.regs + SUNXI_HDMIAUDIOCLKD);
+ break;
+ case SUNXI_DIV_BCLK:
+ if(div <= 8)
+ div = (div>>1) - 1;
+ else if(div == 12)
+ div = 0x4;
+ else if(div == 16)
+ div = 0x5;
+ else if(div == 32)
+ div = 0x6;
+ else if(div == 64)
+ div = 0x7;
+ reg = (readl(sunxi_hdmiaudio.regs + SUNXI_HDMIAUDIOCLKD) & ~SUNXI_HDMIAUDIOCLKD_BCLK_MASK) | (div <<SUNXI_HDMIAUDIOCLKD_BCLK_OFFS);
+ writel(reg, sunxi_hdmiaudio.regs + SUNXI_HDMIAUDIOCLKD);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ //diable MCLK output when high samplerate
+ reg = readl(sunxi_hdmiaudio.regs + SUNXI_HDMIAUDIOCLKD);
+ if(!(reg & 0xF)) {
+ reg &= ~SUNXI_HDMIAUDIOCLKD_MCLKOEN;
+ writel(reg, sunxi_hdmiaudio.regs + SUNXI_HDMIAUDIOCLKD);
+ } else {
+ reg |= SUNXI_HDMIAUDIOCLKD_MCLKOEN;
+ writel(reg, sunxi_hdmiaudio.regs + SUNXI_HDMIAUDIOCLKD);
+ }
+
return 0;
}
@@ -135,78 +460,205 @@ static int sunxi_hdmiaudio_dai_remove(struct snd_soc_dai *dai)
return 0;
}
+static void hdmiaudioregsave(void)
+{
+ regsave[0] = readl(sunxi_hdmiaudio.regs + SUNXI_HDMIAUDIOCTL);
+ regsave[1] = readl(sunxi_hdmiaudio.regs + SUNXI_HDMIAUDIOFAT0);
+ regsave[2] = readl(sunxi_hdmiaudio.regs + SUNXI_HDMIAUDIOFAT1);
+ regsave[3] = readl(sunxi_hdmiaudio.regs + SUNXI_HDMIAUDIOFCTL) | (0x3<<24);
+ regsave[4] = readl(sunxi_hdmiaudio.regs + SUNXI_HDMIAUDIOINT);
+ regsave[5] = readl(sunxi_hdmiaudio.regs + SUNXI_HDMIAUDIOCLKD);
+ regsave[6] = readl(sunxi_hdmiaudio.regs + SUNXI_TXCHSEL);
+ regsave[7] = readl(sunxi_hdmiaudio.regs + SUNXI_TXCHMAP);
+}
+
+static void hdmiaudioregrestore(void)
+{
+ writel(regsave[0], sunxi_hdmiaudio.regs + SUNXI_HDMIAUDIOCTL);
+ writel(regsave[1], sunxi_hdmiaudio.regs + SUNXI_HDMIAUDIOFAT0);
+ writel(regsave[2], sunxi_hdmiaudio.regs + SUNXI_HDMIAUDIOFAT1);
+ writel(regsave[3], sunxi_hdmiaudio.regs + SUNXI_HDMIAUDIOFCTL);
+ writel(regsave[4], sunxi_hdmiaudio.regs + SUNXI_HDMIAUDIOINT);
+ writel(regsave[5], sunxi_hdmiaudio.regs + SUNXI_HDMIAUDIOCLKD);
+ writel(regsave[6], sunxi_hdmiaudio.regs + SUNXI_TXCHSEL);
+ writel(regsave[7], sunxi_hdmiaudio.regs + SUNXI_TXCHMAP);
+}
+
static int sunxi_hdmiaudio_suspend(struct snd_soc_dai *cpu_dai)
{
- printk("[HDMIAUDIO]Entered %s\n", __func__);
+ u32 reg_val;
+
+ if (sunxi_is_sun7i())
+ return 0; /* No rx / tx control, etc. on sun7i() */
- /*
- * printk("[HDMIAUDIO]PLL2 0x01c20008 = %#x, line = %d\n",
- * *(volatile int *)0xF1C20008, __LINE__);
- */
- printk("[HDMIAUDIO]SPECIAL CLK 0x01c20068 = %#x, line= %d\n",
- *(volatile int *)0xF1C20068, __LINE__);
- printk("[HDMIAUDIO]SPECIAL CLK 0x01c200B8 = %#x, line = %d\n",
- *(volatile int *)0xF1C200B8, __LINE__);
+ printk("[HDMIAUDIO]Entered %s\n", __func__);
+
+ //Global Enable Digital Audio Interface
+ reg_val = readl(sunxi_hdmiaudio.regs + SUNXI_HDMIAUDIOCTL);
+ reg_val &= ~SUNXI_HDMIAUDIOCTL_GEN;
+ writel(reg_val, sunxi_hdmiaudio.regs + SUNXI_HDMIAUDIOCTL);
+
+ hdmiaudioregsave();
+ //release the module clock
+ clk_disable(hdmiaudio_moduleclk);
+
+ clk_disable(hdmiaudio_apbclk);
+
+ //printk("[HDMIAUDIO]PLL2 0x01c20008 = %#x, line = %d\n", *(volatile int*)0xF1C20008, __LINE__);
+ printk("[HDMIAUDIO]SPECIAL CLK 0x01c20068 = %#x, line= %d\n", *(volatile int*)0xF1C20068, __LINE__);
+ printk("[HDMIAUDIO]SPECIAL CLK 0x01c200B8 = %#x, line = %d\n", *(volatile int*)0xF1C200B8, __LINE__);
return 0;
}
static int sunxi_hdmiaudio_resume(struct snd_soc_dai *cpu_dai)
{
+ u32 reg_val;
+
+ if (sunxi_is_sun7i())
+ return 0; /* No rx / tx control, etc. on sun7i() */
+
printk("[HDMIAUDIO]Entered %s\n", __func__);
- /*
- * printk("[HDMIAUDIO]PLL2 0x01c20008 = %#x, line = %d\n",
- * *(volatile int *)0xF1C20008, __LINE__);
- */
- printk("[HDMIAUDIO]SPECIAL CLK 0x01c20068 = %#x, line= %d\n",
- *(volatile int *)0xF1C20068, __LINE__);
- printk("[HDMIAUDIO]SPECIAL CLK 0x01c200B8 = %#x, line = %d\n",
- *(volatile int *)0xF1C200B8, __LINE__);
+ //release the module clock
+ clk_enable(hdmiaudio_apbclk);
+
+ //release the module clock
+ clk_enable(hdmiaudio_moduleclk);
+
+ hdmiaudioregrestore();
+
+ //Global Enable Digital Audio Interface
+ reg_val = readl(sunxi_hdmiaudio.regs + SUNXI_HDMIAUDIOCTL);
+ reg_val |= SUNXI_HDMIAUDIOCTL_GEN;
+ writel(reg_val, sunxi_hdmiaudio.regs + SUNXI_HDMIAUDIOCTL);
+
+ //printk("[HDMIAUDIO]PLL2 0x01c20008 = %#x, line = %d\n", *(volatile int*)0xF1C20008, __LINE__);
+ printk("[HDMIAUDIO]SPECIAL CLK 0x01c20068 = %#x, line= %d\n", *(volatile int*)0xF1C20068, __LINE__);
+ printk("[HDMIAUDIO]SPECIAL CLK 0x01c200B8 = %#x, line = %d\n", *(volatile int*)0xF1C200B8, __LINE__);
return 0;
}
-#define SUNXI_HDMI_RATES (SNDRV_PCM_RATE_8000_192000 | SNDRV_PCM_RATE_KNOT)
+#define SUNXI_I2S_RATES (SNDRV_PCM_RATE_8000_192000 | SNDRV_PCM_RATE_KNOT)
static struct snd_soc_dai_ops sunxi_hdmiaudio_dai_ops = {
- .trigger = sunxi_hdmiaudio_trigger,
- .hw_params = sunxi_hdmiaudio_hw_params,
- .set_fmt = sunxi_hdmiaudio_set_fmt,
- .set_clkdiv = sunxi_hdmiaudio_set_clkdiv,
- .set_sysclk = sunxi_hdmiaudio_set_sysclk,
+ .trigger = sunxi_hdmiaudio_trigger,
+ .hw_params = sunxi_hdmiaudio_hw_params,
+ .set_fmt = sunxi_hdmiaudio_set_fmt,
+ .set_clkdiv = sunxi_hdmiaudio_set_clkdiv,
+ .set_sysclk = sunxi_hdmiaudio_set_sysclk,
};
static struct snd_soc_dai_driver sunxi_hdmiaudio_dai = {
-
- .probe = sunxi_hdmiaudio_dai_probe,
- .suspend = sunxi_hdmiaudio_suspend,
- .resume = sunxi_hdmiaudio_resume,
- .remove = sunxi_hdmiaudio_dai_remove,
- .playback = {
- .channels_min = 1,
- .channels_max = 2,
- .rates = SUNXI_HDMI_RATES,
- .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE,
+ .probe = sunxi_hdmiaudio_dai_probe,
+ .suspend = sunxi_hdmiaudio_suspend,
+ .resume = sunxi_hdmiaudio_resume,
+ .remove = sunxi_hdmiaudio_dai_remove,
+ .playback = {
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SUNXI_I2S_RATES,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE
},
- .symmetric_rates = 1,
- .ops = &sunxi_hdmiaudio_dai_ops,
+ .capture = {
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SUNXI_I2S_RATES,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE
+ },
+ .symmetric_rates = 1,
+ .ops = &sunxi_hdmiaudio_dai_ops,
};
static int __devinit sunxi_hdmiaudio_dev_probe(struct platform_device *pdev)
{
- return snd_soc_register_dai(&pdev->dev, &sunxi_hdmiaudio_dai);
+ int reg_val = 0;
+ int ret = 0;
+
+ if (sunxi_is_sun7i()) {
+ /* No rx / tx control, etc. on sun7i() */
+ return snd_soc_register_dai(&pdev->dev, &sunxi_hdmiaudio_dai);
+ }
+
+ sunxi_hdmiaudio.regs = ioremap(SUNXI_HDMIAUDIOBASE, 0x100);
+ if (sunxi_hdmiaudio.regs == NULL)
+ return -ENXIO;
+
+ sunxi_hdmiaudio.ccmregs = ioremap(SUNXI_CCMBASE, 0x100);
+ if (sunxi_hdmiaudio.ccmregs == NULL)
+ return -ENXIO;
+
+ sunxi_hdmiaudio.ioregs = ioremap(0x01C20800, 0x100);
+ if (sunxi_hdmiaudio.ioregs == NULL)
+ return -ENXIO;
+
+ //hdmiaudio apbclk
+ hdmiaudio_apbclk = clk_get(NULL, "apb_i2s");
+ if(-1 == clk_enable(hdmiaudio_apbclk)){
+ printk("hdmiaudio_apbclk failed! line = %d\n", __LINE__);
+ }
+
+ hdmiaudio_pllx8 = clk_get(NULL, "audio_pllx8");
+
+ //hdmiaudio pll2clk
+ hdmiaudio_pll2clk = clk_get(NULL, "audio_pll");
+
+ //hdmiaudio module clk
+ hdmiaudio_moduleclk = clk_get(NULL, "i2s");
+
+ if(clk_set_parent(hdmiaudio_moduleclk, hdmiaudio_pll2clk)){
+ printk("try to set parent of hdmiaudio_moduleclk to hdmiaudio_pll2ck failed! line = %d\n",__LINE__);
+ }
+
+
+ if(clk_set_rate(hdmiaudio_moduleclk, 24576000/8)){
+ printk("set hdmiaudio_moduleclk clock freq to 24576000 failed! line = %d\n", __LINE__);
+ }
+
+
+ if(-1 == clk_enable(hdmiaudio_moduleclk)){
+ printk("open hdmiaudio_moduleclk failed! line = %d\n", __LINE__);
+ }
+
+ reg_val = readl(sunxi_hdmiaudio.regs + SUNXI_HDMIAUDIOCTL);
+ reg_val |= SUNXI_HDMIAUDIOCTL_GEN;
+ writel(reg_val, sunxi_hdmiaudio.regs + SUNXI_HDMIAUDIOCTL);
+
+ ret = snd_soc_register_dai(&pdev->dev, &sunxi_hdmiaudio_dai);
+
+ iounmap(sunxi_hdmiaudio.ioregs);
+
+ return 0;
}
static int __devexit sunxi_hdmiaudio_dev_remove(struct platform_device *pdev)
{
+ if (sunxi_is_sun7i()) {
+ /* No rx / tx control, etc. on sun7i() */
+ snd_soc_unregister_dai(&pdev->dev);
+ return 0;
+ }
+
+ //release the module clock
+ clk_disable(hdmiaudio_moduleclk);
+
+ //release pllx8clk
+ clk_put(hdmiaudio_pllx8);
+
+ //release pll2clk
+ clk_put(hdmiaudio_pll2clk);
+
+ //release apbclk
+ clk_put(hdmiaudio_apbclk);
+
snd_soc_unregister_dai(&pdev->dev);
platform_set_drvdata(pdev, NULL);
return 0;
}
static struct platform_driver sunxi_hdmiaudio_driver = {
- .probe = sunxi_hdmiaudio_dev_probe,
- .remove = __devexit_p(sunxi_hdmiaudio_dev_remove),
- .driver = {
+ .probe = sunxi_hdmiaudio_dev_probe,
+ .remove = __devexit_p(sunxi_hdmiaudio_dev_remove),
+ .driver = {
.name = "sunxi-hdmiaudio",
.owner = THIS_MODULE,
},
@@ -216,8 +668,7 @@ static int __init sunxi_hdmiaudio_init(void)
{
int err = 0;
- err = platform_driver_register(&sunxi_hdmiaudio_driver);
- if (err < 0)
+ if ((err = platform_driver_register(&sunxi_hdmiaudio_driver)) < 0)
return err;
return 0;
diff --git a/sound/soc/sunxi/hdmiaudio/sunxi-hdmiaudio.h b/sound/soc/sunxi/hdmiaudio/sunxi-hdmiaudio.h
new file mode 100644
index 0000000..9f4a0cc
--- /dev/null
+++ b/sound/soc/sunxi/hdmiaudio/sunxi-hdmiaudio.h
@@ -0,0 +1,303 @@
+/*
+ * sound\soc\sunxi\hdmiaudio\sunxi-hdmiaudio.h
+ * (C) Copyright 2007-2011
+ * Allwinner Technology Co., Ltd. <www.allwinnertech.com>
+ * chenpailin <chenpailin@allwinnertech.com>
+ *
+ * some simple description for this code
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ */
+#ifndef SUNXI_HDMIAUIDO_H_
+#define SUNXI_HDMIAUIDO_H_
+#include <linux/drv_hdmi.h>
+
+/*------------------------------------------------------------*/
+/* REGISTER definition */
+
+/* HDMIAUDIO REGISTER */
+#define SUNXI_HDMIAUDIOBASE (0x01C22400)
+
+#define SUNXI_HDMIAUDIOCTL (0x00)
+ #define SUNXI_HDMIAUDIOCTL_SDO3EN (1<<11)
+ #define SUNXI_HDMIAUDIOCTL_SDO2EN (1<<10)
+ #define SUNXI_HDMIAUDIOCTL_SDO1EN (1<<9)
+ #define SUNXI_HDMIAUDIOCTL_SDO0EN (1<<8)
+ #define SUNXI_HDMIAUDIOCTL_ASS (1<<6)
+ #define SUNXI_HDMIAUDIOCTL_MS (1<<5)
+ #define SUNXI_HDMIAUDIOCTL_PCM (1<<4)
+ #define SUNXI_HDMIAUDIOCTL_LOOP (1<<3)
+ #define SUNXI_HDMIAUDIOCTL_TXEN (1<<2)
+ #define SUNXI_HDMIAUDIOCTL_RXEN (1<<1)
+ #define SUNXI_HDMIAUDIOCTL_GEN (1<<0)
+
+#define SUNXI_HDMIAUDIOFAT0 (0x04)
+ #define SUNXI_HDMIAUDIOFAT0_LRCP (1<<7)
+ #define SUNXI_HDMIAUDIOFAT0_BCP (1<<6)
+ #define SUNXI_HDMIAUDIOFAT0_SR_RVD (3<<4)
+ #define SUNXI_HDMIAUDIOFAT0_SR_16BIT (0<<4)
+ #define SUNXI_HDMIAUDIOFAT0_SR_20BIT (1<<4)
+ #define SUNXI_HDMIAUDIOFAT0_SR_24BIT (2<<4)
+ #define SUNXI_HDMIAUDIOFAT0_WSS_16BCLK (0<<2)
+ #define SUNXI_HDMIAUDIOFAT0_WSS_20BCLK (1<<2)
+ #define SUNXI_HDMIAUDIOFAT0_WSS_24BCLK (2<<2)
+ #define SUNXI_HDMIAUDIOFAT0_WSS_32BCLK (3<<2)
+ #define SUNXI_HDMIAUDIOFAT0_FMT_I2S (0<<0)
+ #define SUNXI_HDMIAUDIOFAT0_FMT_LFT (1<<0)
+ #define SUNXI_HDMIAUDIOFAT0_FMT_RGT (2<<0)
+ #define SUNXI_HDMIAUDIOFAT0_FMT_RVD (3<<0)
+
+#define SUNXI_HDMIAUDIOFAT1 (0x08)
+ #define SUNXI_HDMIAUDIOFAT1_SYNCLEN_16BCLK (0<<12)
+ #define SUNXI_HDMIAUDIOFAT1_SYNCLEN_32BCLK (1<<12)
+ #define SUNXI_HDMIAUDIOFAT1_SYNCLEN_64BCLK (2<<12)
+ #define SUNXI_HDMIAUDIOFAT1_SYNCLEN_128BCLK (3<<12)
+ #define SUNXI_HDMIAUDIOFAT1_SYNCLEN_256BCLK (4<<12)
+ #define SUNXI_HDMIAUDIOFAT1_SYNCOUTEN (1<<11)
+ #define SUNXI_HDMIAUDIOFAT1_OUTMUTE (1<<10)
+ #define SUNXI_HDMIAUDIOFAT1_MLS (1<<9)
+ #define SUNXI_HDMIAUDIOFAT1_SEXT (1<<8)
+ #define SUNXI_HDMIAUDIOFAT1_SI_1ST (0<<6)
+ #define SUNXI_HDMIAUDIOFAT1_SI_2ND (1<<6)
+ #define SUNXI_HDMIAUDIOFAT1_SI_3RD (2<<6)
+ #define SUNXI_HDMIAUDIOFAT1_SI_4TH (3<<6)
+ #define SUNXI_HDMIAUDIOFAT1_SW (1<<5)
+ #define SUNXI_HDMIAUDIOFAT1_SSYNC (1<<4)
+ #define SUNXI_HDMIAUDIOFAT1_RXPDM_16PCM (0<<2)
+ #define SUNXI_HDMIAUDIOFAT1_RXPDM_8PCM (1<<2)
+ #define SUNXI_HDMIAUDIOFAT1_RXPDM_8ULAW (2<<2)
+ #define SUNXI_HDMIAUDIOFAT1_RXPDM_8ALAW (3<<2)
+ #define SUNXI_HDMIAUDIOFAT1_TXPDM_16PCM (0<<0)
+ #define SUNXI_HDMIAUDIOFAT1_TXPDM_8PCM (1<<0)
+ #define SUNXI_HDMIAUDIOFAT1_TXPDM_8ULAW (2<<0)
+ #define SUNXI_HDMIAUDIOFAT1_TXPDM_8ALAW (3<<0)
+
+#define SUNXI_HDMIAUDIOTXFIFO (0x0C)
+
+#define SUNXI_HDMIAUDIORXFIFO (0x10)
+
+#define SUNXI_HDMIAUDIOFCTL (0x14)
+ #define SUNXI_HDMIAUDIOFCTL_FIFOSRC (1<<31)
+ #define SUNXI_HDMIAUDIOFCTL_FTX (1<<25)
+ #define SUNXI_HDMIAUDIOFCTL_FRX (1<<24)
+ #define SUNXI_HDMIAUDIOFCTL_TXTL(v) ((v)<<12)
+ #define SUNXI_HDMIAUDIOFCTL_RXTL(v) ((v)<<4)
+ #define SUNXI_HDMIAUDIOFCTL_TXIM_MOD0 (0<<2)
+ #define SUNXI_HDMIAUDIOFCTL_TXIM_MOD1 (1<<2)
+ #define SUNXI_HDMIAUDIOFCTL_RXOM_MOD0 (0<<0)
+ #define SUNXI_HDMIAUDIOFCTL_RXOM_MOD1 (1<<0)
+ #define SUNXI_HDMIAUDIOFCTL_RXOM_MOD2 (2<<0)
+ #define SUNXI_HDMIAUDIOFCTL_RXOM_MOD3 (3<<0)
+
+#define SUNXI_HDMIAUDIOFSTA (0x18)
+ #define SUNXI_HDMIAUDIOFSTA_TXE (1<<28)
+ #define SUNXI_HDMIAUDIOFSTA_TXECNT(v) ((v)<<16)
+ #define SUNXI_HDMIAUDIOFSTA_RXA (1<<8)
+ #define SUNXI_HDMIAUDIOFSTA_RXACNT(v) ((v)<<0)
+
+#define SUNXI_HDMIAUDIOINT (0x1C)
+ #define SUNXI_HDMIAUDIOINT_TXDRQEN (1<<7)
+ #define SUNXI_HDMIAUDIOINT_TXUIEN (1<<6)
+ #define SUNXI_HDMIAUDIOINT_TXOIEN (1<<5)
+ #define SUNXI_HDMIAUDIOINT_TXEIEN (1<<4)
+ #define SUNXI_HDMIAUDIOINT_RXDRQEN (1<<2)
+ #define SUNXI_HDMIAUDIOINT_RXOIEN (1<<1)
+ #define SUNXI_HDMIAUDIOINT_RXAIEN (1<<0)
+
+#define SUNXI_HDMIAUDIOISTA (0x20)
+ #define SUNXI_HDMIAUDIOISTA_TXUISTA (1<<6)
+ #define SUNXI_HDMIAUDIOISTA_TXOISTA (1<<5)
+ #define SUNXI_HDMIAUDIOISTA_TXEISTA (1<<4)
+ #define SUNXI_HDMIAUDIOISTA_RXOISTA (1<<1)
+ #define SUNXI_HDMIAUDIOISTA_RXAISTA (1<<0)
+
+#define SUNXI_HDMIAUDIOCLKD (0x24)
+ #define SUNXI_HDMIAUDIOCLKD_MCLKOEN (1<<7)
+ #define SUNXI_HDMIAUDIOCLKD_BCLKDIV_2 (0<<4)
+ #define SUNXI_HDMIAUDIOCLKD_BCLKDIV_4 (1<<4)
+ #define SUNXI_HDMIAUDIOCLKD_BCLKDIV_6 (2<<4)
+ #define SUNXI_HDMIAUDIOCLKD_BCLKDIV_8 (3<<4)
+ #define SUNXI_HDMIAUDIOCLKD_BCLKDIV_12 (4<<4)
+ #define SUNXI_HDMIAUDIOCLKD_BCLKDIV_16 (5<<4)
+ #define SUNXI_HDMIAUDIOCLKD_BCLKDIV_32 (6<<4)
+ #define SUNXI_HDMIAUDIOCLKD_BCLKDIV_64 (7<<4)
+ #define SUNXI_HDMIAUDIOCLKD_MCLKDIV_1 (0<<0)
+ #define SUNXI_HDMIAUDIOCLKD_MCLKDIV_2 (1<<0)
+ #define SUNXI_HDMIAUDIOCLKD_MCLKDIV_4 (2<<0)
+ #define SUNXI_HDMIAUDIOCLKD_MCLKDIV_6 (3<<0)
+ #define SUNXI_HDMIAUDIOCLKD_MCLKDIV_8 (4<<0)
+ #define SUNXI_HDMIAUDIOCLKD_MCLKDIV_12 (5<<0)
+ #define SUNXI_HDMIAUDIOCLKD_MCLKDIV_16 (6<<0)
+ #define SUNXI_HDMIAUDIOCLKD_MCLKDIV_24 (7<<0)
+ #define SUNXI_HDMIAUDIOCLKD_MCLKDIV_32 (8<<0)
+ #define SUNXI_HDMIAUDIOCLKD_MCLKDIV_48 (9<<0)
+ #define SUNXI_HDMIAUDIOCLKD_MCLKDIV_64 (10<<0)
+
+#define SUNXI_HDMIAUDIOTXCNT (0x28)
+
+#define SUNXI_HDMIAUDIORXCNT (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)
+
+
+/* CCM REGISTER */
+#define SUNXI_CCMBASE (0x01C20000)
+
+#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_AUDIO_CLK_REG (0xb8)
+ #define SUNXI_CCM_AUDIO_CLK_REG_IISSPECIALGATE (1<<31)
+ #define SUNXI_CCM_AUDIO_CLK_REG_DIV(v) ((v)<<16)
+/*------------------------------------------------------------*/
+
+/*------------------------------------------------------------*/
+/* Clock dividers */
+#define SUNXI_DIV_MCLK 0
+#define SUNXI_DIV_BCLK 1
+
+#define SUNXI_HDMIAUDIOCLKD_MCLK_MASK 0x0f
+#define SUNXI_HDMIAUDIOCLKD_MCLK_OFFS 0
+#define SUNXI_HDMIAUDIOCLKD_BCLK_MASK 0x070
+#define SUNXI_HDMIAUDIOCLKD_BCLK_OFFS 4
+#define SUNXI_HDMIAUDIOCLKD_MCLKEN_OFFS 7
+
+unsigned int sunxi_hdmiaudio_get_clockrate(void);
+extern struct sunxi_hdmiaudio_info sunxi_hdmiaudio;
+
+extern void sunxi_snd_txctrl_hdmiaudio(struct snd_pcm_substream *substream, int on);
+extern void sunxi_snd_rxctrl_hdmiaudio(struct snd_pcm_substream *substream, int on);
+
+struct sunxi_hdmiaudio_info {
+ 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 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 mclk_rate; //mclk frequency divide by fs (128fs, 192fs, 256fs, 384fs, 512fs, 768fs)
+ 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)
+
+};
+
+extern struct sunxi_hdmiaudio_info sunxi_hdmiaudio;
+#endif
diff --git a/sound/soc/sunxi/hdmiaudio/sunxi-hdmipcm.c b/sound/soc/sunxi/hdmiaudio/sunxi-hdmipcm.c
index 4916b51..91004e3 100644
--- a/sound/soc/sunxi/hdmiaudio/sunxi-hdmipcm.c
+++ b/sound/soc/sunxi/hdmiaudio/sunxi-hdmipcm.c
@@ -29,30 +29,29 @@
#include <mach/hardware.h>
#include <plat/dma_compat.h>
-static volatile unsigned int dmasrc;
-static volatile unsigned int dmadst;
+#include "sunxi-hdmiaudio.h"
+#include "sunxi-hdmipcm.h"
+
+static volatile unsigned int dmasrc = 0;
+static volatile unsigned int dmadst = 0;
static const struct snd_pcm_hardware sunxi_pcm_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,
+ .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_S32_LE,
- .rates = SNDRV_PCM_RATE_8000_192000 |
- SNDRV_PCM_RATE_KNOT,
+ 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*4,
- .period_bytes_max = 1024*32,
- .periods_min = 4,
- .periods_max = 8,
- .fifo_size = 128,
+ .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,//32,
};
struct sunxi_runtime_data {
@@ -75,19 +74,23 @@ static void sunxi_pcm_enqueue(struct snd_pcm_substream *substream)
int ret;
unsigned long len = prtd->dma_period;
- limit = prtd->dma_limit;
- while (prtd->dma_loaded < limit) {
- if ((pos + len) > prtd->dma_end)
- len = prtd->dma_end - pos;
+ limit = prtd->dma_limit;
+ 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) {
prtd->dma_loaded++;
pos += prtd->dma_period;
- if (pos >= prtd->dma_end)
+ if(pos >= prtd->dma_end)
pos = prtd->dma_start;
- } else
+ }else {
break;
+ }
+
}
prtd->dma_pos = pos;
}
@@ -98,8 +101,9 @@ static void sunxi_audio_buffdone(struct sunxi_dma_params *dma, void *dev_id)
struct snd_pcm_substream *substream = dev_id;
prtd = substream->runtime->private_data;
- if (substream)
- snd_pcm_period_elapsed(substream);
+ if (substream) {
+ snd_pcm_period_elapsed(substream);
+ }
spin_lock(&prtd->lock);
{
@@ -126,12 +130,13 @@ static int sunxi_pcm_hw_params(struct snd_pcm_substream *substream,
if (prtd->params == NULL) {
prtd->params = dma;
ret = sunxi_dma_request(prtd->params, 1);
- if (ret < 0)
- return ret;
+ if (ret < 0) {
+ return ret;
+ }
}
if (sunxi_dma_set_callback(prtd->params, sunxi_audio_buffdone,
- substream) != 0) {
+ substream) != 0) {
sunxi_dma_release(prtd->params);
prtd->params = NULL;
return -EINVAL;
@@ -178,25 +183,25 @@ static int sunxi_pcm_prepare(struct snd_pcm_substream *substream)
if (!prtd->params)
return 0;
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK){
#if defined CONFIG_ARCH_SUN4I || defined CONFIG_ARCH_SUN5I
struct dma_hw_conf codec_dma_conf;
- codec_dma_conf.drqsrc_type = DRQ_TYPE_SDRAM;
- codec_dma_conf.drqdst_type = DRQ_TYPE_HDMIAUDIO;
- codec_dma_conf.xfer_type = DMAXFER_D_BWORD_S_BWORD;
- codec_dma_conf.address_type = DMAADDRT_D_IO_S_LN;
- codec_dma_conf.dir = SW_DMA_WDEV;
- codec_dma_conf.reload = 0;
- codec_dma_conf.hf_irq = SW_DMA_IRQ_FULL;
- codec_dma_conf.from = prtd->dma_start;
- codec_dma_conf.to = prtd->params->dma_addr;
+ codec_dma_conf.drqsrc_type = DRQ_TYPE_SDRAM;
+ codec_dma_conf.drqdst_type = DRQ_TYPE_HDMIAUDIO;
+ codec_dma_conf.xfer_type = DMAXFER_D_BWORD_S_BWORD;
+ codec_dma_conf.address_type = DMAADDRT_D_IO_S_LN;
+ codec_dma_conf.dir = SW_DMA_WDEV;
+ codec_dma_conf.reload = 0;
+ codec_dma_conf.hf_irq = SW_DMA_IRQ_FULL;
+ codec_dma_conf.from = prtd->dma_start;
+ codec_dma_conf.to = prtd->params->dma_addr;
#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_32BIT;
- codec_dma_conf.xfer_type.src_bst_len = DATA_BRST_4;
+ codec_dma_conf.xfer_type.src_bst_len = DATA_BRST_4;
codec_dma_conf.xfer_type.dst_data_width = DATA_WIDTH_32BIT;
- codec_dma_conf.xfer_type.dst_bst_len = DATA_BRST_4;
+ codec_dma_conf.xfer_type.dst_bst_len = DATA_BRST_4;
codec_dma_conf.address_type.src_addr_mode = DDMA_ADDR_LINEAR;
codec_dma_conf.address_type.dst_addr_mode = DDMA_ADDR_IO;
codec_dma_conf.src_drq_type = D_SRC_SDRAM;
@@ -210,8 +215,8 @@ static int sunxi_pcm_prepare(struct snd_pcm_substream *substream)
/* flush the DMA channel */
prtd->dma_loaded = 0;
- if (sunxi_dma_flush(prtd->params) == 0)
- prtd->dma_pos = prtd->dma_start;
+ sunxi_dma_flush(prtd->params);
+ prtd->dma_pos = prtd->dma_start;
/* enqueue dma buffers */
sunxi_pcm_enqueue(substream);
@@ -258,19 +263,21 @@ static snd_pcm_uframes_t sunxi_pcm_pointer(struct snd_pcm_substream *substream)
snd_pcm_uframes_t offset = 0;
spin_lock(&prtd->lock);
- sunxi_dma_getcurposition(prtd->params, (dma_addr_t *)&dmasrc,
- (dma_addr_t *)&dmadst);
+
+ 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;
else
- offset = bytes_to_frames(runtime, dmasrc + prtd->dma_period -
- runtime->dma_addr);
+ {
+ offset = bytes_to_frames(runtime, dmasrc + prtd->dma_period - runtime->dma_addr);
+ }
spin_unlock(&prtd->lock);
- if (offset >= runtime->buffer_size)
+ if(offset >= runtime->buffer_size)
offset = 0;
- return offset;
+ return offset;
}
static int sunxi_pcm_open(struct snd_pcm_substream *substream)
@@ -307,21 +314,21 @@ static int sunxi_pcm_mmap(struct snd_pcm_substream *substream,
struct snd_pcm_runtime *runtime = substream->runtime;
return dma_mmap_writecombine(substream->pcm->card->dev, vma,
- runtime->dma_area,
- runtime->dma_addr,
- runtime->dma_bytes);
+ runtime->dma_area,
+ runtime->dma_addr,
+ runtime->dma_bytes);
}
static struct snd_pcm_ops sunxi_pcm_ops = {
- .open = sunxi_pcm_open,
+ .open = sunxi_pcm_open,
.close = sunxi_pcm_close,
.ioctl = snd_pcm_lib_ioctl,
- .hw_params = sunxi_pcm_hw_params,
+ .hw_params = sunxi_pcm_hw_params,
.hw_free = sunxi_pcm_hw_free,
.prepare = sunxi_pcm_prepare,
.trigger = sunxi_pcm_trigger,
.pointer = sunxi_pcm_pointer,
- .mmap = sunxi_pcm_mmap,
+ .mmap = sunxi_pcm_mmap,
};
static int sunxi_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
@@ -334,7 +341,7 @@ static int sunxi_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
buf->dev.dev = pcm->card->dev;
buf->private_data = NULL;
buf->area = dma_alloc_writecombine(pcm->card->dev, size,
- &buf->addr, GFP_KERNEL);
+ &buf->addr, GFP_KERNEL);
if (!buf->area)
return -ENOMEM;
buf->bytes = size;
@@ -343,9 +350,9 @@ static int sunxi_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
static void sunxi_pcm_free_dma_buffers(struct snd_pcm *pcm)
{
- int stream;
- struct snd_dma_buffer *buf;
struct snd_pcm_substream *substream;
+ struct snd_dma_buffer *buf;
+ int stream;
for (stream = 0; stream < 2; stream++) {
substream = pcm->streams[stream].substream;
@@ -357,7 +364,7 @@ static void sunxi_pcm_free_dma_buffers(struct snd_pcm *pcm)
continue;
dma_free_writecombine(pcm->card->dev, buf->bytes,
- buf->area, buf->addr);
+ buf->area, buf->addr);
buf->area = NULL;
}
}
@@ -366,9 +373,9 @@ static u64 sunxi_pcm_mask = DMA_BIT_MASK(32);
static int sunxi_pcm_new(struct snd_soc_pcm_runtime *rtd)
{
+ struct snd_card *card = rtd->card->snd_card;
+ struct snd_pcm *pcm = rtd->pcm;
int ret = 0;
- struct snd_pcm *pcm = rtd->pcm;
- struct snd_card *card = rtd->card->snd_card;
if (!card->dev->dma_mask)
card->dev->dma_mask = &sunxi_pcm_mask;
@@ -393,15 +400,14 @@ static int sunxi_pcm_new(struct snd_soc_pcm_runtime *rtd)
}
static struct snd_soc_platform_driver sunxi_soc_platform_hdmiaudio = {
- .ops = &sunxi_pcm_ops,
- .pcm_new = sunxi_pcm_new,
- .pcm_free = sunxi_pcm_free_dma_buffers,
+ .ops = &sunxi_pcm_ops,
+ .pcm_new = sunxi_pcm_new,
+ .pcm_free = sunxi_pcm_free_dma_buffers,
};
static int __devinit sunxi_hdmiaudio_pcm_probe(struct platform_device *pdev)
{
- return snd_soc_register_platform(&pdev->dev,
- &sunxi_soc_platform_hdmiaudio);
+ return snd_soc_register_platform(&pdev->dev, &sunxi_soc_platform_hdmiaudio);
}
static int __devexit sunxi_hdmiaudio_pcm_remove(struct platform_device *pdev)
@@ -411,9 +417,9 @@ static int __devexit sunxi_hdmiaudio_pcm_remove(struct platform_device *pdev)
}
static struct platform_driver sunxi_hdmiaudio_pcm_driver = {
- .probe = sunxi_hdmiaudio_pcm_probe,
- .remove = __devexit_p(sunxi_hdmiaudio_pcm_remove),
- .driver = {
+ .probe = sunxi_hdmiaudio_pcm_probe,
+ .remove = __devexit_p(sunxi_hdmiaudio_pcm_remove),
+ .driver = {
.name = "sunxi-hdmiaudio-pcm-audio",
.owner = THIS_MODULE,
},
@@ -423,8 +429,7 @@ static struct platform_driver sunxi_hdmiaudio_pcm_driver = {
static int __init sunxi_soc_platform_hdmiaudio_init(void)
{
int err = 0;
- err = platform_driver_register(&sunxi_hdmiaudio_pcm_driver);
- if (err < 0)
+ if ((err = platform_driver_register(&sunxi_hdmiaudio_pcm_driver)) < 0)
return err;
return 0;
}
diff --git a/sound/soc/sunxi/hdmiaudio/sunxi-hdmipcm.h b/sound/soc/sunxi/hdmiaudio/sunxi-hdmipcm.h
new file mode 100644
index 0000000..0649177
--- /dev/null
+++ b/sound/soc/sunxi/hdmiaudio/sunxi-hdmipcm.h
@@ -0,0 +1,25 @@
+/*
+ * sound\soc\sunxi\hdmiaudio\sunxi-hdmipcm.h
+ * (C) Copyright 2007-2011
+ * Allwinner Technology Co., Ltd. <www.allwinnertech.com>
+ * chenpailin <chenpailin@allwinnertech.com>
+ *
+ * some simple description for this code
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ */
+
+#ifndef SUNXI_HDMIPCM_H_
+#define SUNXI_HDMIPCM_H_
+
+enum sunxi_dma_buffresult {
+ SUNXI_RES_OK,
+ SUNXI_RES_ERR,
+ SUNXI_RES_ABORT
+};
+
+#endif //SUNXI_HDMIPCM_H_
diff --git a/sound/soc/sunxi/hdmiaudio/sunxi-sndhdmi.c b/sound/soc/sunxi/hdmiaudio/sunxi-sndhdmi.c
index 75157fa..c89f760 100644
--- a/sound/soc/sunxi/hdmiaudio/sunxi-sndhdmi.c
+++ b/sound/soc/sunxi/hdmiaudio/sunxi-sndhdmi.c
@@ -24,27 +24,213 @@
#include <plat/sys_config.h>
#include <linux/io.h>
+#include "sunxi-hdmiaudio.h"
+#include "sunxi-hdmipcm.h"
+
+#include "sndhdmi.h"
+
+static struct clk *xtal;
+
+static int clk_users;
+static DEFINE_MUTEX(clk_lock);
+
+#ifdef ENFORCE_RATES
+static struct snd_pcm_hw_constraint_list hw_constraints_rates = {
+ .count = ARRAY_SIZE(rates),
+ .list = rates,
+ .mask = 0,
+};
+#endif
+
+static int sunxi_sndhdmi_startup(struct snd_pcm_substream *substream)
+{
+ int ret = 0;
+ #ifdef ENFORCE_RATES
+ struct snd_pcm_runtime *runtime = substream->runtime;;
+ #endif
+ mutex_lock(&clk_lock);
+ mutex_unlock(&clk_lock);
+ if (!ret) {
+ #ifdef ENFORCE_RATES
+ ret = snd_pcm_hw_constraint_list(runtime, 0,
+ SNDRV_PCM_HW_PARAM_RATE,
+ &hw_constraints_rates);
+ if (ret < 0)
+
+ #endif
+ }
+ return ret;
+}
+
+static void sunxi_sndhdmi_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
+{
+ __u32 samp_rate; // sample 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
+
+} __mclk_set_inf;
+
+typedef struct __BCLK_SET_INF
+{
+ __u8 bitpersamp; // bits per sample
+ __u8 clk_div; // clock division
+ __u16 mult_fs; // multiplay of sample rate
+
+} __bclk_set_inf;
+
+//bclk divider table
+static __bclk_set_inf BCLK_INF[] =
+{
+ // 16bits per sample
+ {16, 4, 128}, {16, 6, 192}, {16, 8, 256},
+ {16, 12, 384}, {16, 16, 512},
+
+ //24 bits per sample
+ {24, 4, 192}, {24, 8, 384}, {24, 16, 768},
+
+ //32 bits per sample
+ {32, 2, 128}, {32, 4, 256}, {32, 6, 384},
+ {32, 8, 512}, {32, 12, 768},
+
+ //end flag
+ {0xff, 0, 0},
+};
+
+//mclk divider table
+static __mclk_set_inf MCLK_INF[] =
+{
+ // 8k bitrate
+ { 8000, 128, 24, 0}, { 8000, 192, 16, 0}, { 8000, 256, 12, 0},
+ { 8000, 384, 8, 0}, { 8000, 512, 6, 0}, { 8000, 768, 4, 0},
+
+ // 16k bitrate
+ { 16000, 128, 12, 0}, { 16000, 192, 8, 0}, { 16000, 256, 6, 0},
+ { 16000, 384, 4, 0}, { 16000, 768, 2, 0},
+
+ // 32k bitrate
+ { 32000, 128, 6, 0}, { 32000, 192, 4, 0}, { 32000, 384, 2, 0},
+ { 32000, 768, 1, 0},
+
+ // 64k bitrate
+ { 64000, 192, 2, 0}, { 64000, 384, 1, 0},
+
+ //128k bitrate
+ {128000, 192, 1, 0},
+
+ // 12k bitrate
+ { 12000, 128, 16, 0}, { 12000, 256, 8, 0}, { 12000, 512, 4, 0},
+
+ // 24k bitrate
+ { 24000, 128, 8, 0}, { 24000, 256, 4, 0}, { 24000, 512, 2, 0},
+
+ // 48K bitrate
+ { 48000, 128, 4, 0}, { 48000, 256, 2, 0}, { 48000, 512, 1, 0},
+
+ // 96k bitrate
+ { 96000, 128 , 2, 0}, { 96000, 256, 1, 0},
+
+ //192k bitrate
+ {192000, 128, 1, 0},
+
+ //11.025k bitrate
+ { 11025, 128, 16, 1}, { 11205, 256, 8, 1}, { 11205, 512, 4, 1},
+
+ //22.05k bitrate
+ { 22050, 128, 8, 1}, { 22050, 256, 4, 1},
+ { 22050, 512, 2, 1},
+
+ //44.1k bitrate
+ { 44100, 128, 4, 1}, { 44100, 256, 2, 1}, { 44100, 512, 1, 1},
+
+ //88.2k bitrate
+ { 88200, 128, 2, 1}, { 88200, 256, 1, 1},
+
+ //176.4k bitrate
+ {176400, 128, 1, 1},
+
+ //end flag 0xffffffff
+ {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)
+{
+ u32 i, j, ret = -EINVAL;
+
+ for(i=0; i< 100; i++) {
+ if((MCLK_INF[i].samp_rate == sample_rate) &&
+ ((MCLK_INF[i].mult_fs == 256) || (MCLK_INF[i].mult_fs == 128))) {
+ for(j=0; j<ARRAY_SIZE(BCLK_INF); j++) {
+ if((BCLK_INF[j].bitpersamp == sample_width) &&
+ (BCLK_INF[j].mult_fs == MCLK_INF[i].mult_fs)) {
+ //set mclk and bclk division
+ *mclk_div = MCLK_INF[i].clk_div;
+ *mpll = MCLK_INF[i].mpll;
+ *bclk_div = BCLK_INF[j].clk_div;
+ *mult_fs = MCLK_INF[i].mult_fs;
+ ret = 0;
+ break;
+ }
+ }
+ }else if(MCLK_INF[i].samp_rate == 0xffffffff)
+ break;
+ }
+
+ return ret;
+}
+
static int sunxi_sndhdmi_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
int ret = 0;
- struct snd_soc_pcm_runtime *rtd;
- struct snd_soc_dai *codec_dai;
- struct snd_soc_dai *cpu_dai;
+ unsigned long rate = params_rate(params);
+ u32 mclk_div=0, mpll=0, bclk_div=0, mult_fs=0;
- if (!substream) {
- printk("error:%s,line:%d\n", __func__, __LINE__);
- return -EAGAIN;
- }
- rtd = substream->private_data;
- codec_dai = rtd->codec_dai;
- cpu_dai = rtd->cpu_dai;
+ get_clock_divder(rate, 32, &mclk_div, &mpll, &bclk_div, &mult_fs);
+
+ ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
+ SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
+ if (ret < 0)
+ return ret;
+
+ ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
+ SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
+ if (ret < 0)
+ return ret;
+
+ ret = snd_soc_dai_set_sysclk(cpu_dai, 0 , mpll, 0);
+ if (ret < 0)
+ return ret;
+
+ 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;
- ret = snd_soc_dai_set_fmt(codec_dai, 0);
+ ret = snd_soc_dai_set_clkdiv(cpu_dai, SUNXI_DIV_BCLK, bclk_div);
if (ret < 0)
return ret;
- ret = snd_soc_dai_set_fmt(cpu_dai, 0);
+ ret = snd_soc_dai_set_clkdiv(codec_dai, 0, mult_fs);
if (ret < 0)
return ret;
@@ -52,24 +238,26 @@ static int sunxi_sndhdmi_hw_params(struct snd_pcm_substream *substream,
}
static struct snd_soc_ops sunxi_sndhdmi_ops = {
- .hw_params = sunxi_sndhdmi_hw_params,
+ .startup = sunxi_sndhdmi_startup,
+ .shutdown = sunxi_sndhdmi_shutdown,
+ .hw_params = sunxi_sndhdmi_hw_params,
};
static struct snd_soc_dai_link sunxi_sndhdmi_dai_link = {
- .name = "HDMIAUDIO",
- .stream_name = "SUNXI-HDMIAUDIO",
- .cpu_dai_name = "sunxi-hdmiaudio.0",
+ .name = "HDMIAUDIO",
+ .stream_name = "SUNXI-HDMIAUDIO",
+ .cpu_dai_name = "sunxi-hdmiaudio.0",
.codec_dai_name = "sndhdmi",
- .platform_name = "sunxi-hdmiaudio-pcm-audio.0",
- .codec_name = "sunxi-hdmiaudio-codec.0",
- .ops = &sunxi_sndhdmi_ops,
+ .platform_name = "sunxi-hdmiaudio-pcm-audio.0",
+ .codec_name = "sunxi-hdmiaudio-codec.0",
+ .ops = &sunxi_sndhdmi_ops,
};
static struct snd_soc_card snd_soc_sunxi_sndhdmi = {
- .name = "sunxi-sndhdmi",
+ .name = "sunxi-sndhdmi",
.owner = THIS_MODULE,
- .dai_link = &sunxi_sndhdmi_dai_link,
- .num_links = 1,
+ .dai_link = &sunxi_sndhdmi_dai_link,
+ .num_links = 1,
};
static int __devinit sunxi_sndhdmi_probe(struct platform_device *pdev)
diff --git a/sound/soc/sunxi/hdmiaudio/sunxi-sndhdmi.h b/sound/soc/sunxi/hdmiaudio/sunxi-sndhdmi.h
new file mode 100644
index 0000000..341aee9
--- /dev/null
+++ b/sound/soc/sunxi/hdmiaudio/sunxi-sndhdmi.h
@@ -0,0 +1,26 @@
+/*
+ * sound\soc\sunxi\hdmiaudio\sunxi-sndhdmi.h
+ * (C) Copyright 2007-2011
+ * Allwinner Technology Co., Ltd. <www.allwinnertech.com>
+ * chenpailin <chenpailin@allwinnertech.com>
+ *
+ * some simple description for this code
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ */
+
+#ifndef SUNXI_SNDHDMI_H_
+#define SUNXI_SNDHDMI_H_
+
+struct sunxi_sndhdmi_platform_data {
+ int hdmiaudio_bclk;
+ int hdmiaudio_ws;
+ int hdmiaudio_data;
+ void (*power)(int);
+ int model;
+}
+#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..57f82c1 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,24 +227,62 @@ 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);
}
/* flush the DMA channel */
prtd->dma_loaded = 0;
- if (sunxi_dma_flush(prtd->params) == 0)
- prtd->dma_pos = prtd->dma_start;
+ sunxi_dma_flush(prtd->params);
+ prtd->dma_pos = prtd->dma_start;
/* enqueue dma buffers */
sunxi_pcm_enqueue(substream);
@@ -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 50418a5..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 7c1a3d4..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; //1. Valid data at the LSB 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..d5377fc 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,15 +253,32 @@ 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;
- if (sunxi_dma_flush(prtd->params) == 0)
- prtd->dma_pos = prtd->dma_start;
+ sunxi_dma_flush(prtd->params);
+ prtd->dma_pos = prtd->dma_start;
/* enqueue dma buffers */
sunxi_pcm_enqueue(substream);
@@ -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;
diff --git a/sound/soc/sunxi/sunxi-codec.c b/sound/soc/sunxi/sunxi-codec.c
index 1b7f8f1..197fa84 100644
--- a/sound/soc/sunxi/sunxi-codec.c
+++ b/sound/soc/sunxi/sunxi-codec.c
@@ -1155,8 +1155,8 @@ static int snd_sunxi_codec_prepare(struct snd_pcm_substream *substream)
&codec_play_dma_conf, 0);
/* flush the DMA channel */
play_prtd->dma_loaded = 0;
- if (sunxi_dma_flush(play_prtd->params) == 0)
- play_prtd->dma_pos = play_prtd->dma_start;
+ sunxi_dma_flush(play_prtd->params);
+ play_prtd->dma_pos = play_prtd->dma_start;
/* enqueue dma buffers */
sunxi_pcm_enqueue(substream);
return play_ret;
@@ -1196,8 +1196,8 @@ static int snd_sunxi_codec_prepare(struct snd_pcm_substream *substream)
&codec_capture_dma_conf, 0);
/* flush the DMA channel */
capture_prtd->dma_loaded = 0;
- if (sunxi_dma_flush(capture_prtd->params) == 0)
- capture_prtd->dma_pos = capture_prtd->dma_start;
+ sunxi_dma_flush(capture_prtd->params);
+ capture_prtd->dma_pos = capture_prtd->dma_start;
/* enqueue dma buffers */
sunxi_pcm_enqueue(substream);