aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/ramips/patches-4.3/0050-alsa-add-ralink-sdk-driver.patch
diff options
context:
space:
mode:
Diffstat (limited to 'target/linux/ramips/patches-4.3/0050-alsa-add-ralink-sdk-driver.patch')
-rw-r--r--target/linux/ramips/patches-4.3/0050-alsa-add-ralink-sdk-driver.patch8487
1 files changed, 8487 insertions, 0 deletions
diff --git a/target/linux/ramips/patches-4.3/0050-alsa-add-ralink-sdk-driver.patch b/target/linux/ramips/patches-4.3/0050-alsa-add-ralink-sdk-driver.patch
new file mode 100644
index 0000000000..1048396231
--- /dev/null
+++ b/target/linux/ramips/patches-4.3/0050-alsa-add-ralink-sdk-driver.patch
@@ -0,0 +1,8487 @@
+From f98ffa1f01240407e39c1b53135312db73f044c6 Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic@openwrt.org>
+Date: Mon, 7 Dec 2015 17:30:48 +0100
+Subject: [PATCH 50/53] alsa: add ralink sdk driver
+
+Signed-off-by: John Crispin <blogic@openwrt.org>
+---
+ sound/soc/Kconfig | 1 +
+ sound/soc/Makefile | 1 +
+ sound/soc/codecs/Kconfig | 2 +-
+ sound/soc/codecs/wm8960.c | 120 +-
+ sound/soc/codecs/wm8960.h | 64 +
+ sound/soc/mtk/Kconfig | 35 +
+ sound/soc/mtk/Makefile | 39 +
+ sound/soc/mtk/i2c_wm8960.c | 492 ++++++
+ sound/soc/mtk/i2c_wm8960.h | 288 ++++
+ sound/soc/mtk/i2s_ctrl.c | 3524 ++++++++++++++++++++++++++++++++++++++++
+ sound/soc/mtk/i2s_ctrl.h | 523 ++++++
+ sound/soc/mtk/i2s_debug.c | 698 ++++++++
+ sound/soc/mtk/mt76xx_i2s.c | 304 ++++
+ sound/soc/mtk/mt76xx_i2s.h | 18 +
+ sound/soc/mtk/mt76xx_machine.c | 317 ++++
+ sound/soc/mtk/mt76xx_machine.h | 21 +
+ sound/soc/mtk/mt76xx_pcm.c | 499 ++++++
+ sound/soc/mtk/ralink_gdma.c | 918 +++++++++++
+ sound/soc/mtk/ralink_gdma.h | 326 ++++
+ sound/soc/soc-core.c | 3 +-
+ 20 files changed, 8174 insertions(+), 19 deletions(-)
+ create mode 100644 sound/soc/mtk/Kconfig
+ create mode 100644 sound/soc/mtk/Makefile
+ create mode 100644 sound/soc/mtk/i2c_wm8960.c
+ create mode 100644 sound/soc/mtk/i2c_wm8960.h
+ create mode 100644 sound/soc/mtk/i2s_ctrl.c
+ create mode 100644 sound/soc/mtk/i2s_ctrl.h
+ create mode 100644 sound/soc/mtk/i2s_debug.c
+ create mode 100644 sound/soc/mtk/mt76xx_i2s.c
+ create mode 100644 sound/soc/mtk/mt76xx_i2s.h
+ create mode 100644 sound/soc/mtk/mt76xx_machine.c
+ create mode 100644 sound/soc/mtk/mt76xx_machine.h
+ create mode 100644 sound/soc/mtk/mt76xx_pcm.c
+ create mode 100644 sound/soc/mtk/ralink_gdma.c
+ create mode 100644 sound/soc/mtk/ralink_gdma.h
+
+diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig
+index 76ce95c..09aa2c7 100644
+--- a/sound/soc/Kconfig
++++ b/sound/soc/Kconfig
+@@ -64,6 +64,7 @@ source "sound/soc/txx9/Kconfig"
+ source "sound/soc/ux500/Kconfig"
+ source "sound/soc/xtensa/Kconfig"
+ source "sound/soc/zte/Kconfig"
++source "sound/soc/mtk/Kconfig"
+
+ # Supported codecs
+ source "sound/soc/codecs/Kconfig"
+diff --git a/sound/soc/Makefile b/sound/soc/Makefile
+index e9d8e0e..a3c6b43 100644
+--- a/sound/soc/Makefile
++++ b/sound/soc/Makefile
+@@ -46,3 +46,4 @@ obj-$(CONFIG_SND_SOC) += txx9/
+ obj-$(CONFIG_SND_SOC) += ux500/
+ obj-$(CONFIG_SND_SOC) += xtensa/
+ obj-$(CONFIG_SND_SOC) += zte/
++obj-$(CONFIG_SND_SOC) += mtk/
+diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
+index 0c9733e..276a4c5 100644
+--- a/sound/soc/codecs/Kconfig
++++ b/sound/soc/codecs/Kconfig
+@@ -816,7 +816,7 @@ config SND_SOC_WM8955
+ tristate
+
+ config SND_SOC_WM8960
+- tristate
++ tristate "WM8960"
+
+ config SND_SOC_WM8961
+ tristate
+diff --git a/sound/soc/codecs/wm8960.c b/sound/soc/codecs/wm8960.c
+index dbd8840..3118f5c 100644
+--- a/sound/soc/codecs/wm8960.c
++++ b/sound/soc/codecs/wm8960.c
+@@ -27,6 +27,7 @@
+ #include <sound/wm8960.h>
+
+ #include "wm8960.h"
++#include "../mtk/i2c_wm8960.h"
+
+ /* R25 - Power 1 */
+ #define WM8960_VMID_MASK 0x180
+@@ -57,10 +58,10 @@ static int wm8960_set_pll(struct snd_soc_codec *codec,
+ * using 2 wire for device control, so we cache them instead.
+ */
+ static const struct reg_default wm8960_reg_defaults[] = {
+- { 0x0, 0x00a7 },
+- { 0x1, 0x00a7 },
+- { 0x2, 0x0000 },
+- { 0x3, 0x0000 },
++ { 0x0, 0x002b },
++ { 0x1, 0x002b },
++ { 0x2, 0x00ff },
++ { 0x3, 0x00ff },
+ { 0x4, 0x0000 },
+ { 0x5, 0x0008 },
+ { 0x6, 0x0000 },
+@@ -92,8 +93,8 @@ static const struct reg_default wm8960_reg_defaults[] = {
+ { 0x25, 0x0050 },
+ { 0x26, 0x0000 },
+ { 0x27, 0x0000 },
+- { 0x28, 0x0000 },
+- { 0x29, 0x0000 },
++ { 0x28, 0x007b },
++ { 0x29, 0x007b },
+ { 0x2a, 0x0040 },
+ { 0x2b, 0x0000 },
+ { 0x2c, 0x0000 },
+@@ -138,7 +139,15 @@ struct wm8960_priv {
+ struct wm8960_data pdata;
+ };
+
++#if 1
++#define wm8960_reset(c) do{ \
++ int i = 0;\
++ snd_soc_write(c, WM8960_RESET, 0);\
++ for(i = 0; i < 1000*HZ; i++);\
++ }while(0)
++#else
+ #define wm8960_reset(c) regmap_write(c, WM8960_RESET, 0)
++#endif
+
+ /* enumerated controls */
+ static const char *wm8960_polarity[] = {"No Inversion", "Left Inverted",
+@@ -192,8 +201,8 @@ static int wm8960_get_deemph(struct snd_kcontrol *kcontrol,
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+ struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);
+
+- ucontrol->value.integer.value[0] = wm8960->deemph;
+- return 0;
++ //ucontrol->value.integer.value[0] = wm8960->deemph;
++ return wm8960->deemph;
+ }
+
+ static int wm8960_put_deemph(struct snd_kcontrol *kcontrol,
+@@ -211,6 +220,71 @@ static int wm8960_put_deemph(struct snd_kcontrol *kcontrol,
+ return wm8960_set_deemph(codec);
+ }
+
++static int wm8960_preinit(struct snd_soc_codec *codec)
++{
++ //printk("****** %s ******\n", __func__);
++ snd_soc_write(codec, WM8960_RESET, 0);
++ mdelay(500);
++
++ return 0;
++}
++
++static int wm8960_postinit(struct snd_soc_codec *codec)
++{
++ u32 data;
++ //printk("****** %s ******\n", __func__);
++ // In
++ data = snd_soc_read(codec, WM8960_POWER1);
++ snd_soc_write(codec, WM8960_POWER1, data|WM8960_PWR1_ADCL|WM8960_PWR1_ADCR|WM8960_PWR1_AINL |WM8960_PWR1_AINR|WM8960_PWR1_MICB);//0x19
++ data = snd_soc_read(codec, WM8960_ADDCTL1);
++ snd_soc_write(codec, WM8960_ADDCTL1, data|ADDITIONAL1_DATSEL(0x01));//0x17
++ snd_soc_write(codec, WM8960_LADC, LEFTGAIN_LDVU|LEFTGAIN_LDACVOL(0xc3));//0x15
++ snd_soc_write(codec, WM8960_RADC, LEFTGAIN_LDVU|LEFTGAIN_LDACVOL(0xc3));//0x16
++ snd_soc_write(codec, WM8960_LINPATH, 0x148);//0x20
++ snd_soc_write(codec, WM8960_RINPATH, 0x148);//0x21
++ snd_soc_write(codec, WM8960_POWER3, WM8960_PWR3_LMIC|WM8960_PWR3_RMIC);//0x2f
++
++ // Out
++ data = snd_soc_read(codec, WM8960_POWER2);
++ snd_soc_write(codec, WM8960_POWER2, data|WM8960_PWR2_DACL|WM8960_PWR2_DACR|WM8960_PWR2_LOUT1|WM8960_PWR2_ROUT1|WM8960_PWR2_SPKL|WM8960_PWR2_SPKR);//0x1a
++ mdelay(10);
++ snd_soc_write(codec, WM8960_IFACE2, 0x40);
++ snd_soc_write(codec, WM8960_LDAC, LEFTGAIN_LDVU|LEFTGAIN_LDACVOL(0xff));//0x0a
++ snd_soc_write(codec, WM8960_RDAC, RIGHTGAIN_RDVU|RIGHTGAIN_RDACVOL(0xff));//0x0b
++ snd_soc_write(codec, WM8960_LOUTMIX, 0x100);//0x22
++ snd_soc_write(codec, WM8960_ROUTMIX, 0x100);//0x25
++
++ data = snd_soc_read(codec, WM8960_POWER3);
++ snd_soc_write(codec, WM8960_POWER3, data|WM8960_PWR3_ROMIX|WM8960_PWR3_LOMIX);//0x2f
++
++ snd_soc_write(codec, WM8960_CLASSD1, 0xf7);//0x31
++ snd_soc_write(codec, WM8960_CLASSD3, 0xad);//0x33
++ snd_soc_write(codec, WM8960_DACCTL1, 0x000);//0x05
++
++ data = snd_soc_read(codec, WM8960_POWER1);
++ snd_soc_write(codec, WM8960_POWER1, data|0x1c0);//0x19
++
++
++ snd_soc_write(codec, WM8960_LOUT1, LOUT1_LO1VU|LOUT1_LO1ZC|LOUT1_LOUT1VOL(115));//0x02
++ snd_soc_write(codec, WM8960_ROUT1, ROUT1_RO1VU|ROUT1_RO1ZC|ROUT1_ROUT1VOL(115));//0x03
++
++ snd_soc_write(codec, WM8960_LINVOL, LINV_IPVU|LINV_LINVOL(110)); //LINV(0x00)=>0x12b
++ snd_soc_write(codec, WM8960_RINVOL, RINV_IPVU|RINV_RINVOL(110)); //LINV(0x01)=>0x12b
++
++ return 0;
++}
++
++static int wm8960_close(struct snd_soc_codec *codec)
++{
++ snd_soc_write(codec, WM8960_DACCTL1,0x8); //0x05->0x08
++ snd_soc_write(codec, WM8960_POWER1, 0x000); //0x19->0x000
++ mdelay(300);
++ snd_soc_write(codec, WM8960_POWER2, 0x000); //0x1a->0x000
++
++ return 0;
++}
++
++
+ static const DECLARE_TLV_DB_SCALE(adc_tlv, -9750, 50, 1);
+ static const DECLARE_TLV_DB_SCALE(inpga_tlv, -1725, 75, 0);
+ static const DECLARE_TLV_DB_SCALE(dac_tlv, -12750, 50, 1);
+@@ -563,6 +637,7 @@ static int wm8960_set_dai_fmt(struct snd_soc_dai *codec_dai,
+
+ /* set iface */
+ snd_soc_write(codec, WM8960_IFACE1, iface);
++ wm8960_postinit(codec);
+ return 0;
+ }
+
+@@ -809,9 +884,10 @@ static int wm8960_set_bias_level_out3(struct snd_soc_codec *codec,
+ ret = wm8960_configure_clocking(codec);
+ if (ret)
+ return ret;
+-
++#if 0
+ /* Set VMID to 2x50k */
+ snd_soc_update_bits(codec, WM8960_POWER1, 0x180, 0x80);
++#endif
+ break;
+
+ case SND_SOC_BIAS_ON:
+@@ -852,12 +928,16 @@ static int wm8960_set_bias_level_out3(struct snd_soc_codec *codec,
+ /* Disable anti-pop features */
+ snd_soc_write(codec, WM8960_APOP1, WM8960_BUFIOEN);
+ }
+-
++#if 0
+ /* Set VMID to 2x250k */
+ snd_soc_update_bits(codec, WM8960_POWER1, 0x180, 0x100);
++#endif
+ break;
+
+ case SND_SOC_BIAS_OFF:
++#if 1
++ wm8960_close(codec);
++#else
+ /* Enable anti-pop features */
+ snd_soc_write(codec, WM8960_APOP1,
+ WM8960_POBCTRL | WM8960_SOFT_ST |
+@@ -866,6 +946,7 @@ static int wm8960_set_bias_level_out3(struct snd_soc_codec *codec,
+ /* Disable VMID and VREF, let them discharge */
+ snd_soc_write(codec, WM8960_POWER1, 0);
+ msleep(600);
++#endif
+ break;
+ }
+
+@@ -1101,10 +1182,15 @@ static int wm8960_set_pll(struct snd_soc_codec *codec,
+
+ if (pll_div.k) {
+ reg |= 0x20;
+-
++#if 1
+ snd_soc_write(codec, WM8960_PLL2, (pll_div.k >> 16) & 0xff);
+ snd_soc_write(codec, WM8960_PLL3, (pll_div.k >> 8) & 0xff);
+ snd_soc_write(codec, WM8960_PLL4, pll_div.k & 0xff);
++#else
++ snd_soc_write(codec, WM8960_PLL2, (pll_div.k >> 16) & 0xff);
++ snd_soc_write(codec, WM8960_PLL3, (pll_div.k >> 8) & 0xff);
++ snd_soc_write(codec, WM8960_PLL4, pll_div.k & 0xff);
++#endif
+ }
+ snd_soc_write(codec, WM8960_PLL1, reg);
+
+@@ -1150,7 +1236,11 @@ static int wm8960_set_dai_clkdiv(struct snd_soc_dai *codec_dai,
+ snd_soc_write(codec, WM8960_PLL1, reg | div);
+ break;
+ case WM8960_DCLKDIV:
++#if 1
+ reg = snd_soc_read(codec, WM8960_CLOCK2) & 0x03f;
++#else
++ reg = snd_soc_read(codec, WM8960_CLOCK2) & 0x03f;
++#endif
+ snd_soc_write(codec, WM8960_CLOCK2, reg | div);
+ break;
+ case WM8960_TOCLKSEL:
+@@ -1285,7 +1375,7 @@ static int wm8960_i2c_probe(struct i2c_client *i2c,
+ {
+ struct wm8960_data *pdata = dev_get_platdata(&i2c->dev);
+ struct wm8960_priv *wm8960;
+- int ret;
++ int ret - 0;
+
+ wm8960 = devm_kzalloc(&i2c->dev, sizeof(struct wm8960_priv),
+ GFP_KERNEL);
+@@ -1307,11 +1397,7 @@ static int wm8960_i2c_probe(struct i2c_client *i2c,
+ else if (i2c->dev.of_node)
+ wm8960_set_pdata_from_of(i2c, &wm8960->pdata);
+
+- ret = wm8960_reset(wm8960->regmap);
+- if (ret != 0) {
+- dev_err(&i2c->dev, "Failed to issue reset\n");
+- return ret;
+- }
++ wm8960_reset(wm8960->regmap);
+
+ if (wm8960->pdata.shared_lrclk) {
+ ret = regmap_update_bits(wm8960->regmap, WM8960_ADDCTL2,
+diff --git a/sound/soc/codecs/wm8960.h b/sound/soc/codecs/wm8960.h
+index ab3220d..5205deb 100644
+--- a/sound/soc/codecs/wm8960.h
++++ b/sound/soc/codecs/wm8960.h
+@@ -111,4 +111,68 @@
+ #define WM8960_OPCLK_DIV_5_5 (4 << 0)
+ #define WM8960_OPCLK_DIV_6 (5 << 0)
+
++/*
++ * WM8960 Power management
++ */
++#define WM8960_PWR1_VMIDSEL_DISABLED (0 << 7)
++#define WM8960_PWR1_VMIDSEL_50K (1 << 7)
++#define WM8960_PWR1_VMIDSEL_250K (2 << 7)
++#define WM8960_PWR1_VMIDSEL_5K (3 << 7)
++#define WM8960_PWR1_VREF (1 << 6)
++#define WM8960_PWR1_AINL (1 << 5)
++#define WM8960_PWR1_AINR (1 << 4)
++#define WM8960_PWR1_ADCL (1 << 3)
++#define WM8960_PWR1_ADCR (1 << 2)
++#define WM8960_PWR1_MICB (1 << 1)
++#define WM8960_PWR1_DIGENB (1 << 0)
++
++#define WM8960_PWR2_DACL (1 << 8)
++#define WM8960_PWR2_DACR (1 << 7)
++//#define WM8960_PWR2_LOUT1 (1 << 6)
++//#define WM8960_PWR2_ROUT1 (1 << 5)
++#define WM8960_PWR2_SPKL (1 << 4)
++#define WM8960_PWR2_SPKR (1 << 3)
++//#define WM8960_PWR2_OUT3 (1 << 1)
++#define WM8960_PWR2_PLL_EN (1 << 0)
++
++#define WM8960_PWR3_LMIC (1 << 5)
++#define WM8960_PWR3_RMIC (1 << 4)
++#define WM8960_PWR3_LOMIX (1 << 3)
++#define WM8960_PWR3_ROMIX (1 << 2)
++
++#define LEFTGAIN 0x0a
++#define LEFTGAIN_LDVU (1 << 8)
++#define LEFTGAIN_LDACVOL(x) ((x) & 0xff)
++
++#define RIGHTGAIN 0x0b
++#define RIGHTGAIN_RDVU (1 << 8)
++#define RIGHTGAIN_RDACVOL(x) ((x) & 0xff)
++
++#define ADDITIONAL1_DATSEL(x) (((x) & 0x3) << 2)
++
++#define AINTFCE1_WL_32 (3 << 2)
++#define AINTFCE1_WL_24 (2 << 2)
++#define AINTFCE1_WL_20 (1 << 2)
++#define AINTFCE1_WL_16 (0 << 2)
++#define AINTFCE1_FORMAT_I2S (2 << 0)
++
++#define LOUT1_LO1VU (1 << 8)
++#define LOUT1_LO1ZC (1 << 7)
++#define LOUT1_LOUT1VOL(x) ((x) & 0x7f)
++
++#define ROUT1_RO1VU (1 << 8)
++#define ROUT1_RO1ZC (1 << 7)
++#define ROUT1_ROUT1VOL(x) ((x) & 0x7f)
++
++#define LINV_IPVU (1 << 8) /* FIXME */
++
++#define LINV_LINMUTE (1 << 7)
++#define LINV_LIZC (1 << 6)
++#define LINV_LINVOL(x) ((x) & 0x3f)
++
++#define RINV_IPVU (1 << 8) /* FIXME */
++#define RINV_RINMUTE (1 << 7)
++#define RINV_RIZC (1 << 6)
++#define RINV_RINVOL(x) ((x) & 0x3f)
++
+ #endif
+diff --git a/sound/soc/mtk/Kconfig b/sound/soc/mtk/Kconfig
+new file mode 100644
+index 0000000..26d2531
+--- /dev/null
++++ b/sound/soc/mtk/Kconfig
+@@ -0,0 +1,35 @@
++config SND_MT76XX_SOC
++ tristate "SoC Audio for MT76XX APSoC Machine"
++ depends on SND_SOC && (SOC_MT7620 || SOC_MT7621)
++
++ help
++ Say Y or M if you want to add support for codecs attached to
++ the MTK I2S interface.
++
++choice
++ prompt "Selected SoC type"
++ depends on SND_MT76XX_SOC
++ default SND_MT76XX_SOC_MT7620
++
++config SND_MT76XX_SOC_MT7620
++ bool "MT7620"
++ depends on SOC_MT7620
++
++config SND_MT76XX_SOC_MT7628
++ bool "MT7628"
++ depends on SOC_MT7620
++
++config SND_MT76XX_SOC_MT7621
++ bool "MT7621"
++ depends on SOC_MT7621
++
++endchoice
++
++config SND_MT76XX_PCM
++ tristate "MTK SoC Audio PCM Platform"
++ depends on SND_MT76XX_SOC
++
++config SND_MT76XX_I2S
++ tristate "MTK SoC I2S Support"
++ depends on SND_MT76XX_SOC
++
+diff --git a/sound/soc/mtk/Makefile b/sound/soc/mtk/Makefile
+new file mode 100644
+index 0000000..00b3dff
+--- /dev/null
++++ b/sound/soc/mtk/Makefile
+@@ -0,0 +1,39 @@
++KBUILD_CFLAGS += -I$(srctree)
++
++ifeq ($(CONFIG_SND_MT76XX_SOC_MT7620),y)
++KBUILD_CFLAGS += -DCONFIG_MT7620 -DCONFIG_RALINK_MT7620
++endif
++ifeq ($(CONFIG_SND_MT76XX_SOC_MT7628),y)
++KBUILD_CFLAGS += -DCONFIG_MT7628 -DCONFIG_RALINK_MT7628
++endif
++ifeq ($(CONFIG_SOC_MT7620),y)
++KBUILD_CFLAGS += -DRALINK_SYSCTL_BASE=0xB0000000
++KBUILD_CFLAGS += -DRALINK_INTCL_BASE=0xB0000200
++KBUILD_CFLAGS += -DRALINK_PIO_BASE=0xB0000600
++KBUILD_CFLAGS += -DRALINK_I2S_BASE=0xB0000A00
++KBUILD_CFLAGS += -DRALINK_GDMA_BASE=0xB0002800
++KBUILD_CFLAGS += -DCONFIG_GDMA_EVERYBODY
++KBUILD_CFLAGS += -DCONFIG_SND_MT76XX_SOC
++KBUILD_CFLAGS += -DCONFIG_I2S_WM8960
++KBUILD_CFLAGS += -DCONFIG_I2S_MCLK_12P288MHZ
++KBUILD_CFLAGS += -DCONFIG_GDMA_EVERYBODY
++KBUILD_CFLAGS += -DSURFBOARDINT_DMA=15
++KBUILD_CFLAGS += -DRALINK_INTCTL_DMA=128
++KBUILD_CFLAGS += -DCONFIG_SND_SOC_WM8960
++endif
++
++# MTK APSoC Platform Support
++snd-soc-mt76xx-i2s-ctl-objs := i2s_ctrl.o i2s_debug.o #i2c_wm8960.o
++snd-soc-mt76xx-pcm-objs := mt76xx_pcm.o
++snd-soc-mt76xx-i2s-objs := mt76xx_i2s.o
++
++obj-$(CONFIG_SND_MT76XX_PCM) += snd-soc-mt76xx-pcm.o
++obj-$(CONFIG_SND_MT76XX_I2S) += snd-soc-mt76xx-i2s-ctl.o snd-soc-mt76xx-i2s.o
++
++# MTK APSoC Machine Support
++snd-soc-mt76xx-machine-objs := mt76xx_machine.o
++
++obj-$(CONFIG_SND_MT76XX_SOC) += i2c_wm8960.o ralink_gdma.o snd-soc-mt76xx-machine.o
++
++
++
+diff --git a/sound/soc/mtk/i2c_wm8960.c b/sound/soc/mtk/i2c_wm8960.c
+new file mode 100644
+index 0000000..70f16e1
+--- /dev/null
++++ b/sound/soc/mtk/i2c_wm8960.c
+@@ -0,0 +1,492 @@
++#include <linux/kernel.h>
++#include <linux/version.h>
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/slab.h>
++#include <linux/i2c.h>
++#include <linux/delay.h>
++#include <linux/interrupt.h>
++#include <linux/fs.h>
++#include <linux/fcntl.h>
++#include <linux/cdev.h>
++#if defined(CONFIG_ARCH_MT7623)
++#include <mt_i2c.h>
++#include <mach/mt_gpio.h>
++#endif
++#include "i2c_wm8960.h"
++#include "i2s_ctrl.h"
++
++
++#define BUF_SIZE 20
++
++#undef MSG
++#define MSG printk
++
++
++#if defined(CONFIG_ARCH_MT7623)
++/*FIXME*/
++//static struct i2c_board_info __initdata i2c_devs1 = { I2C_BOARD_INFO("codec_wm8960", (0X34>>1))};
++static struct i2c_board_info __initdata i2c_devs1 = { I2C_BOARD_INFO("codec_wm8960", (0X34))};
++
++#endif
++unsigned long wm_reg_data[56];
++struct wm8960_data *wmio;
++
++struct wm8960_data {
++ struct i2c_client *client;
++ struct device *dev;
++ const char *name;
++};
++
++
++void i2c_WM8960_write(u32 reg, u32 data)
++{
++ int ret;
++ struct i2c_msg msg;
++ u8 buf[2]={0};
++
++#if defined(CONFIG_ARCH_MT7623)
++ unsigned int ext_flag = 0;
++
++ ext_flag &= 0x7FFFFFFF;
++ ext_flag |= I2C_A_FILTER_MSG;
++ ext_flag |= I2C_POLLING_FLAG;
++#endif
++
++ wm_reg_data[reg] = data;
++
++ buf[0]= (reg<<1)|(0x01&(data>>8));
++ buf[1]= (data&0xFF);
++
++#if defined(CONFIG_ARCH_MT7623)
++ /*FIXME*/
++ //msg.addr = wmio->client->addr;
++ msg.addr = wmio->client->addr>>1;
++
++#else
++ msg.addr = wmio->client->addr>>1;
++#endif
++ msg.flags = 0;
++ msg.buf = (char *)buf;
++ msg.len = 2;
++#if defined(CONFIG_ARCH_MT7623)
++ msg.timing = 80;
++ msg.ext_flag = ext_flag & 0x7FFFFFFF;
++#endif
++
++ ret = i2c_transfer(wmio->client->adapter, &msg, 1);
++ MSG("[WM8960(%02X)=0x%08X]\n",(unsigned int)reg,(unsigned int)data);
++
++ if (ret <= 0)
++ printk("%s: i2c write error!\n", __func__);
++}
++
++
++
++// Reset and power up the WM8960
++void audiohw_preinit(void)
++{
++ memset(wm_reg_data, 0 , sizeof(unsigned long)*55);
++
++ i2c_WM8960_write(RESET, RESET_RESET); // Reset (0x0F)
++
++ mdelay(50);
++ wm_reg_data[RESET] = 0xFFFF;
++ mdelay(50);
++}
++
++void audiohw_set_apll(int srate)
++{
++ unsigned long data;
++
++ if((srate==8000) || (srate==12000) || (srate==16000) || (srate==24000) || (srate==32000) || (srate==48000))
++ {
++ // Provide 12.288MHz SYSCLK
++ data = wm_reg_data[PLL1];
++ i2c_WM8960_write(PLL1, data | PLL1_OPCLKDIV_1 | PLL1_SDM_FRACTIONAL | PLL1_PLLPRESCALE_1 | PLL1_PLLN(0x8)); // PLL1 (0x34)
++
++ i2c_WM8960_write(PLL2, PLL2_PLLK_23_16(0x31)); // PLL2 (0x35)
++ i2c_WM8960_write(PLL3, PLL3_PLLK_15_8(0x26)); // PLL3 (0x36)
++ i2c_WM8960_write(PLL4, PLL4_PLLK_7_0(0xe9)); // PLL4 (0x37)
++ }
++ else if ((srate==11025) || (srate==22050) || (srate==44100))
++ {
++ //Provide 11.2896MHz SYSCLK
++ data = wm_reg_data[PLL1];
++ i2c_WM8960_write(PLL1, data | PLL1_OPCLKDIV_1 | PLL1_SDM_FRACTIONAL | PLL1_PLLPRESCALE_1 | PLL1_PLLN(0x7)); //PLL1 (0x34)
++
++ i2c_WM8960_write(PLL2, PLL2_PLLK_23_16(0x86)); //PLL2 (0x35)
++ i2c_WM8960_write(PLL3, PLL3_PLLK_15_8(0xc2)); //PLL3 (0x36)
++ i2c_WM8960_write(PLL4, PLL4_PLLK_7_0(0x26)); //PLL4 (0x37)
++ }
++ else
++ {
++ printk("Not support this srate\n");
++ }
++ mdelay(3);
++}
++
++
++void audiohw_set_frequency(int fsel, int pll_en)
++{
++ MSG("audiohw_set_frequency_=0x%08X\n",fsel);
++
++ if (pll_en)
++ {
++ printk("PLL enable\n");
++ i2c_WM8960_write(CLOCKING1, (fsel<<3) | CLOCKING1_SYSCLKDIV_2 | CLOCKING1_CLKSEL_PLL); //CLOCKING (0x04)=>0x05
++
++ }
++ else
++ {
++ printk("PLL disable\n");
++ i2c_WM8960_write(CLOCKING1, (fsel<<3));//| CLOCKING1_SYSCLKDIV_2); //CLOCKING (0x04)
++ }
++
++}
++
++//FIXME
++int audiohw_set_lineout_vol(int Aout, int vol_l, int vol_r)
++{
++ MSG("audiohw_set_lineout_vol_\n");
++ switch(Aout)
++ {
++ case 1:
++ //i2c_WM8960_write(LOUT1, LOUT1_LO1VU|LOUT1_LO1ZC|LOUT1_LOUT1VOL(0x7f)); //LOUT1(0x02)
++ //i2c_WM8960_write(ROUT1, ROUT1_RO1VU|ROUT1_RO1ZC|ROUT1_ROUT1VOL(0x7f)); //ROUT1(0x03)
++ i2c_WM8960_write(LOUT1, LOUT1_LO1VU|LOUT1_LO1ZC|LOUT1_LOUT1VOL(vol_l)); //LOUT1(0x02)
++ i2c_WM8960_write(ROUT1, ROUT1_RO1VU|ROUT1_RO1ZC|ROUT1_ROUT1VOL(vol_r)); //ROUT1(0x03)
++ break;
++ case 2:
++ i2c_WM8960_write(LSPK, LSPK_SPKLVU|LSPK_SPKLZC| LSPK_SPKLVOL(vol_l));
++ i2c_WM8960_write(RSPK, RSPK_SPKRVU|RSPK_SPKRZC| RSPK_SPKRVOL(vol_r));
++ break;
++ default:
++ break;
++ }
++ return 0;
++}
++
++//FIXME
++int audiohw_set_linein_vol(int vol_l, int vol_r)
++{
++ MSG("audiohw_set_linein_vol_\n");
++
++ i2c_WM8960_write(LINV, LINV_IPVU|LINV_LINVOL(vol_l)); //LINV(0x00)=>0x12b
++ i2c_WM8960_write(RINV, RINV_IPVU|RINV_RINVOL(vol_r)); //LINV(0x01)=>0x12b
++
++ return 0;
++}
++
++//Set signal path
++int audiohw_postinit(int bSlave, int AIn, int AOut, int pll_en, int wordLen24b)
++{
++
++ int i;
++ unsigned long data;
++
++ if(wm_reg_data[RESET]!=0xFFFF)
++ return 0;
++
++ if(bSlave)
++ {
++ MSG("WM8960 slave.....\n");
++ if(wordLen24b)
++ {
++ printk("24 bit word length\n");
++ i2c_WM8960_write(AINTFCE1, AINTFCE1_WL_24 | AINTFCE1_FORMAT_I2S); //AINTFCE1(0x07)
++ }
++ else
++ {
++ printk("16 bit word length\n");
++ i2c_WM8960_write(AINTFCE1, AINTFCE1_WL_16 | AINTFCE1_FORMAT_I2S); //AINTFCE1(0x07)
++ }
++ }
++ else
++ {
++ MSG("WM8960 master.....\n");
++ i2c_WM8960_write(CLOCKING2, 0x1c4);//CLOCKING2_BCLKDIV(0x1c4)); //CLOCKING2(0x08)
++
++ if(wordLen24b)
++ {
++ printk("24 bit word length\n");
++ i2c_WM8960_write(AINTFCE1, AINTFCE1_MS | AINTFCE1_WL_24 | AINTFCE1_FORMAT_I2S); //AINTFCE1(0x07)
++ }
++ else
++ {
++ printk("16 bit word length\n");
++ i2c_WM8960_write(AINTFCE1, AINTFCE1_MS | AINTFCE1_WL_16 | AINTFCE1_FORMAT_I2S); //AINTFCE1(0x07)
++ }
++ mdelay(5);
++ }
++
++
++ //From app notes: allow Vref to stabilize to reduce clicks
++ for(i = 0; i < 1000*HZ; i++);
++
++ if(AIn > 0)
++ {
++ data = wm_reg_data[PWRMGMT1];
++ i2c_WM8960_write(PWRMGMT1, data|PWRMGMT1_ADCL|PWRMGMT1_ADCR|PWRMGMT1_AINL |PWRMGMT1_AINR);//|PWRMGMT1_MICB);//PWRMGMT1(0x19)
++
++ data = wm_reg_data[ADDITIONAL1];
++ i2c_WM8960_write(ADDITIONAL1, data|ADDITIONAL1_DATSEL(0x01)); //ADDITIONAL1(0x17)
++ i2c_WM8960_write(LADCVOL, LADCVOL_LAVU_EN|LADCVOL_LADCVOL(0xc3)); //LADCVOL(0x15)
++ i2c_WM8960_write(RADCVOL, RADCVOL_RAVU_EN|RADCVOL_RADCVOL(0xc3)); //RADCVOL(0x16)
++ i2c_WM8960_write(ADCLPATH, ADCLPATH_LMN1|ADCLPATH_LMIC2B);//|ADCLPATH_LMICBOOST_13DB); //ADCLPATH(0x20)=>(0x108)
++ i2c_WM8960_write(ADCRPATH, ADCRPATH_RMN1|ADCRPATH_RMIC2B);//|ADCRPATH_RMICBOOST_13DB); //ADCRPATH(0x21)=>(0x108)
++ i2c_WM8960_write(PWRMGMT3, PWRMGMT3_LMIC|PWRMGMT3_RMIC); //PWRMGMT3(0x2f)
++
++ //i2c_WM8960_write(LINBMIX, 0x000); //LINBMIX(0x2B)
++
++ if (AOut<=0)
++ {
++ i2c_WM8960_write(AINTFCE2, 0x40); //FIXME:(0x09)
++
++ data = wm_reg_data[PWRMGMT2];
++ if(pll_en)
++ {
++ i2c_WM8960_write(PWRMGMT2, data|PWRMGMT2_PLL_EN|PWRMGMT2_DACL|PWRMGMT2_DACR); //PWRMGMT2(0x1a)
++ }
++ else
++ {
++ i2c_WM8960_write(PWRMGMT2, data|PWRMGMT2_DACL|PWRMGMT2_DACR); //PWRMGMT2(0x1a)
++
++ }
++ }
++ }
++ if(AOut>0)
++ {
++ //Power management 2 setting
++ data = wm_reg_data[PWRMGMT2];
++
++ if(pll_en)
++ {
++ i2c_WM8960_write(PWRMGMT2, data|PWRMGMT2_PLL_EN|PWRMGMT2_DACL|PWRMGMT2_DACR|PWRMGMT2_LOUT1|PWRMGMT2_ROUT1|PWRMGMT2_SPKL|PWRMGMT2_SPKR); //PWRMGMT2(0x1a)
++ }
++ else
++ {
++ i2c_WM8960_write(PWRMGMT2, data|PWRMGMT2_DACL|PWRMGMT2_DACR|PWRMGMT2_LOUT1|PWRMGMT2_ROUT1|PWRMGMT2_SPKL|PWRMGMT2_SPKR); //PWRMGMT2(0x1a)
++
++ }
++
++ mdelay(10);
++
++ i2c_WM8960_write(AINTFCE2, 0x40); //FIXME:(0x09)
++
++ i2c_WM8960_write(LEFTGAIN, LEFTGAIN_LDVU|LEFTGAIN_LDACVOL(0xff)); //LEFTGAIN(0x0a)
++ i2c_WM8960_write(RIGHTGAIN, RIGHTGAIN_RDVU|RIGHTGAIN_RDACVOL(0xff)); //RIGHTGAIN(0x0b)
++
++ i2c_WM8960_write(LEFTMIX1, 0x100); //LEFTMIX1(0x22)
++ i2c_WM8960_write(RIGHTMIX2, 0x100); //RIGHTMIX2(0x25)
++
++ data = wm_reg_data[PWRMGMT3]; //FIXME
++ i2c_WM8960_write(PWRMGMT3, data|PWRMGMT3_ROMIX|PWRMGMT3_LOMIX); //PWRMGMT3(0x2f)
++
++ data = wm_reg_data[CLASSDCTRL1]; //CLASSDCTRL1(0x31) SPEAKER FIXME
++ i2c_WM8960_write(CLASSDCTRL1, 0xf7);//data|CLASSDCTRL1_OP_LRSPK);
++
++ data = wm_reg_data[CLASSDCTRL3]; //CLASSDCTRL3(0x33)
++ i2c_WM8960_write(CLASSDCTRL3, 0xad);//data|(0x1b));
++ }
++
++ i2c_WM8960_write(DACCTRL1, 0x000); //DACCTRL1(0x05)
++
++ data = wm_reg_data[PWRMGMT1];
++ i2c_WM8960_write(PWRMGMT1, data|0x1c0); //FIXME:PWRMGMT1(0x19)
++
++
++ printk("WM8960 All initial ok!\n");
++
++ return 0;
++
++}
++
++void audiohw_micboost(int boostgain)
++{
++ unsigned long data;
++
++ data = wm_reg_data[ADCLPATH];
++ i2c_WM8960_write(ADCLPATH, data|(boostgain << 4));
++
++ data = wm_reg_data[ADCRPATH];
++ i2c_WM8960_write(ADCRPATH, data|(boostgain << 4));
++}
++
++void audiohw_micin(int enableMic)
++{
++ unsigned long data;
++
++ if (enableMic==1)
++ {
++ data = wm_reg_data[PWRMGMT1];
++ i2c_WM8960_write(PWRMGMT1, data|PWRMGMT1_MICB);
++ }
++#if 1
++ else
++ {
++ data = wm_reg_data[PWRMGMT1];
++ i2c_WM8960_write(PWRMGMT1, data & (~(PWRMGMT1_MICB)));
++ }
++#endif
++}
++
++void audiohw_mute( bool mute)
++{
++ //Mute: Set DACMU = 1 to soft-mute the audio DACs.
++ //Unmute: Set DACMU = 0 to soft-un-mute the audio DACs.
++ i2c_WM8960_write(DACCTRL1, mute ? DACCTRL1_DACMU : 0);
++}
++
++
++//Nice shutdown of WM8960 codec
++void audiohw_close(void)
++{
++ i2c_WM8960_write(DACCTRL1,DACCTRL1_DACMU); //0x05->0x08
++ i2c_WM8960_write(PWRMGMT1, 0x000); //0x19->0x000
++ mdelay(400);
++ i2c_WM8960_write(PWRMGMT2, 0x000); //0x1a->0x000
++
++}
++
++void audiohw_loopback(int fsel)
++{
++}
++
++void audiohw_codec_exlbk(void)
++{
++ memset(wm_reg_data, 0 , sizeof(unsigned long)*55);
++
++ i2c_WM8960_write(LINV, 0x117); //0x00->0x117
++ i2c_WM8960_write(RINV, 0x117); //0x01->0x117
++ i2c_WM8960_write(LOUT1, 0x179); //0x02->0x179
++ i2c_WM8960_write(ROUT1, 0x179); //0x03->0x179
++ i2c_WM8960_write(CLOCKING1, 0x00); //0x04->0x00
++ //i2c_WM8960_write(CLOCKING1, 0x40); //0x04->0x00
++ i2c_WM8960_write(DACCTRL1, 0x00); //0x05->0x00
++ i2c_WM8960_write(AINTFCE2, 0x41); //0x09->0x41
++ i2c_WM8960_write(LADCVOL, 0x1c3); //0x15->0x1c3
++ i2c_WM8960_write(RADCVOL, 0x1c3); //0x16->0x1c3
++ i2c_WM8960_write(PWRMGMT1, 0xfc); //0x19->0xfc
++ i2c_WM8960_write(PWRMGMT2, 0x1e0); //0x1a->0x1e0
++ i2c_WM8960_write(ADCLPATH, 0x108); //0x20->0x108
++ i2c_WM8960_write(ADCRPATH, 0x108); //0x21->0x108
++ i2c_WM8960_write(LEFTMIX1, 0x150); //0x22->0x150
++ i2c_WM8960_write(RIGHTMIX2, 0x150); //0x25->0x150
++ i2c_WM8960_write(BYPASS1, 0x00); //0x2d->0x00
++ i2c_WM8960_write(BYPASS2, 0x00); //0x2e->0x00
++ i2c_WM8960_write(PWRMGMT3, 0x3c); //0x2f->0x3c
++}
++
++void audiohw_bypass(void)
++{
++ int i;
++
++ memset(wm_reg_data, 0 , sizeof(unsigned long)*55);
++ i2c_WM8960_write(RESET, 0x000); //0x0f(R15)->0x000
++
++ for(i = 0; i < 1000*HZ; i++);
++
++ i2c_WM8960_write(PWRMGMT1, 0xf0); //0x19(R25)->0xf0
++ i2c_WM8960_write(PWRMGMT2, 0x60); //0x1a(R26)->0x60
++ i2c_WM8960_write(PWRMGMT3, 0x3c); //0x2f(R47)->0x3c
++ i2c_WM8960_write(LINV, 0x117); // 0x00(R0)->0x117
++ i2c_WM8960_write(RINV, 0x117); // 0x01(R1)->0x117
++ i2c_WM8960_write(ADCLPATH, 0x108); //0x20(R32)->0x108
++ i2c_WM8960_write(ADCRPATH, 0x108); //0x21(R33)->0x108
++ i2c_WM8960_write(BYPASS1, 0x80); //0x2d(R45)->0x80
++ i2c_WM8960_write(BYPASS2, 0x80); //0x2e(R46)->0x80
++ i2c_WM8960_write(LOUT1, 0x179); // 0x02(R2)->0x179
++ i2c_WM8960_write(ROUT1, 0x179); // 0x03(R3)->0x179
++}
++EXPORT_SYMBOL(audiohw_set_frequency);
++EXPORT_SYMBOL(audiohw_close);
++EXPORT_SYMBOL(audiohw_postinit);
++EXPORT_SYMBOL(audiohw_preinit);
++EXPORT_SYMBOL(audiohw_set_apll);
++EXPORT_SYMBOL(audiohw_codec_exlbk);
++EXPORT_SYMBOL(audiohw_bypass);
++EXPORT_SYMBOL(audiohw_set_lineout_vol);
++EXPORT_SYMBOL(audiohw_set_linein_vol);
++EXPORT_SYMBOL(audiohw_micin);
++EXPORT_SYMBOL(audiohw_mute);
++EXPORT_SYMBOL(audiohw_loopback);
++EXPORT_SYMBOL(audiohw_micboost);
++
++static int codec_wm8960_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id)
++{
++ struct wm8960_data *wm;
++
++printk("*******Enter %s********\n", __func__);
++
++ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
++ return -EIO;
++
++ wm = devm_kzalloc(&client->dev, sizeof(struct wm8960_data), GFP_KERNEL);
++ if (!wm)
++ return -ENOMEM;
++
++#if defined(CONFIG_ARCH_MT7623)
++ mt_set_gpio_mode(GPIO242, GPIO_MODE_04);
++ mt_set_gpio_mode(GPIO243, GPIO_MODE_04);
++#endif
++ wm->client = client;
++ wm->dev = &client->dev;
++ wm->name = id->name;
++ i2c_set_clientdata(client, wm);
++ wmio = wm;
++
++ memset(wm_reg_data, 0 , sizeof(unsigned long)*55);
++
++ return 0;
++}
++
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,8,0)
++static int codec_wm8960_i2c_remove(struct i2c_client *client)
++#else
++static int __devexit codec_wm8960_i2c_remove(struct i2c_client *client)
++#endif
++{
++ struct wm8960_data *wm = i2c_get_clientdata(client);
++ kfree(wm);
++
++ return 0;
++}
++
++static const struct i2c_device_id wm8960_id[] = {
++ { "codec_wm8960", 0 },
++ {}
++};
++
++static struct i2c_driver codec_wm8960_i2c_driver = {
++ .driver = {
++ .name = "codec_wm8960"
++ },
++ .probe = codec_wm8960_i2c_probe,
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,8,0)
++ .remove = codec_wm8960_i2c_remove,
++#else
++ .remove = __devexit_p(codec_wm8960_i2c_remove),
++#endif
++ .id_table = wm8960_id,
++};
++static int __init wm8960_i2c_init(void)
++{
++#if defined(CONFIG_ARCH_MT7623)
++ i2c_register_board_info(1, &i2c_devs1, 1);
++#endif
++ return i2c_add_driver(&codec_wm8960_i2c_driver);;
++}
++
++static void __exit wm8960_i2c_exit(void)
++{
++ i2c_del_driver(&codec_wm8960_i2c_driver);
++}
++
++module_init(wm8960_i2c_init);
++module_exit(wm8960_i2c_exit);
++
++MODULE_AUTHOR("Ryder Lee <ryder.lee@mediatek.com>");
++MODULE_DESCRIPTION("WM8960 I2C client driver");
++MODULE_LICENSE("GPL");
++
+diff --git a/sound/soc/mtk/i2c_wm8960.h b/sound/soc/mtk/i2c_wm8960.h
+new file mode 100644
+index 0000000..c769345
+--- /dev/null
++++ b/sound/soc/mtk/i2c_wm8960.h
+@@ -0,0 +1,288 @@
++/* wm8960.h -- WM8960 Soc Audio driver */
++#ifndef _WM8960_H
++#define _WM8960_H
++
++#define bool unsigned char
++#define false 0
++#define true 1
++
++/* volume/balance/treble/bass interdependency */
++#define VOLUME_MIN -730
++#define VOLUME_MAX 60
++
++
++/* Register addresses and bits */
++#define OUTPUT_MUTED 0x2f
++#define OUTPUT_0DB 0x79
++
++#define LINV 0x00
++#define LINV_IPVU (1 << 8) /* FIXME */
++#define LINV_LINMUTE (1 << 7)
++#define LINV_LIZC (1 << 6)
++#define LINV_LINVOL(x) ((x) & 0x3f)
++
++#define RINV 0x01
++#define RINV_IPVU (1 << 8) /* FIXME */
++#define RINV_RINMUTE (1 << 7)
++#define RINV_RIZC (1 << 6)
++#define RINV_RINVOL(x) ((x) & 0x3f)
++
++#define LOUT1 0x02
++#define LOUT1_LO1VU (1 << 8)
++#define LOUT1_LO1ZC (1 << 7)
++#define LOUT1_LOUT1VOL(x) ((x) & 0x7f)
++
++#define ROUT1 0x03
++#define ROUT1_RO1VU (1 << 8)
++#define ROUT1_RO1ZC (1 << 7)
++#define ROUT1_ROUT1VOL(x) ((x) & 0x7f)
++
++#define CLOCKING1 0x04 /* FIXME */
++#define CLOCKING1_ADCDIV(x) (((x) & 0x7) << 6)
++#define CLOCKING1_DACDIV(x) (((x) & 0x7) << 3)
++#define CLOCKING1_SYSCLKDIV_1 (0 << 1)
++#define CLOCKING1_SYSCLKDIV_2 (2 << 1)
++#define CLOCKING1_CLKSEL_MCLK (0 << 0)
++#define CLOCKING1_CLKSEL_PLL (1 << 0)
++
++#define DACCTRL1 0x05
++#define DACCTRL1_DATTENUATE (1 << 7)
++#define DACCTRL1_DACMU (1 << 3)
++#define DACCTRL1_DEEMPH_48 (3 << 1)
++#define DACCTRL1_DEEMPH_44 (2 << 1)
++#define DACCTRL1_DEEMPH_32 (1 << 1)
++#define DACCTRL1_DEEMPH_NONE (0 << 1)
++#define DACCTRL1_DEEMPH(x) ((x) & (0x3 << 1))
++
++#define DACCTRL2 0x06
++
++#define AINTFCE1 0x07
++#define AINTFCE1_BCLKINV (1 << 7)
++#define AINTFCE1_MS (1 << 6)
++#define AINTFCE1_LRSWAP (1 << 5)
++#define AINTFCE1_LRP (1 << 4)
++#define AINTFCE1_WL_32 (3 << 2)
++#define AINTFCE1_WL_24 (2 << 2)
++#define AINTFCE1_WL_20 (1 << 2)
++#define AINTFCE1_WL_16 (0 << 2)
++#define AINTFCE1_WL(x) (((x) & 0x3) << 2)
++#define AINTFCE1_FORMAT_DSP (3 << 0)
++#define AINTFCE1_FORMAT_I2S (2 << 0)
++#define AINTFCE1_FORMAT_LJUST (1 << 0)
++#define AINTFCE1_FORMAT_RJUST (0 << 0)
++#define AINTFCE1_FORMAT(x) ((x) & 0x3)
++
++/* FIXME */
++#define CLOCKING2 0x08
++#define CLOCKING2_DCLKDIV(x) (((x) & 0x7) << 6)
++#define CLOCKING2_BCLKDIV(x) (((x) & 0xf) << 0)
++
++#define AINTFCE2 0x09
++#define AINTFCE2_ALRCGPIO_ALRC (0 << 6)
++#define AINTFCE2_ALRCGPIO_GPIO (1 << 6)
++#define AINTFCE2_LOOPBACK (1 << 0)
++
++#define LEFTGAIN 0x0a
++#define LEFTGAIN_LDVU (1 << 8)
++#define LEFTGAIN_LDACVOL(x) ((x) & 0xff)
++
++#define RIGHTGAIN 0x0b
++#define RIGHTGAIN_RDVU (1 << 8)
++#define RIGHTGAIN_RDACVOL(x) ((x) & 0xff)
++
++#define RESET 0x0f
++#define RESET_RESET 0x000
++
++#define ALC1 0x11
++#define ALC1_ALCOFF (0x0 << 7)
++#define ALC1_ALCRONLY (0x1 << 7)
++#define ALC1_ALCLONLY (0x2 << 7)
++#define ALC1_ALCSTEREO (0x3 << 7)
++#define ALC1_ALCSEL(x) (((x) & 0x3) << 7)
++#define ALC1_SET_MAXGAIN(x) ((x & 0x7) << 4)
++#define ALC1_GET_MAXGAIN(x) ((x) & (0x7 << 4))
++#define ALC1_ALCL(x) ((x) & 0x0f)
++
++#define ALC2 0x12
++#define ALC2_MINGAIN(x) ((x & 0x7) << 4)
++#define ALC2_HLD(x) ((x) & 0x0f)
++
++#define ALC3 0x13
++#define ALC3_SET_DCY(x) ((x & 0x0f) << 4)
++#define ALC3_GET_DCY(x) ((x) & (0x0f << 4))
++#define ALC3_ATK(x) ((x) & 0x0f)
++
++#define NOISEGATE 0x14
++#define NOISEGATE_SET_NGTH(x) ((x & 0x1f) << 3)
++#define NOISEGATE_GET_NGTH(x) ((x) & (0x1f << 3))
++#define NOISEGATE_NGAT_ENABLE 1
++
++#define LADCVOL 0x15
++#define LADCVOL_LAVU_EN (1 << 8)
++#define LADCVOL_LADCVOL(x) ((x) & 0x0ff)
++
++#define RADCVOL 0x16
++#define RADCVOL_RAVU_EN (1 << 8)
++#define RADCVOL_RADCVOL(x) ((x) & 0x0ff)
++
++#define ADDITIONAL1 0x17
++#define ADDITIONAL1_TSDEN (1 << 8)
++#define ADDITIONAL1_VSEL_LOWEST (0 << 6)
++#define ADDITIONAL1_VSEL_LOW (1 << 6)
++#define ADDITIONAL1_VSEL_DEFAULT2 (2 << 6)
++#define ADDITIONAL1_VSEL_DEFAULT (3 << 6)
++#define ADDITIONAL1_VSEL(x) (((x) & 0x3) << 6)
++#define ADDITIONAL1_DMONOMIX_STEREO (0 << 4)
++#define ADDITIONAL1_DMONOMIX_MONO (1 << 4)
++#define ADDITIONAL1_DATSEL(x) (((x) & 0x3) << 2)
++#define ADDITIONAL1_TOCLKSEL (1 << 1)
++#define ADDITIONAL1_TOEN (1 << 0)
++
++#define ADDITIONAL2 0x18
++#define ADDITIONAL2_HPSWEN (1 << 6)
++#define ADDITIONAL2_HPSWPOL (1 << 5)
++#define ADDITIONAL2_TRIS (1 << 3)
++#define ADDITIONAL2_LRCM_ON (1 << 2)
++
++#define PWRMGMT1 0x19
++#define PWRMGMT1_VMIDSEL_DISABLED (0 << 7)
++#define PWRMGMT1_VMIDSEL_50K (1 << 7)
++#define PWRMGMT1_VMIDSEL_250K (2 << 7)
++#define PWRMGMT1_VMIDSEL_5K (3 << 7)
++#define PWRMGMT1_VREF (1 << 6)
++#define PWRMGMT1_AINL (1 << 5)
++#define PWRMGMT1_AINR (1 << 4)
++#define PWRMGMT1_ADCL (1 << 3)
++#define PWRMGMT1_ADCR (1 << 2)
++#define PWRMGMT1_MICB (1 << 1)
++#define PWRMGMT1_DIGENB (1 << 0)
++
++#define PWRMGMT2 0x1a
++#define PWRMGMT2_DACL (1 << 8)
++#define PWRMGMT2_DACR (1 << 7)
++#define PWRMGMT2_LOUT1 (1 << 6)
++#define PWRMGMT2_ROUT1 (1 << 5)
++#define PWRMGMT2_SPKL (1 << 4)
++#define PWRMGMT2_SPKR (1 << 3)
++#define PWRMGMT2_OUT3 (1 << 1)
++#define PWRMGMT2_PLL_EN (1 << 0)
++
++#define ADDITIONAL3 0x1b
++#define ADDITIONAL3_VROI (1 << 6)
++#define ADDITIONAL3_OUT3CAP (1 << 3)
++#define ADDITIONAL3_ADC_ALC_SR(x) ((x) & 0x7)
++
++#define ANTIPOP1 0x1c
++#define ANTIPOP2 0x1d
++
++#define ADCLPATH 0x20
++#define ADCLPATH_LMN1 (1 << 8)
++#define ADCLPATH_LMP3 (1 << 7)
++#define ADCLPATH_LMP2 (1 << 6)
++#define ADCLPATH_LMICBOOST_29DB (0x3 << 4)
++#define ADCLPATH_LMICBOOST_20DB (0x2 << 4)
++#define ADCLPATH_LMICBOOST_13DB (0x1 << 4)
++#define ADCLPATH_SET_LMICBOOST(x) ((x & 0x3) << 4)
++#define ADCLPATH_LMIC2B (1 << 3)
++
++
++#define ADCRPATH 0x21
++#define ADCRPATH_RMN1 (1 << 8)
++#define ADCRPATH_RMP3 (1 << 7)
++#define ADCRPATH_RMP2 (1 << 6)
++#define ADCRPATH_RMICBOOST_29DB (0x3 << 4)
++#define ADCRPATH_RMICBOOST_20DB (0x2 << 4)
++#define ADCRPATH_RMICBOOST_13DB (0x1 << 4)
++#define ADCRPATH_SET_RMICBOOST(x) ((x & 0x3) << 4)
++#define ADCRPATH_RMIC2B (1 << 3)
++
++
++#define LEFTMIX1 0x22
++#define LEFTMIX1_LD2LO (1 << 8)
++#define LEFTMIX1_LI2LO (1 << 7)
++#define LEFTMIX1_LI2LO_DEFAULT (5 << 4)
++#define LEFTMIX1_LI2LOVOL(x) (((x) & 0x7) << 4)
++
++#define RIGHTMIX2 0x25
++#define RIGHTMIX2_RD2RO (1 << 8)
++#define RIGHTMIX2_RI2RO (1 << 7)
++#define RIGHTMIX2_RI2RO_DEFAULT (5 << 4)
++#define RIGHTMIX2_RI2ROVOL(x) (((x) & 0x7) << 4)
++
++#define MONOMIX1 0x26
++#define MONOMIX1_L2MO (1 << 7)
++
++#define MONOMIX2 0x27
++#define MONOMIX2_R2MO (1 << 7)
++
++#define LSPK 0x28
++#define LSPK_SPKLVU (1 << 8)
++#define LSPK_SPKLZC (1 << 7)
++#define LSPK_SPKLVOL(x) ((x) & 0x7f)
++
++#define RSPK 0x29
++#define RSPK_SPKRVU (1 << 8)
++#define RSPK_SPKRZC (1 << 7)
++#define RSPK_SPKRVOL(x) ((x) & 0x7f)
++
++#define OUT3V 0x2a
++#define LINBMIX 0x2b
++#define RINBMIX 0x2c
++#define BYPASS1 0x2d
++#define BYPASS2 0x2e
++
++#define PWRMGMT3 0x2f
++#define PWRMGMT3_LMIC (1<<5)
++#define PWRMGMT3_RMIC (1<<4)
++#define PWRMGMT3_LOMIX (1<<3)
++#define PWRMGMT3_ROMIX (1<<2)
++
++#define ADDITIONAL4 0x30
++
++#define CLASSDCTRL1 0x31
++#define CLASSDCTRL1_OP_OFF (0<<6)
++#define CLASSDCTRL1_OP_LSPK (1<<6)
++#define CLASSDCTRL1_OP_RSPK (2<<6)
++#define CLASSDCTRL1_OP_LRSPK (3<<6)
++
++#define CLASSDCTRL3 0x33
++
++#define PLL1 0x34
++#define PLL1_OPCLKDIV_1 (0<<6)
++#define PLL1_OPCLKDIV_2 (1<<6)
++#define PLL1_OPCLKDIV_3 (2<<6)
++#define PLL1_OPCLKDIV_4 (3<<6)
++#define PLL1_OPCLKDIV_5p5 (4<<6)
++#define PLL1_OPCLKDIV_6 (5<<6)
++#define PLL1_SDM_INTERGER (0<<5)
++#define PLL1_SDM_FRACTIONAL (1<<5)
++#define PLL1_PLLPRESCALE_1 (0<<4)
++#define PLL1_PLLPRESCALE_2 (1<<4)
++#define PLL1_PLLN(x) ((x) & 0xf)
++
++#define PLL2 0x35
++#define PLL2_PLLK_23_16(x) ((x) & 0x1ff)
++
++#define PLL3 0x36
++#define PLL3_PLLK_15_8(x) ((x) & 0x1ff)
++
++#define PLL4 0x37
++#define PLL4_PLLK_7_0(x) ((x) & 0x1ff)
++
++/* codec API */
++void audiohw_preinit(void);
++int audiohw_postinit(int bSlave, int AIn, int AOut, int pll_en, int wordLen24b);
++void audiohw_close(void);
++void audiohw_set_frequency(int fsel, int pll_en);
++void audiohw_mute(bool mute);
++void audiohw_micboost(int boostgain);
++void audiohw_micin(int enableMic);
++void audiohw_set_apll(int srate);
++int audiohw_set_lineout_vol(int Aout, int vol_l, int vol_r);
++int audiohw_set_linein_vol(int vol_l, int vol_r);
++void audiohw_mute( bool mute);
++void audiohw_loopback(int fsel);
++void audiohw_codec_exlbk(void);
++void audiohw_bypass(void);
++
++#endif /* _WM875x_H */
+diff --git a/sound/soc/mtk/i2s_ctrl.c b/sound/soc/mtk/i2s_ctrl.c
+new file mode 100644
+index 0000000..05034b0
+--- /dev/null
++++ b/sound/soc/mtk/i2s_ctrl.c
+@@ -0,0 +1,3524 @@
++#include <linux/init.h>
++#include <linux/version.h>
++#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,35)
++#include <linux/sched.h>
++#endif
++#include <linux/module.h>
++#include <linux/kernel.h> /* _printk() */
++#include <linux/slab.h> /* kmalloc() */
++#include <linux/fs.h> /* everything... */
++#include <linux/errno.h> /* error codes */
++#include <linux/types.h> /* size_t */
++#include <linux/proc_fs.h>
++#include <linux/fcntl.h> /* O_ACCMODE */
++#if LINUX_VERSION_CODE < KERNEL_VERSION(3,10,14)
++#include <asm/system.h> /* cli(), *_flags */
++#endif
++#include <asm/uaccess.h> /* copy_from/to_user */
++#include <linux/interrupt.h>
++#include <linux/mm.h>
++#include <linux/mm_types.h>
++#include <linux/pci.h>
++#include <linux/delay.h>
++#include "ralink_gdma.h"
++#if defined(CONFIG_I2S_WITH_AEC)
++#include "../aec/aec_api.h"
++#endif
++
++#ifdef CONFIG_DEVFS_FS
++#include <linux/devfs_fs_kernel.h>
++static devfs_handle_t devfs_handle;
++#endif
++
++#include "i2s_ctrl.h"
++
++#if defined(CONFIG_SND_MT76XX_SOC)
++#include <sound/soc/mtk/mt76xx_machine.h>
++#endif
++
++#if defined(CONFIG_I2S_WM8750)
++#include "../codec/i2c_wm8750.h"
++#endif
++#if defined(CONFIG_I2S_WM8751)
++#include "../codec/i2c_wm8751.h"
++#endif
++#if defined(CONFIG_I2S_WM8960)
++#include "i2c_wm8960.h"
++#endif
++
++static int i2sdrv_major = 191;
++#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,35)
++#else
++static struct class *i2smodule_class;
++#endif
++
++static int _printk(char *fmt, ...)
++{
++ return 0;
++}
++
++/* external functions declarations */
++#if defined(CONFIG_I2S_WM8960)
++extern void audiohw_set_frequency(int fsel, int codec_pll_en);
++void audiohw_set_apll(int srate);
++#elif defined(CONFIG_I2S_WM8750)||defined(CONFIG_I2S_WM8751)
++extern void audiohw_set_frequency(int fsel);
++#endif
++#if defined(CONFIG_I2S_WM8960)||defined(CONFIG_I2S_WM8750)||defined(CONFIG_I2S_WM8751)
++extern int audiohw_set_lineout_vol(int Aout, int vol_l, int vol_r);
++extern int audiohw_set_master_vol(int vol_l, int vol_r);
++extern int audiohw_set_linein_vol(int vol_l, int vol_r);
++#endif
++
++extern void audiohw_micboost(int boostgain);
++
++extern int GdmaI2sTx(uint32_t Src, uint32_t Dst, uint8_t TxNo, uint16_t TransCount,
++ void (*DoneIntCallback)(uint32_t data),
++ void (*UnMaskIntCallback)(uint32_t data));
++
++extern int GdmaI2sRx(uint32_t Src, uint32_t Dst, uint8_t RxNo, uint16_t TransCount,
++ void (*DoneIntCallback)(uint32_t data),
++ void (*UnMaskIntCallback)(uint32_t data));
++
++extern int GdmaMaskChannel(uint32_t ChNum);
++
++extern int GdmaUnMaskChannel(uint32_t ChNum);
++
++/* internal functions declarations */
++irqreturn_t i2s_irq_isr(int irq, void *irqaction);
++int i2s_debug_cmd(unsigned int cmd, unsigned long arg);
++
++/* forward declarations for _fops */
++#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,35)
++static long i2s_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
++#else
++static int i2s_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
++#endif
++static int i2s_mmap(struct file *file, struct vm_area_struct *vma);
++static int i2s_open(struct inode *inode, struct file *file);
++static int i2s_release(struct inode *inode, struct file *file);
++int i2s_mmap_alloc(unsigned long size);
++int i2s_mmap_remap(struct vm_area_struct *vma, unsigned long size);
++
++/* global varable definitions */
++i2s_config_type i2s_config;
++i2s_status_type i2s_status;
++i2s_config_type* pi2s_config = &i2s_config;;
++i2s_status_type* pi2s_status = &i2s_status;;
++
++static inline long
++ugly_hack_sleep_on_timeout(wait_queue_head_t *q, long timeout)
++{
++ unsigned long flags;
++ wait_queue_t wait;
++
++ init_waitqueue_entry(&wait, current);
++
++ __set_current_state(TASK_INTERRUPTIBLE);
++ spin_lock_irqsave(&q->lock, flags);
++ __add_wait_queue(q, &wait);
++ spin_unlock(&q->lock);
++
++ timeout = schedule_timeout(timeout);
++
++ spin_lock_irq(&q->lock);
++ __remove_wait_queue(q, &wait);
++ spin_unlock_irqrestore(&q->lock, flags);
++
++ return timeout;
++}
++
++#define interruptible_sleep_on(x) \
++ ugly_hack_sleep_on_timeout(x, MAX_SCHEDULE_TIMEOUT);
++
++
++#if defined(ARM_ARCH)
++static dma_addr_t i2s_txdma_addr0, i2s_txdma_addr1;
++static dma_addr_t i2s_rxdma_addr0, i2s_rxdma_addr1;
++#define I2S_TX_FIFO_WREG_PHY (I2S_TX_FIFO_WREG & 0x1FFFFFFF)
++#define I2S_RX_FIFO_RREG_PHY (I2S_RX_FIFO_RREG & 0x1FFFFFFF)
++#else
++static dma_addr_t i2s_txdma_addr, i2s_rxdma_addr;
++#endif
++static dma_addr_t i2s_mmap_addr[MAX_I2S_PAGE*2];
++ /* 8khz 11.025khz 12khz 16khz 22.05khz 24Khz 32khz 44.1khz 48khz 88.2khz 96khz*/
++unsigned long i2s_inclk_15p625Mhz[11] = {60<<8, 43<<8, 40<<8, 30<<8, 21<<8, 19<<8, 14<<8, 10<<8, 9<<8, 7<<8, 4<<8};
++unsigned long i2s_exclk_12p288Mhz[11] = {47<<8, 34<<8, 31<<8, 23<<8, 16<<8, 15<<8, 11<<8, 8<<8, 7<<8, 5<<8, 3<<8};
++unsigned long i2s_exclk_12Mhz[11] = {46<<8, 33<<8, 30<<8, 22<<8, 16<<8, 15<<8, 11<<8, 8<<8, 7<<8, 5<<8, 3<<8};
++#if defined(CONFIG_I2S_WM8750) || defined(CONFIG_SND_SOC_WM8750)
++ /* 8k 11.025k 12k 16k 22.05k 24k 32k 44.1k 48k 88.2k 96k*/
++unsigned long i2s_codec_12p288Mhz[11] = {0x0C, 0x00, 0x10, 0x14, 0x38, 0x38, 0x18, 0x20, 0x00, 0x00, 0x1C};
++unsigned long i2s_codec_12Mhz[11] = {0x0C, 0x32, 0x10, 0x14, 0x37, 0x38, 0x18, 0x22, 0x00, 0x3E, 0x1C};
++unsigned long i2s_codec_24p576Mhz[11] = {0x4C, 0x00, 0x50, 0x54, 0x00, 0x78, 0x58, 0x00, 0x40, 0x00, 0x5C};
++unsigned long i2s_codec_18p432Mhz[11] = {0x0e, 0x32, 0x12, 0x16, 0x36, 0x3a, 0x1a, 0x22, 0x02, 0x3e, 0x1e};
++#endif
++#if defined(CONFIG_I2S_WM8751) || defined(CONFIG_SND_SOC_WM8751)
++unsigned long i2s_codec_12p288Mhz[11] = {0x04, 0x00, 0x10, 0x14, 0x38, 0x38, 0x18, 0x20, 0x00, 0x00, 0x1C};
++unsigned long i2s_codec_12Mhz[11] = {0x04, 0x32, 0x10, 0x14, 0x37, 0x38, 0x18, 0x22, 0x00, 0x3E, 0x1C};
++#endif
++#if defined(CONFIG_I2S_WM8960) || defined(CONFIG_SND_SOC_WM8960)
++unsigned long i2s_codec_12p288Mhz[11] = {0x36, 0x24, 0x24, 0x1b, 0x12, 0x12, 0x09, 0x00, 0x00, 0x00, 0x00};
++unsigned long i2s_codec_12Mhz[11] = {0x36, 0x24, 0x24, 0x1b, 0x12, 0x12, 0x09, 0x00, 0x00, 0x00, 0x00};
++#endif
++EXPORT_SYMBOL(i2s_codec_12p288Mhz);
++EXPORT_SYMBOL(i2s_codec_12Mhz);
++
++#if defined(CONFIG_RALINK_RT6855A)
++ /* 8K 11.025k 12k 16k 22.05k 24k 32k 44.1K 48k 88.2k 96k */
++unsigned long i2s_inclk_int[11] = { 97, 70, 65, 48, 35, 32, 24, 17, 16, 12, 8};
++unsigned long i2s_inclk_comp[11] = { 336, 441, 53, 424, 220, 282, 212, 366, 141, 185, 70};
++#elif defined (CONFIG_RALINK_MT7621)
++#ifdef MT7621_ASIC_BOARD
++#if defined (CONFIG_I2S_MCLK_12P288MHZ)
++unsigned long i2s_inclk_int[11] = { 576, 384, 0, 288, 192, 192, 144, 96, 96, 48, 48};
++unsigned long i2s_inclk_comp[11] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
++#elif defined(CONFIG_I2S_MCLK_12MHZ)
++unsigned long i2s_inclk_int[11] = {1171, 850, 0, 585, 425, 390, 292, 212, 195, 106, 97};
++unsigned long i2s_inclk_comp[11] = { 448, 174, 0, 480, 87, 320, 496, 299, 160, 149, 336};
++#endif
++#else //MT7621_FPGA_BOARD
++unsigned long i2s_inclk_int[11] = { 529, 384, 0, 264, 192, 176, 132, 96, 88, 48, 44};
++unsigned long i2s_inclk_comp[11] = { 102, 0, 0, 307, 0, 204, 153, 0, 102, 0, 51};
++#endif
++#elif defined (CONFIG_RALINK_MT7628)
++#ifdef MT7628_ASIC_BOARD
++ /* 8K 11.025k 12k 16k 22.05k 24k 32k 44.1K 48k 88.2k 96k 176k 192k */
++unsigned long i2s_inclk_int_16bit[13] = {937, 680, 0, 468, 340, 312, 234, 170, 156, 85, 78, 42, 39};
++unsigned long i2s_inclk_comp_16bit[13]= {256, 139, 0, 384, 69, 256, 192, 34, 128, 17, 64, 267, 32};
++unsigned long i2s_inclk_int_24bit[13] = {625, 404, 0, 312, 226, 208, 156, 113, 104, 56, 52, 28, 26};
++unsigned long i2s_inclk_comp_24bit[13]= { 0, 404, 0, 256, 387, 170, 128, 193, 85, 352, 42, 176, 21};
++#else
++ /* 8K 11.025k 12k 16k 22.05k 24k 32k 44.1K 48k 88.2k 96k 176k 192k */
++unsigned long i2s_inclk_int_16bit[13] = {468, 340, 0, 234, 170, 156, 117, 85, 78, 42, 39, 21, 19};
++unsigned long i2s_inclk_comp_16bit[13]= {384, 69, 0, 192, 34, 128, 96, 17, 64, 264, 32, 133, 272};
++unsigned long i2s_inclk_int_24bit[13] = {312, 202, 0, 156, 113, 104, 78, 56, 52, 28, 26, 14, 13};
++unsigned long i2s_inclk_comp_24bit[13]= {256, 202, 0, 128, 193, 85, 64, 352, 42, 176, 21, 88, 10};
++#endif
++#elif defined (CONFIG_ARCH_MT7623)
++#if defined MT7623_ASIC_BOARD
++ /* 8K 11.025k 12k 16k 22.05k 24k 32k 44.1K 48k 88.2k 96k 176k 192k */
++unsigned long i2s_inclk_int_16bit[13] = {576, 384, 0, 288, 192, 192, 144, 96, 96, 48, 48, 24, 24};
++unsigned long i2s_inclk_comp_16bit[13]= { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
++unsigned long i2s_inclk_int_24bit[13] = {384, 256, 0, 192, 128, 128, 96, 64, 64, 32, 32, 16, 16};
++unsigned long i2s_inclk_comp_24bit[13]= { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
++#else
++ /* 8K 11.025k 12k 16k 22.05k 24k 32k 44.1K 48k 88.2k 96k 176k 192k */
++unsigned long i2s_inclk_int_16bit[13] = {72, 48, 0, 36, 24, 24, 18, 12, 12, 6, 6, 3, 3};
++unsigned long i2s_inclk_comp_16bit[13]= { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
++unsigned long i2s_inclk_int_24bit[13] = {48, 32, 0, 24, 16, 16, 12, 8, 8, 4, 4, 2, 2};
++unsigned long i2s_inclk_comp_24bit[13]= { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
++#endif
++#else
++ /* 8K 11.025k 12k 16k 22.05k 24k 32k 44.1K 48k 88.2k 96k */
++unsigned long i2s_inclk_int[11] = { 78, 56, 52, 39, 28, 26, 19, 14, 13, 9, 6};
++unsigned long i2s_inclk_comp[11] = { 64, 352, 42, 32, 176, 21, 272, 88, 10, 455, 261};
++#endif
++
++#if defined(CONFIG_I2S_WITH_AEC)
++aecFuncTbl_t *aecFuncP;
++#endif
++/* USB mode 22.05Khz register value in datasheet is 0x36 but will cause slow clock, 0x37 is correct value */
++/* USB mode 44.1Khz register value in datasheet is 0x22 but will cause slow clock, 0x23 is correct value */
++
++struct tasklet_struct i2s_tx_tasklet;
++struct tasklet_struct i2s_rx_tasklet;
++EXPORT_SYMBOL(i2s_tx_tasklet);
++EXPORT_SYMBOL(i2s_rx_tasklet);
++
++char test_buf[I2S_PAGE_SIZE];
++char test_buf_1[I2S_PAGE_SIZE];
++char test_buf_2[I2S_PAGE_SIZE];
++
++static const struct file_operations i2s_fops = {
++ owner : THIS_MODULE,
++ mmap : i2s_mmap,
++ open : i2s_open,
++ release : i2s_release,
++#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,35)
++ unlocked_ioctl: i2s_ioctl,
++#else
++ ioctl : i2s_ioctl,
++#endif
++};
++
++int __init i2s_mod_init(void)
++{
++ int result;
++
++ _printk("******* i2s module init **********\n");
++ /* register device with kernel */
++#ifdef CONFIG_DEVFS_FS
++ if(devfs_register_chrdev(i2sdrv_major, I2SDRV_DEVNAME , &i2s_fops)) {
++ _printk(KERN_WARNING " i2s: can't create device node - %s\n", I2SDRV_DEVNAME);
++ return -EIO;
++ }
++
++ devfs_handle = devfs_register(NULL, I2SDRV_DEVNAME, DEVFS_FL_DEFAULT, i2sdrv_major, 0,
++ S_IFCHR | S_IRUGO | S_IWUGO, &i2s_fops, NULL);
++#else
++ result = register_chrdev(i2sdrv_major, I2SDRV_DEVNAME, &i2s_fops);
++ if (result < 0) {
++ _printk(KERN_WARNING "i2s: can't get major %d\n",i2sdrv_major);
++ return result;
++ }
++
++ if (i2sdrv_major == 0) {
++ i2sdrv_major = result; /* dynamic */
++ }
++#endif
++
++#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,35)
++#else
++ i2smodule_class=class_create(THIS_MODULE, I2SDRV_DEVNAME);
++ if (IS_ERR(i2smodule_class))
++ return -EFAULT;
++ device_create(i2smodule_class, NULL, MKDEV(i2sdrv_major, 0), I2SDRV_DEVNAME);
++#endif
++
++#if defined(CONFIG_I2S_WITH_AEC)
++ _printk("AEC FuncP init \n");
++ /*Add by mtk04880*/
++ aecFuncP = kmalloc(sizeof(aecFuncTbl_t), GFP_KERNEL);
++ /*If aecFuncP cannot request memory,it will be ignored in I2S module. Since AEC & I2S are independent
++ * when AEC module is inserted,It will return err message (but I2S will keep running without AEC support)
++ * */
++ if(aecFuncP){
++ memset(aecFuncP,0,sizeof(aecFuncTbl_t));
++ }
++#endif
++
++ return 0;
++}
++
++void i2s_mod_exit(void)
++{
++ _printk("************ i2s module exit *************\n");
++#ifdef CONFIG_DEVFS_FS
++ devfs_unregister_chrdev(i2sdrv_major, I2SDRV_DEVNAME);
++ devfs_unregister(devfs_handle);
++#else
++ unregister_chrdev(i2sdrv_major, I2SDRV_DEVNAME);
++#endif
++#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,35)
++#else
++ device_destroy(i2smodule_class,MKDEV(i2sdrv_major, 0));
++ class_destroy(i2smodule_class);
++#endif
++ return ;
++}
++
++
++int i2s_open(struct inode *inode, struct file *filp)
++{
++#if defined(I2S_HW_INTERRUPT_EN)&&(I2S_SW_IRQ_EN)
++ int Ret;
++#endif
++ int minor = iminor(inode);
++
++ if (minor >= I2S_MAX_DEV)
++ return -ENODEV;
++
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
++ MOD_INC_USE_COUNT;
++#else
++ try_module_get(THIS_MODULE);
++#endif
++
++ if (filp->f_flags & O_NONBLOCK) {
++ MSG("filep->f_flags O_NONBLOCK set\n");
++ return -EAGAIN;
++ }
++
++ /* set i2s_config */
++ filp->private_data = pi2s_config;
++ memset(pi2s_config, 0, sizeof(i2s_config_type));
++#ifdef I2S_STATISTIC
++ memset(pi2s_status, 0, sizeof(i2s_status_type));
++#endif
++ i2s_param_init(pi2s_config);
++
++#if defined(I2S_HW_INTERRUPT_EN)&&(I2S_SW_IRQ_EN)
++#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,35)
++ Ret = request_irq(SURFBOARDINT_I2S, i2s_irq_isr, IRQF_DISABLED, "Ralink_I2S", NULL);
++#else
++ Ret = request_irq(SURFBOARDINT_I2S, i2s_irq_isr, SA_INTERRUPT, "Ralink_I2S", NULL);
++#endif
++
++ if(Ret){
++ MSG("IRQ %d is not free.\n", SURFBOARDINT_I2S);
++ i2s_release(inode, filp);
++ return -1;
++ }
++#endif
++
++ init_waitqueue_head(&(pi2s_config->i2s_tx_qh));
++ init_waitqueue_head(&(pi2s_config->i2s_rx_qh));
++ spin_lock_init(&pi2s_config->lock);
++
++ return 0;
++}
++
++
++static int i2s_release(struct inode *inode, struct file *filp)
++{
++ i2s_config_type* ptri2s_config;
++
++ /* decrement usage count */
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
++ MOD_DEC_USE_COUNT;
++#else
++ module_put(THIS_MODULE);
++#endif
++
++#if defined(I2S_HW_INTERRUPT_EN)&&(I2S_SW_IRQ_EN)
++ free_irq(SURFBOARDINT_I2S, NULL);
++#endif
++
++ ptri2s_config = filp->private_data;
++ if(ptri2s_config==NULL)
++ goto EXIT;
++#ifdef CONFIG_I2S_MMAP
++ i2s_mem_unmap(ptri2s_config);
++#else
++ i2s_txbuf_free(ptri2s_config);
++ i2s_rxbuf_free(ptri2s_config);
++#endif
++ /* free buffer */
++ i2s_txPagebuf_free(ptri2s_config);
++ i2s_rxPagebuf_free(ptri2s_config);
++EXIT:
++ MSG("i2s_release succeeds\n");
++ return 0;
++}
++
++int i2s_mmap_alloc(unsigned long size)
++{
++ int i;
++ u32 page_size;
++ int first_index;
++
++ page_size = I2S_PAGE_SIZE;
++
++ if ((pi2s_config->mmap_index == 0) || (pi2s_config->mmap_index == MAX_I2S_PAGE))
++ {
++ MSG("mmap_index=%d\n", pi2s_config->mmap_index);
++
++ first_index = pi2s_config->mmap_index;
++ pi2s_config->pMMAPBufPtr[pi2s_config->mmap_index] = kmalloc(size, GFP_DMA);
++ i2s_mmap_addr[pi2s_config->mmap_index] = (dma_addr_t)dma_map_single(NULL, pi2s_config->pMMAPBufPtr[pi2s_config->mmap_index], size, DMA_BIDIRECTIONAL);
++
++ if( pi2s_config->pMMAPBufPtr[pi2s_config->mmap_index] == NULL )
++ {
++ MSG("i2s_mmap failed\n");
++ return -1;
++ }
++ }
++ else
++ {
++ _printk("illegal index:%d\n", pi2s_config->mmap_index);
++ return -1;
++ }
++
++ _printk("MMAP[%d]=0x%08X, i2s_mmap_addr[%d]=0x%08x\n",
++ pi2s_config->mmap_index, (u32)pi2s_config->pMMAPBufPtr[pi2s_config->mmap_index],
++ pi2s_config->mmap_index, i2s_mmap_addr[pi2s_config->mmap_index]);
++
++ memset(pi2s_config->pMMAPBufPtr[pi2s_config->mmap_index], 0, size);
++ pi2s_config->mmap_index++;
++
++ for (i=1; i<MAX_I2S_PAGE; i++)
++ {
++ i2s_mmap_addr[pi2s_config->mmap_index] = i2s_mmap_addr[first_index] + i*page_size;
++ pi2s_config->pMMAPBufPtr[pi2s_config->mmap_index] = pi2s_config->pMMAPBufPtr[first_index] + i*page_size;
++
++ _printk("MMAP[%d]=0x%08X, i2s_mmap_addr[%d]=0x%08x\n",pi2s_config->mmap_index, (u32)pi2s_config->pMMAPBufPtr[pi2s_config->mmap_index], pi2s_config->mmap_index, i2s_mmap_addr[pi2s_config->mmap_index]);
++
++ /* Notice: The last mmap_index's value should be MAX_I2S_PAGE or MAX_I2S_PAGE*2 */
++ pi2s_config->mmap_index++;
++ }
++
++ return 0;
++}
++
++int i2s_mmap_remap(struct vm_area_struct *vma, unsigned long size)
++{
++ int nRet;
++
++ if((pi2s_config->pMMAPBufPtr[0]!=NULL) && (pi2s_config->mmap_index == MAX_I2S_PAGE))
++ {
++ MSG("i2s_mmap_remap:0\n");
++ nRet = remap_pfn_range(vma, vma->vm_start, virt_to_phys((void *)pi2s_config->pMMAPBufPtr[0]) >> PAGE_SHIFT, size, vma->vm_page_prot);
++
++ if( nRet != 0 )
++ {
++ _printk("i2s_mmap->remap_pfn_range failed\n");
++ return -EIO;
++ }
++ }
++
++ if((pi2s_config->pMMAPBufPtr[MAX_I2S_PAGE]!=NULL) && (pi2s_config->mmap_index == MAX_I2S_PAGE*2))
++ {
++ MSG("i2s_mmap_remap:%d\n", MAX_I2S_PAGE);
++
++ nRet = remap_pfn_range(vma, vma->vm_start, virt_to_phys((void *)pi2s_config->pMMAPBufPtr[MAX_I2S_PAGE]) >> PAGE_SHIFT, size, vma->vm_page_prot);
++
++ if( nRet != 0 )
++ {
++ _printk("i2s_mmap->remap_pfn_range failed\n");
++ return -EIO;
++ }
++ }
++
++ return 0;
++}
++
++static int i2s_mmap(struct file *filp, struct vm_area_struct *vma)
++{
++ unsigned long size = vma->vm_end-vma->vm_start;
++ _printk("page_size=%d, ksize=%lu\n", I2S_PAGE_SIZE, size);
++
++ if((pi2s_config->pMMAPBufPtr[0]==NULL)&&(pi2s_config->mmap_index!=0))
++ pi2s_config->mmap_index = 0;
++
++ _printk("%s: vm_start=%08X,vm_end=%08X\n", __func__, (u32)vma->vm_start, (u32)vma->vm_end);
++
++ /* Do memory allocate and dma sync */
++ i2s_mmap_alloc(size);
++
++ i2s_mmap_remap(vma, size);
++
++
++ return 0;
++}
++
++int i2s_mem_unmap(i2s_config_type* ptri2s_config)
++{
++ u32 page_size;
++
++ page_size = I2S_PAGE_SIZE;
++
++ if(ptri2s_config->pMMAPBufPtr[0])
++ {
++ _printk("ummap MMAP[0]=0x%08X\n", (u32)ptri2s_config->pMMAPBufPtr[0]);
++ dma_unmap_single(NULL, i2s_mmap_addr[0], MAX_I2S_PAGE*page_size, DMA_BIDIRECTIONAL);
++ kfree(ptri2s_config->pMMAPBufPtr[0]);
++ }
++
++ if(ptri2s_config->pMMAPBufPtr[MAX_I2S_PAGE])
++ {
++ _printk("ummap MMAP[%d]=0x%08X\n", MAX_I2S_PAGE, (u32)ptri2s_config->pMMAPBufPtr[MAX_I2S_PAGE]);
++ dma_unmap_single(NULL, i2s_mmap_addr[MAX_I2S_PAGE], MAX_I2S_PAGE*page_size, DMA_BIDIRECTIONAL);
++ kfree(ptri2s_config->pMMAPBufPtr[MAX_I2S_PAGE]);
++ }
++
++ ptri2s_config->mmap_index = 0;
++
++ return 0;
++}
++
++int i2s_param_init(i2s_config_type* ptri2s_config)
++{
++ ptri2s_config->dmach = GDMA_I2S_TX0;
++ ptri2s_config->tx_ff_thres = CONFIG_I2S_TFF_THRES;
++ ptri2s_config->tx_ch_swap = CONFIG_I2S_CH_SWAP;
++ ptri2s_config->rx_ff_thres = CONFIG_I2S_TFF_THRES;
++ ptri2s_config->rx_ch_swap = CONFIG_I2S_CH_SWAP;
++ ptri2s_config->slave_en = CONFIG_I2S_SLAVE_EN;
++ ptri2s_config->codec_pll_en = CONFIG_I2S_CODEC_PLL_EN;
++
++ ptri2s_config->bRxDMAEnable = 0;
++ ptri2s_config->bTxDMAEnable = 0;
++ //ptri2s_config->bALSAEnable = 0;
++ ptri2s_config->srate = 44100;
++ ptri2s_config->txvol = 0;
++ ptri2s_config->rxvol = 0;
++ ptri2s_config->lbk = 0;
++ ptri2s_config->extlbk = 0;
++ ptri2s_config->txrx_coexist = 0;
++ ptri2s_config->wordlen_24b = 0;
++#if defined(CONFIG_RALINK_MT7628) || defined(CONFIG_ARCH_MT7623)
++ ptri2s_config->sys_endian = 0;
++ ptri2s_config->fmt = 0;
++#endif
++ ptri2s_config->micboost = 0;
++ ptri2s_config->micin = 0;
++
++ return 0;
++}
++
++int i2s_txbuf_alloc(i2s_config_type* ptri2s_config)
++{
++ int i;
++
++ for( i = 0 ; i < MAX_I2S_PAGE ; i ++ )
++ {
++#if defined(CONFIG_I2S_MMAP)
++ ptri2s_config->pMMAPTxBufPtr[i] = ptri2s_config->pMMAPBufPtr[i];
++#else
++ if(ptri2s_config->pMMAPTxBufPtr[i]==NULL)
++ ptri2s_config->pMMAPTxBufPtr[i] = kmalloc(I2S_PAGE_SIZE, GFP_KERNEL);
++#endif
++ memset(ptri2s_config->pMMAPTxBufPtr[i], 0, I2S_PAGE_SIZE);
++ }
++
++ return 0;
++}
++
++int i2s_rxbuf_alloc(i2s_config_type* ptri2s_config)
++{
++ int i;
++
++ for( i = 0 ; i < MAX_I2S_PAGE ; i ++ )
++ {
++#if defined(CONFIG_I2S_MMAP)
++ ptri2s_config->pMMAPRxBufPtr[i] = ptri2s_config->pMMAPBufPtr[i+(ptri2s_config->mmap_index-MAX_I2S_PAGE)];
++#else
++ if(ptri2s_config->pMMAPRxBufPtr[i]==NULL)
++ ptri2s_config->pMMAPRxBufPtr[i] = kmalloc(I2S_PAGE_SIZE, GFP_KERNEL);
++#endif
++ memset(ptri2s_config->pMMAPRxBufPtr[i], 0, I2S_PAGE_SIZE);
++ }
++
++ return 0;
++}
++
++int i2s_txPagebuf_alloc(i2s_config_type* ptri2s_config)
++{
++#if defined(ARM_ARCH)
++ ptri2s_config->pPage0TxBuf8ptr = (u8*)pci_alloc_consistent(NULL, I2S_PAGE_SIZE , &i2s_txdma_addr0);
++ ptri2s_config->pPage1TxBuf8ptr = (u8*)pci_alloc_consistent(NULL, I2S_PAGE_SIZE , &i2s_txdma_addr1);
++ if(ptri2s_config->pPage0TxBuf8ptr==NULL)
++ {
++ MSG("Allocate Tx Page0 Buffer Failed\n");
++ return -1;
++ }
++ if(ptri2s_config->pPage1TxBuf8ptr==NULL)
++ {
++ MSG("Allocate Tx Page1 Buffer Failed\n");
++ return -1;
++ }
++#else
++ ptri2s_config->pPage0TxBuf8ptr = (u8*)pci_alloc_consistent(NULL, I2S_PAGE_SIZE*2 , &i2s_txdma_addr);
++ if(ptri2s_config->pPage0TxBuf8ptr==NULL)
++ {
++ MSG("Allocate Tx Page Buffer Failed\n");
++ return -1;
++ }
++ ptri2s_config->pPage1TxBuf8ptr = ptri2s_config->pPage0TxBuf8ptr + I2S_PAGE_SIZE;
++#endif
++ return 0;
++}
++
++int i2s_rxPagebuf_alloc(i2s_config_type* ptri2s_config)
++{
++#if defined(ARM_ARCH)
++ ptri2s_config->pPage0RxBuf8ptr = (u8*)pci_alloc_consistent(NULL, I2S_PAGE_SIZE, &i2s_rxdma_addr0);
++ ptri2s_config->pPage1RxBuf8ptr = (u8*)pci_alloc_consistent(NULL, I2S_PAGE_SIZE, &i2s_rxdma_addr1);
++ if(ptri2s_config->pPage0RxBuf8ptr==NULL)
++ {
++ MSG("Allocate Rx Page Buffer Failed\n");
++ return -1;
++ }
++ if(ptri2s_config->pPage1RxBuf8ptr==NULL)
++ {
++ MSG("Allocate Rx Page Buffer Failed\n");
++ return -1;
++ }
++#else
++ ptri2s_config->pPage0RxBuf8ptr = (u8*)pci_alloc_consistent(NULL, I2S_PAGE_SIZE*2 , &i2s_rxdma_addr);
++ if(ptri2s_config->pPage0RxBuf8ptr==NULL)
++ {
++ MSG("Allocate Rx Page Buffer Failed\n");
++ return -1;
++ }
++ ptri2s_config->pPage1RxBuf8ptr = ptri2s_config->pPage0RxBuf8ptr + I2S_PAGE_SIZE;
++#endif
++ return 0;
++}
++
++int i2s_txbuf_free(i2s_config_type* ptri2s_config)
++{
++ int i;
++
++ for(i = 0 ; i < MAX_I2S_PAGE ; i ++)
++ {
++ if(ptri2s_config->pMMAPTxBufPtr[i] != NULL)
++ {
++#if defined(CONFIG_I2S_MMAP)
++ ptri2s_config->pMMAPTxBufPtr[i] = NULL;
++#else
++ kfree(ptri2s_config->pMMAPTxBufPtr[i]);
++ ptri2s_config->pMMAPTxBufPtr[i] = NULL;
++#endif
++ }
++ }
++ return 0;
++}
++
++int i2s_rxbuf_free(i2s_config_type* ptri2s_config)
++{
++ int i;
++
++ for(i = 0 ; i < MAX_I2S_PAGE ; i ++)
++ {
++ if(ptri2s_config->pMMAPRxBufPtr[i] != NULL)
++ {
++#if defined(CONFIG_I2S_MMAP)
++ ptri2s_config->pMMAPRxBufPtr[i] = NULL;
++#else
++ kfree(ptri2s_config->pMMAPRxBufPtr[i]);
++ ptri2s_config->pMMAPRxBufPtr[i] = NULL;
++#endif
++ }
++ }
++
++ return 0;
++}
++
++int i2s_txPagebuf_free(i2s_config_type* ptri2s_config)
++{
++#if defined(ARM_ARCH)
++ if (ptri2s_config->pPage0TxBuf8ptr)
++ {
++ pci_free_consistent(NULL, I2S_PAGE_SIZE, ptri2s_config->pPage0TxBuf8ptr, i2s_txdma_addr0);
++ ptri2s_config->pPage0TxBuf8ptr = NULL;
++ }
++
++ if (ptri2s_config->pPage1TxBuf8ptr)
++ {
++ pci_free_consistent(NULL, I2S_PAGE_SIZE, ptri2s_config->pPage1TxBuf8ptr, i2s_txdma_addr1);
++ ptri2s_config->pPage1TxBuf8ptr = NULL;
++ }
++ _printk("Free tx page buffer\n");
++#else
++ if (ptri2s_config->pPage0TxBuf8ptr)
++ {
++ pci_free_consistent(NULL, I2S_PAGE_SIZE*2, ptri2s_config->pPage0TxBuf8ptr, i2s_txdma_addr);
++ ptri2s_config->pPage0TxBuf8ptr = NULL;
++ }
++#endif
++ return 0;
++
++}
++
++int i2s_rxPagebuf_free(i2s_config_type* ptri2s_config)
++{
++#if defined(ARM_ARCH)
++ if (ptri2s_config->pPage0RxBuf8ptr)
++ {
++ pci_free_consistent(NULL, I2S_PAGE_SIZE, ptri2s_config->pPage0RxBuf8ptr, i2s_rxdma_addr0);
++ ptri2s_config->pPage0RxBuf8ptr = NULL;
++ }
++ if (ptri2s_config->pPage1RxBuf8ptr)
++ {
++ pci_free_consistent(NULL, I2S_PAGE_SIZE, ptri2s_config->pPage1RxBuf8ptr, i2s_rxdma_addr1);
++ ptri2s_config->pPage1RxBuf8ptr = NULL;
++ }
++ _printk("Free rx page buffer\n");
++#else
++ if (ptri2s_config->pPage0RxBuf8ptr)
++ {
++ pci_free_consistent(NULL, I2S_PAGE_SIZE*2, ptri2s_config->pPage0RxBuf8ptr, i2s_rxdma_addr);
++ ptri2s_config->pPage0RxBuf8ptr = NULL;
++ }
++#endif
++ return 0;
++}
++
++int i2s_reset_tx_param(i2s_config_type* ptri2s_config)
++{
++ ptri2s_config->tx_isr_cnt = 0;
++ ptri2s_config->tx_w_idx = 0;
++ ptri2s_config->tx_r_idx = 0;
++ ptri2s_config->enLable = 0;
++ ptri2s_config->tx_pause_en = 0;
++ ptri2s_config->end_cnt = 0;
++ ptri2s_config->tx_stop_cnt = 0;
++
++#ifdef I2S_STATISTIC
++ pi2s_status->txbuffer_unrun = 0;
++ pi2s_status->txbuffer_ovrun = 0;
++ pi2s_status->txdmafault = 0;
++ pi2s_status->txovrun = 0;
++ pi2s_status->txunrun = 0;
++ pi2s_status->txthres = 0;
++ pi2s_status->txbuffer_len = 0;
++#endif
++
++ return 0;
++}
++
++int i2s_reset_rx_param(i2s_config_type* ptri2s_config)
++{
++ ptri2s_config->rx_isr_cnt = 0;
++ ptri2s_config->rx_w_idx = 0;
++ ptri2s_config->rx_r_idx = 0;
++ ptri2s_config->enLable = 0;
++ ptri2s_config->rx_pause_en = 0;
++ ptri2s_config->rx_stop_cnt = 0;
++
++#ifdef I2S_STATISTIC
++ pi2s_status->rxbuffer_unrun = 0;
++ pi2s_status->rxbuffer_ovrun = 0;
++ pi2s_status->rxdmafault = 0;
++ pi2s_status->rxovrun = 0;
++ pi2s_status->rxunrun = 0;
++ pi2s_status->rxthres = 0;
++ pi2s_status->rxbuffer_len = 0;
++#endif
++
++ return 0;
++}
++#ifdef MT7621_ASIC_BOARD
++int i2s_pll_config_mt7621(unsigned long index)
++{
++ unsigned long data;
++ unsigned long regValue;
++ bool xtal_20M_en = 0;
++// bool xtal_25M_en = 0;
++ bool xtal_40M_en = 0;
++
++ regValue = i2s_inw(RALINK_SYSCTL_BASE + 0x10);
++ regValue = (regValue >> 6) & 0x7;
++ if (regValue < 3)
++ {
++ xtal_20M_en = 1;
++ MSG("Xtal is 20MHz. \n");
++ }
++ else if (regValue < 6)
++ {
++ xtal_40M_en = 1;
++ MSG("Xtal is 40M.\n");
++ }
++ else
++ {
++ //xtal_25M_en = 1;
++ MSG("Xtal is 25M.\n");
++ }
++
++#if defined (CONFIG_I2S_MCLK_12P288MHZ)
++ _printk("MT7621 provide 12.288M/11.298MHz REFCLK\n");
++ /* Firstly, reset all required register to default value */
++ i2s_outw(RALINK_ANA_CTRL_BASE, 0x00008000);
++ i2s_outw(RALINK_ANA_CTRL_BASE+0x0014, 0x01001d61);//0x01401d61);
++ i2s_outw(RALINK_ANA_CTRL_BASE+0x0018, 0x38233d0e);
++ i2s_outw(RALINK_ANA_CTRL_BASE+0x001c, 0x80100004);//0x80120004);
++ i2s_outw(RALINK_ANA_CTRL_BASE+0x0020, 0x1c7dbf48);
++
++ /* toggle RG_XPTL_CHG */
++ i2s_outw(RALINK_ANA_CTRL_BASE, 0x00008800);
++ i2s_outw(RALINK_ANA_CTRL_BASE, 0x00008c00);
++
++ data = i2s_inw(RALINK_ANA_CTRL_BASE+0x0014);
++ data &= ~(0x0000ffc0);
++ if ((xtal_40M_en) || (xtal_20M_en))
++ {
++ data |= REGBIT(0x1d, 8); /* for 40M or 20M */
++ }
++ else
++ {
++ data |= REGBIT(0x17, 8); /* for 25M */
++ }
++
++ if (xtal_40M_en)
++ {
++ data |= REGBIT(0x1, 6); /* for 40M */
++ }
++ i2s_outw(RALINK_ANA_CTRL_BASE+0x0014, data);
++
++
++ data = i2s_inw(RALINK_ANA_CTRL_BASE+0x0018);
++ data &= ~(0xf0773f00);
++ data |= REGBIT(0x3, 28);
++ data |= REGBIT(0x2, 20);
++ if ((xtal_40M_en) || (xtal_20M_en))
++ {
++ data |= REGBIT(0x3, 16); /* for 40M or 20M */
++ }
++ else
++ {
++ data |= REGBIT(0x2, 16); /* for 25M */
++ }
++ data |= REGBIT(0x3, 12);
++ if ((xtal_40M_en) || (xtal_20M_en))
++ {
++ data |= REGBIT(0xd, 8); /* for 40M or 20M */
++ }
++ else
++ {
++ data |= REGBIT(0x7, 8); /* for 25M */
++ }
++ i2s_outw(RALINK_ANA_CTRL_BASE+0x0018, data);
++
++ if((index==1)|(index==4)|(index==7)|(index==9))// 270 MHz for 22.05K, 44.1K, 88.2K, 176.4K
++ {
++ if ((xtal_40M_en) || (xtal_20M_en))
++ {
++ i2s_outw(RALINK_ANA_CTRL_BASE+0x0020, 0x1a18548a); /* for 40M or 20M */
++ }
++ else
++ {
++ i2s_outw(RALINK_ANA_CTRL_BASE+0x0020, 0x14ad106e); /* for 25M */
++ }
++ }
++ else if ((index==0)|(index==3)|(index==5)|(index==6)|(index==8)|(index==10))// 294 MHZ for 24K, 48K, 96K, 192K
++ {
++ if ((xtal_40M_en) || (xtal_20M_en))
++ {
++ i2s_outw(RALINK_ANA_CTRL_BASE+0x0020, 0x1c7dbf48); /* for 40M or 20M */
++ }
++ else
++ {
++ i2s_outw(RALINK_ANA_CTRL_BASE+0x0020, 0x1697cc39); /* for 25M */
++ }
++ }
++ else if (index==2)
++ {
++ _printk("Not support 12KHz sampling rate!\n");
++ return -1;
++ }
++ else
++ {
++ _printk("Wrong sampling rate!\n");
++ return -1;
++ }
++
++ //*Common setting - Set PLLGP_CTRL_4 *//
++ /* 1. Bit 31 */
++ data = i2s_inw(RALINK_ANA_CTRL_BASE+0x001c);
++ data &= ~(REGBIT(0x1, 31));
++ i2s_outw(RALINK_ANA_CTRL_BASE+0x001c, data);
++ ndelay(10);
++
++ /* 2. Bit 0 */
++ data = i2s_inw(RALINK_ANA_CTRL_BASE+0x001c);
++ data |= REGBIT(0x1, 0);
++ i2s_outw(RALINK_ANA_CTRL_BASE+0x001c, data);
++ udelay(200);
++
++ /* 3. Bit 3 */
++ data = i2s_inw(RALINK_ANA_CTRL_BASE+0x001c);
++ data |= REGBIT(0x1, 3);
++ i2s_outw(RALINK_ANA_CTRL_BASE+0x001c, data);
++ udelay(1);
++
++ /* 4. Bit 8 */
++ data = i2s_inw(RALINK_ANA_CTRL_BASE+0x001c);
++ data |= REGBIT(0x1, 8);
++ i2s_outw(RALINK_ANA_CTRL_BASE+0x001c, data);
++ ndelay(40);
++
++ /* 5. Bit 6 */
++ data = i2s_inw(RALINK_ANA_CTRL_BASE+0x001c);
++ data |= REGBIT(0x1, 6);
++ i2s_outw(RALINK_ANA_CTRL_BASE+0x001c, data);
++ ndelay(40);
++
++ /* 6. Bit 5 & Bit 7*/
++ data = i2s_inw(RALINK_ANA_CTRL_BASE+0x001c);
++ data |= REGBIT(0x1, 5);
++ data |= REGBIT(0x1, 7);
++ i2s_outw(RALINK_ANA_CTRL_BASE+0x001c, data);
++ udelay(1);
++
++ /* 7. Bit 17 */
++ data = i2s_inw(RALINK_ANA_CTRL_BASE+0x001c);
++ data |= REGBIT(0x1, 17);
++ i2s_outw(RALINK_ANA_CTRL_BASE+0x001c, data);
++
++#elif defined(CONFIG_I2S_MCLK_12MHZ)
++ _printk("MT7621 provide 12MHz REFCLK\n");
++ /* Firstly, reset all required register to default value */
++ i2s_outw(RALINK_ANA_CTRL_BASE+0x0014, 0x01401d61);//0x01401d61);
++ i2s_outw(RALINK_ANA_CTRL_BASE+0x001c, 0x80120004);//0x80100004);
++ i2s_outw(RALINK_ANA_CTRL_BASE+0x0018, 0x38233d0e);
++
++ if (xtal_40M_en)
++ {
++ data = i2s_inw(RALINK_ANA_CTRL_BASE+0x001c);
++ data &= ~REGBIT(0x1, 17);
++ i2s_outw(RALINK_ANA_CTRL_BASE+0x001c, data);
++
++ data = i2s_inw(RALINK_ANA_CTRL_BASE+0x0014);
++ data &= ~REGBIT(0x3, 4);
++ data |= REGBIT(0x1, 4);
++ i2s_outw(RALINK_ANA_CTRL_BASE+0x0014, data);
++
++ data = i2s_inw(RALINK_ANA_CTRL_BASE+0x001c);
++ data &= ~REGBIT(0x1, 31);
++ i2s_outw(RALINK_ANA_CTRL_BASE+0x001c, data);
++ }
++ else if (xtal_20M_en)
++ {
++ data = i2s_inw(RALINK_ANA_CTRL_BASE+0x001c);
++ data &= ~REGBIT(0x1, 17);
++ i2s_outw(RALINK_ANA_CTRL_BASE+0x001c, data);
++
++ data = i2s_inw(RALINK_ANA_CTRL_BASE+0x0014);
++ data &= ~REGBIT(0x3, 6);
++ i2s_outw(RALINK_ANA_CTRL_BASE+0x0014, data);
++
++ data = i2s_inw(RALINK_ANA_CTRL_BASE+0x0014);
++ data &= ~REGBIT(0x3, 4);
++ data |= REGBIT(0x1, 4);
++ i2s_outw(RALINK_ANA_CTRL_BASE+0x0014, data);
++
++ data = i2s_inw(RALINK_ANA_CTRL_BASE+0x001c);
++ data &= ~REGBIT(0x1, 31);
++ i2s_outw(RALINK_ANA_CTRL_BASE+0x001c, data);
++ }
++ else
++ {
++ data = i2s_inw(RALINK_ANA_CTRL_BASE+0x001c);
++ data &= ~REGBIT(0x1, 17);
++ i2s_outw(RALINK_ANA_CTRL_BASE+0x001c, data);
++
++ data = i2s_inw(RALINK_ANA_CTRL_BASE+0x0014);
++ data &= ~REGBIT(0x7f, 8);
++ data |= REGBIT(0x17, 8);
++ i2s_outw(RALINK_ANA_CTRL_BASE+0x0014, data);
++
++ data = i2s_inw(RALINK_ANA_CTRL_BASE+0x0014);
++ data &= ~REGBIT(0x3, 6);
++ i2s_outw(RALINK_ANA_CTRL_BASE+0x0014, data);
++
++ data = i2s_inw(RALINK_ANA_CTRL_BASE+0x0018);
++ data &= ~REGBIT(0x7, 16);
++ data |= REGBIT(0x2, 16);
++ i2s_outw(RALINK_ANA_CTRL_BASE+0x0018, data);
++
++ data = i2s_inw(RALINK_ANA_CTRL_BASE+0x0018);
++ data &= ~REGBIT(0xf, 8);
++ data |= REGBIT(0x7, 8);
++ i2s_outw(RALINK_ANA_CTRL_BASE+0x0018, data);
++
++
++ data = i2s_inw(RALINK_ANA_CTRL_BASE+0x0014);
++ data &= ~REGBIT(0x3, 4);
++ data |= REGBIT(0x1, 4);
++ i2s_outw(RALINK_ANA_CTRL_BASE+0x0014, data);
++
++ data = i2s_inw(RALINK_ANA_CTRL_BASE+0x001c);
++ data &= ~REGBIT(0x1, 31);
++ i2s_outw(RALINK_ANA_CTRL_BASE+0x001c, data);
++
++ }
++#endif
++ return 0;
++}
++#if defined(CONFIG_I2S_IN_MCLK)
++int i2s_pll_refclk_set(void)
++{
++ unsigned long data;
++
++ /* Set APLL register for REFCLK */
++ data = i2s_inw(RALINK_SYSCTL_BASE+0x90);
++ data &= ~(0x0000f000);
++ data |= REGBIT(0x1, 12);
++ i2s_outw(RALINK_SYSCTL_BASE+0x0090, data);
++
++ data = i2s_inw(RALINK_SYSCTL_BASE+0x0090);
++ data &= ~(0x00000300);
++ i2s_outw(RALINK_SYSCTL_BASE+0x0090, data);
++ MSG("Set 0x90 register\n");
++
++ return 0;
++}
++#endif
++#endif
++
++#ifdef MT7623_ASIC_BOARD
++int i2s_pll_config_mt7623(unsigned long index)
++{
++ unsigned long data;
++
++ /* xPLL PWR ON */
++ data = i2s_inw(AUD2PLL_PWR_CON0);
++ data |= 0x1;
++ i2s_outw(AUD2PLL_PWR_CON0, data);
++ udelay(5);
++
++ /* xPLL ISO Disable */
++ data = i2s_inw(AUD2PLL_PWR_CON0);
++ data &= ~(0x2);
++ i2s_outw(AUD2PLL_PWR_CON0, data);
++
++ /* xPLL Frequency Set */
++ data = i2s_inw(AUD2PLL_CON0);
++ data |= 0x1;
++ i2s_outw(AUD2PLL_CON0, data);
++
++ /* AUD1PLL Frequency Set(change from 98.304MHz to 294.912MHz) */
++ i2s_outw(AUD1PLL_CON0, 0x121);
++ i2s_outw(AUD1PLL_CON1, 0xad5efee6);
++ udelay(40);
++
++ /* Audio clock setting */
++ if((index==1)|(index==4)|(index==7)|(index==9)|(index==11))// for 22.05K, 44.1K, 88.2K, 176.4K
++ {
++ _printk("\n*****%s:index=%d(270MHz)*****\n", __func__, (int)index);
++ data = i2s_inw(0xFB00002c);
++ //data &= ~REGBIT(0x8, 1);
++ data &= ~(0x80);
++ i2s_outw(0xFB00002C, data); /* AUD1PLL 270.9204MHz */
++ }
++ else if ((index==0)|(index==3)|(index==5)|(index==6)|(index==8)|(index==10)|(index==12)) //for 24K, 48K, 96K, 192K
++ {
++ _printk("\n*****%s:index=%d(294MHz)*****\n", __func__, (int)index);
++ data = i2s_inw(0xFB00002c);
++ //data |= REGBIT(0x8, 1);
++ data |= (0x80);
++ i2s_outw(0xFB00002c, data); /* AUD1PLL 294.912MHz */
++ }
++ else if (index==2)
++ {
++ _printk("Not support 12KHz sampling rate!\n");
++ return -1;
++ }
++ else
++ {
++ _printk("Wrong sampling rate!\n");
++ return -1;
++ }
++ return 0;
++}
++#endif
++
++#if defined(MT7628_ASIC_BOARD) || defined(CONFIG_ARCH_MT7623)
++int i2s_driving_strength_adjust(void)
++{
++#if defined(MT7628_ASIC_BOARD)
++ unsigned long data;
++
++ MSG("Adjust MT7628 current's driving strngth\n");
++ /* Adjust REFCLK0's driving strength of current which can avoid
++ * the glitch of REFCKL0
++ * E4 = 0xb0001354[5]; E8 = 0xb0001364[5]
++ * (E4,E8)=(0,0)-> 4 mA;
++ * =(1,0)-> 8 mA;
++ * =(0,1)-> 12 mA;
++ * =(1,1)-> 16 mA*/
++
++ /* Set to 12mA */
++ data = i2s_inw(0xb0001354);
++ data &= ~(0x1<<5);
++ i2s_outw(0xb0001354, data);
++
++ data = i2s_inw(0xb0001364);
++ data |= (0x1<<5);
++ i2s_outw(0xb0001364, data);
++#endif
++#if defined(CONFIG_ARCH_MT7623)
++ MSG("Adjust MT7623 current's driving strngth\n");
++
++ i2s_outw(0xF0005F80, 0x7777);
++#endif
++
++ return 0;
++}
++#endif
++
++#if defined(CONFIG_I2S_IN_MCLK)
++#if defined(CONFIG_I2S_MCLK_12MHZ)
++int i2s_refclk_12m_enable(void)
++{
++ unsigned long data;
++
++ MSG("Enable SoC MCLK 12Mhz\n");
++
++#if defined(CONFIG_RALINK_RT6855A)
++ data = i2s_inw(RALINK_SYSCTL_BASE+0x860);
++ data |= (0x1<<17);
++ data &= ~(0x7<<18);
++ data |= (0x1<<18);
++ i2s_outw(RALINK_SYSCTL_BASE+0x860, data);
++#elif defined(CONFIG_RALINK_RT3350)
++ data = i2s_inw(RALINK_SYSCTL_BASE+0x2c);
++ data |= (0x1<<8);
++ i2s_outw(RALINK_SYSCTL_BASE+0x2c, data);
++#elif defined(CONFIG_RALINK_RT3883)
++ data = i2s_inw(RALINK_SYSCTL_BASE+0x2c);
++ data &= ~(0x03<<13);
++ data |= (0x1<<13);
++ i2s_outw(RALINK_SYSCTL_BASE+0x2c, data);
++#elif defined(CONFIG_RALINK_RT3352)||defined(CONFIG_RALINK_RT5350) || defined (CONFIG_RALINK_RT6855)
++ data = i2s_inw(RALINK_SYSCTL_BASE+0x2c);
++ data &= ~(0x0F<<8);
++ data |= (0x3<<8);
++ i2s_outw(RALINK_SYSCTL_BASE+0x2c, data);
++#elif defined(CONFIG_RALINK_MT7620)
++ data = i2s_inw(RALINK_SYSCTL_BASE+0x2c);
++ data &= ~(0x07<<9);
++ data |= (1<<9);
++ i2s_outw(RALINK_SYSCTL_BASE+0x2c, data);
++#elif defined(CONFIG_RALINK_MT7621)
++ data = i2s_inw(RALINK_SYSCTL_BASE+0x2c);
++ data &= ~(0x1f<<18);
++ data |= REGBIT(0x19, 18);
++ data &= ~(0x1f<<12);
++ data |= REGBIT(0x1, 12);
++ data &= ~(0x7<<9);
++ data |= REGBIT(0x5, 9);
++ i2s_outw(RALINK_SYSCTL_BASE+0x2c, data);
++#elif defined(CONFIG_RALINK_MT7628)
++ data = i2s_inw(RALINK_SYSCTL_BASE+0x2c);
++ MSG("turn on REFCLK output for MCLK1\n");
++ data &= ~(0x7<<9);
++ data |= (0x1<<9); /* output for MCLK */
++ i2s_outw(RALINK_SYSCTL_BASE+0x2c, data);
++#else
++ #error "This SoC does not provide 12MHz clock to audio codec\n");
++#endif
++ i2s_refclk_gpio_out_config();
++
++ return 0;
++}
++#endif
++
++#if defined(CONFIG_I2S_MCLK_12P288MHZ)
++int i2s_refclk_12p288m_enable(void)
++{
++ unsigned long data;
++ MSG("Enable SoC MCLK 12.288Mhz\n");
++
++#if defined(CONFIG_RALINK_RT3352)||defined(CONFIG_RALINK_RT5350) || defined (CONFIG_RALINK_RT6855)
++ data = i2s_inw(RALINK_SYSCTL_BASE+0x2c);
++ data &= ~(0x01F<<18);
++ data |= 31<<18;
++ data &= ~(0x01F<<12);
++ data |= 1<<12;
++ data |= (0xF<<8);
++ i2s_outw(RALINK_SYSCTL_BASE+0x2c, data);
++#elif defined(CONFIG_RALINK_MT7621)
++ data = i2s_inw(RALINK_SYSCTL_BASE+0x2c);
++ data &= ~(0x1f<<18);
++ data |= REGBIT(0xc, 18);
++ data &= ~(0x1f<<12);
++ data |= REGBIT(0x1, 12);
++ data &= ~(0x7<<9);
++ data |= REGBIT(0x5, 9);
++ i2s_outw(RALINK_SYSCTL_BASE+0x2c, data);
++ _printk("MT7621 provide REFCLK 12.288MHz/11.289MHz\n");
++#elif defined(CONFIG_ARCH_MT7623)
++ /* MT7623 does not need to set divider for REFCLK */
++ /* GPIO126 - I2S0_MCLK */
++ data = i2s_inw(0xF00058F0);
++ data &= ~(0x7<<3);
++ data |= (0x6<<3);
++ i2s_outw(0xF00058F0, data);
++ /* GPIO_DIR8: OUT */
++ data = i2s_inw(0xF0005070);
++ data |= (0x1<<14);
++ i2s_outw(0xF0005070, data);
++#else
++ #error "This SoC does not provide 12.288Mhz clock to audio codec\n");
++#endif
++
++ return 0;
++}
++#endif
++
++#if defined(CONFIG_I2S_MCLK_18P432MHZ)
++int i2s_refclk_18p432m_enable(unsigned long index)
++{
++ unsigned long data;
++ MSG("Enable SoC MCLK 18.432MHz/16.934MHz");
++
++ if((index==1)|(index==4)|(index==7)|(index==9))// 16.934MHz for 22.05K, 44.1K, 88.2K, 176.4K
++ {
++ data = i2s_inw(ETHDMASYS_SYSCTL_BASE+0x2c);
++ data &= ~(0x1<<7);
++ i2s_outw(ETHDMASYS_SYSCTL_BASE+0x2c, data);
++ }
++ else if((index==0)|(index==3)|(index==5)|(index==6)|(index==8)|(index==10))// 18.432MHZ for 24K, 48K, 96K, 192K
++ {
++ data = i2s_inw(ETHDMASYS_SYSCTL_BASE+0x2c);
++ data |= (0x1<<7);
++ i2s_outw(ETHDMASYS_SYSCTL_BASE+0x2c, data);
++ }
++
++ data = i2s_inw(ETHDMASYS_SYSCTL_BASE+0x30);
++ data |= (0x1<<17);
++ i2s_outw(ETHDMASYS_SYSCTL_BASE+0x30, data);
++
++ return 0;
++}
++#endif
++#endif
++
++int i2s_refclk_disable(void)
++{
++ unsigned long data;
++
++#if defined(CONFIG_RALINK_RT6855A)
++ data = i2s_inw(RALINK_SYSCTL_BASE+0x860);
++ data &= ~(1<<17);
++ i2s_outw(RALINK_SYSCTL_BASE+0x860, data);
++#elif defined(CONFIG_RALINK_RT3350)
++ data = i2s_inw(RALINK_SYSCTL_BASE+0x2c);
++ data &= ~(0x1<<8);
++ i2s_outw(RALINK_SYSCTL_BASE+0x2c, data);
++#elif defined(CONFIG_RALINK_RT3883)
++ data = i2s_inw(RALINK_SYSCTL_BASE+0x2c);
++ data &= ~(0x0F<<13);
++ i2s_outw(RALINK_SYSCTL_BASE+0x2c, data);
++#elif defined(CONFIG_RALINK_RT3352)||defined(CONFIG_RALINK_RT5350)||defined (CONFIG_RALINK_RT6855)
++ data = i2s_inw(RALINK_SYSCTL_BASE+0x2c);
++ data &= ~(0x0F<<8);
++ i2s_outw(RALINK_SYSCTL_BASE+0x2c, data);
++#elif defined (CONFIG_RALINK_MT7620)||defined (CONFIG_RALINK_MT7621)||defined (CONFIG_RALINK_MT7628)
++ _printk("turn off REFCLK output from internal CLK\n");
++ data = i2s_inw(RALINK_SYSCTL_BASE+0x2c);
++ data &= ~(0x07<<9);
++ i2s_outw(RALINK_SYSCTL_BASE+0x2c, data);
++#elif defined (CONFIG_ARCH_MT7623) /*FIXME:2*/
++#ifdef MT7623_ASIC_BOARD
++ _printk("turn off REFCLK output from internal CLK\n");
++ /* GPIO126 - I2S0_MCLK */
++ data = i2s_inw(0xF00058F0);
++ data &= ~(0x7<<3);
++ //data |= (0x2<<3);
++ i2s_outw(0xF00058F0, data);
++ /* GPIO126 => GPIO_DIR8: IN */
++ data = i2s_inw(0xF0005070);
++ data &= ~(0x1<<14);
++ i2s_outw(0xF0005070, data);
++#else
++ _printk("turn off REFCLK output from internal CLK\n");
++ data = i2s_inw(ETHDMASYS_SYSCTL_BASE+0x30);
++ data &= ~(0x1<<17);
++ i2s_outw(ETHDMASYS_SYSCTL_BASE+0x30, data);
++#endif
++#endif
++ return 0;
++}
++
++int i2s_refclk_gpio_out_config(void)
++{
++#ifndef CONFIG_ARCH_MT7623
++ unsigned long data; /* FIXME */
++#endif
++
++ /* Set REFCLK GPIO pin as REFCLK mode*/
++#if defined(CONFIG_RALINK_MT7620)
++ data = i2s_inw(RALINK_SYSCTL_BASE+0x60);
++ data &= ~(0x03<<21); /* WDT */
++ data |= (1<<21);
++ //data &= ~(0x03<<16); /* PERST */
++ //data |= (1<<16);
++ i2s_outw(RALINK_SYSCTL_BASE+0x60, data);
++#endif
++#if defined(CONFIG_RALINK_MT7621)
++ data = i2s_inw(RALINK_SYSCTL_BASE+0x60);
++ //data &= ~(0x3<<10); /* PERST */
++ //data |= (0x2<<10);
++ data &= ~(0x3<<8); /* WDT */
++ data |= (0x2<<8);
++ i2s_outw(RALINK_SYSCTL_BASE+0x60, data);
++ MSG("Set 0x60 register\n");
++#endif
++#if defined(CONFIG_RALINK_MT7628)
++ data = i2s_inw(RALINK_SYSCTL_BASE+0x60);
++ data &= ~(0x1<<18);
++ i2s_outw(RALINK_SYSCTL_BASE+0x60, data);
++#endif
++
++ return 0;
++}
++
++int i2s_refclk_gpio_in_config(void)
++{
++#ifndef CONFIG_ARCH_MT7623
++ unsigned long data; /* FIXME */
++#endif
++
++#if defined (CONFIG_RALINK_MT7620)
++ data = i2s_inw(RALINK_SYSCTL_BASE+0x60);
++ data &= ~(0x03<<21); /* WDT */
++ data |= (1<<21);
++ //data &= ~(0x03<<16); /* PERST */
++ //data |= (1<<16);
++ i2s_outw(RALINK_SYSCTL_BASE+0x60, data);
++
++ data = i2s_inw(RALINK_PIO_BASE);
++ data &= ~(0x1<<17); /* GPIO share ping 17 for WDT */
++ i2s_outw(RALINK_PIO_BASE, data);
++
++ //data = i2s_inw(RALINK_PIO_BASE+0x04);
++ //data &= ~(0x1<<4); /* GPIO share ping 36 for PERST */
++ //i2s_outw(RALINK_PIO_BASE+0x04, data);
++#endif
++#if defined (CONFIG_RALINK_MT7621)
++ data = i2s_inw(RALINK_SYSCTL_BASE+0x60);
++ //data &= ~(0x3<<10); /* PERST */
++ //data |= (0x1<<10);
++ data &= ~(0x3<<8); /* WDT */
++ data |= (0x1<<8);
++ i2s_outw(RALINK_SYSCTL_BASE+0x60, data);
++
++ data = i2s_inw(RALINK_PIO_BASE);
++ //data &= ~(0x1<<19); /* GPIO share ping 19 for RERST */
++ data &= ~(0x1<<18); /* GPIO share ping 18 for WDT */
++ i2s_outw(RALINK_PIO_BASE, data);
++#endif
++#if defined (CONFIG_RALINK_MT7628)
++ /* To use external OSC, set REFCLK_GPIO ping as GPIO mode and set it as input direction */
++ data = i2s_inw(RALINK_SYSCTL_BASE+0x60);
++ data |= (0x1<<18);
++ i2s_outw(RALINK_SYSCTL_BASE+0x60, data);
++
++ data = i2s_inw(RALINK_PIO_BASE+0x04);
++ data &= ~(0x1<<5); /* GPIO share ping 37*/
++ i2s_outw(RALINK_PIO_BASE+0x04, data);
++#endif
++
++ return 0;
++}
++
++int i2s_slave_clock_gpio_in_mt7623(void)
++{
++ unsigned long data;
++
++ /* GPIO74(I2S0_BCLK)=>GPIO_DIR5: IN */
++ data = i2s_inw(0xF0005040);
++ data &= ~(0x1<<10);
++ i2s_outw(0xF0005040, data);
++
++ /* GPIO73(I2S0_LRCK)=>GPIO_DIR5: IN */
++ data = i2s_inw(0xF0005040);
++ data &= ~(0x1<<9);
++ i2s_outw(0xF0005040, data);
++
++ _printk("i2s_slave_clock_gpio_in_mt7623\n");
++
++ return 0;
++}
++
++int i2s_master_clock_gpio_out_mt7623(void)
++{
++ unsigned long data;
++
++ /* GPIO74(I2S0_BCLK)=>GPIO_DIR5: OUT */
++ data = i2s_inw(0xF0005040);
++ data |= (0x1<<10);
++ i2s_outw(0xF0005040, data);
++
++ /* GPIO73(I2S0_LRCK)=>GPIO_DIR5: OUT */
++ data = i2s_inw(0xF0005040);
++ data |= (0x1<<9);
++ i2s_outw(0xF0005040, data);
++
++ _printk("i2s_master_clock_gpio_out_mt7623\n");
++
++ return 0;
++}
++
++int i2s_share_pin_mt7623(i2s_config_type* ptri2s_config)
++{
++ unsigned long data;
++
++ _printk("\nConfig MT7623 I2S pinmux\n");
++ /* GPIO74 - I2S0_BCLK */
++ data = i2s_inw(0xF0005840);
++ data &= ~(0x7<<12);
++ data |= (0x6<<12);
++ i2s_outw(0xF0005840, data);
++
++ /* GPIO73 - I2S0_LRCK */
++ data = i2s_inw(0xF0005840);
++ data &= ~(0x7<<9);
++ data |= (0x6<<9);
++ i2s_outw(0xF0005840, data);
++
++ if(ptri2s_config->slave_en==0)
++ i2s_master_clock_gpio_out_mt7623();
++ else
++ i2s_slave_clock_gpio_in_mt7623();
++
++ /* GPIO49 - I2S0_DATA */
++ data = i2s_inw(0xF00057F0);
++ data &= ~(0x7<<12);
++ data |= (0x6<<12);
++ i2s_outw(0xF00057F0, data);
++ /* GPIO_DIR4: OUT */
++ data = i2s_inw(0xF0005030);
++ data |= (0x1<<1);
++ i2s_outw(0xF0005030, data);
++
++ /* GPIO72 - I2S0_DATA_IN */
++ data = i2s_inw(0xF0005840);
++ data &= ~(0x7<<6);
++ data |= (0x6<<6);
++ i2s_outw(0xF0005840, data);
++ /* GPIO_DIR5: IN */
++ data = i2s_inw(0xF0005040);
++ data &= ~(0x1<<8);
++ i2s_outw(0xF0005040, data);
++
++ return 0;
++}
++
++int i2s_share_pin_config(i2s_config_type* ptri2s_config)
++{
++#ifndef CONFIG_ARCH_MT7623
++ unsigned long data; /*FIXME*/
++#endif
++
++ /* set share pins to i2s/gpio mode and i2c mode */
++#if defined(CONFIG_RALINK_RT6855A)
++ data = i2s_inw(RALINK_SYSCTL_BASE+0x860);
++ data |= 0x00008080;
++ i2s_outw(RALINK_SYSCTL_BASE+0x860, data);
++#elif defined(CONFIG_RALINK_MT7621)
++ data = i2s_inw(RALINK_SYSCTL_BASE+0x60);
++ data &= 0xFFFFFFE3;
++ data |= 0x00000010;
++ i2s_outw(RALINK_SYSCTL_BASE+0x60, data);
++#elif defined(CONFIG_RALINK_MT7628)
++ data = i2s_inw(RALINK_SYSCTL_BASE+0x60);
++ data &= ~(0x3<<6); /* I2S_MODE */
++ data &= ~(0x3<<20); /* I2C_MODE */
++ i2s_outw(RALINK_SYSCTL_BASE+0x60, data);
++#elif defined(CONFIG_ARCH_MT7623)
++ i2s_share_pin_mt7623(ptri2s_config);
++#else
++ data = i2s_inw(RALINK_SYSCTL_BASE+0x60);
++ data &= 0xFFFFFFE2;
++ data |= 0x00000018;
++ i2s_outw(RALINK_SYSCTL_BASE+0x60, data);
++#endif
++ return 0;
++}
++
++int i2s_ws_config(i2s_config_type* ptri2s_config, unsigned long index)
++{
++ unsigned long data;
++ unsigned long* pTable;
++
++#if defined(CONFIG_I2S_IN_CLK)
++ /* REFCLK is 15.625Mhz or 40Mhz(fractional division) */
++#if defined(CONFIG_I2S_FRAC_DIV)
++ MSG("Internal REFCLK with fractional division\n");
++#if defined(CONFIG_RALINK_MT7628) || defined(CONFIG_ARCH_MT7623)
++ if (ptri2s_config->wordlen_24b == 1)
++ {
++ MSG("24 bit int table\n");
++ pTable = i2s_inclk_int_24bit;
++ }
++ else
++ {
++ MSG("16 bit int table\n");
++ pTable = i2s_inclk_int_16bit;
++ }
++#else
++ pTable = i2s_inclk_int;
++#endif /* CONFIG_RALINK_MT7628 */
++
++ data = (unsigned long)(pTable[index]);
++ i2s_outw(I2S_DIVINT_CFG, data);
++
++#if defined(CONFIG_RALINK_MT7628) || defined(CONFIG_ARCH_MT7623)
++ if (ptri2s_config->wordlen_24b == 1)
++ {
++ MSG("24 bit comp table\n");
++ pTable = i2s_inclk_comp_24bit;
++ }
++ else
++ {
++ MSG("16 bit comp table\n");
++ pTable = i2s_inclk_comp_16bit;
++ }
++#else
++ pTable = i2s_inclk_comp;
++#endif /* CONFIG_RALINK_MT7628 */
++
++ data = (unsigned long)(pTable[index]);
++ data |= REGBIT(1, I2S_CLKDIV_EN);
++ i2s_outw(I2S_DIVCOMP_CFG, data);
++#else
++ MSG("Internal REFCLK 15.625Mhz \n");
++ pTable = i2s_inclk_15p625Mhz;
++ data = i2s_inw(RALINK_SYSCTL_BASE+0x30);
++ data &= 0xFFFF00FF;
++ data |= (unsigned long)(pTable[index]);
++ data |= 0x00008000;
++ i2s_outw(RALINK_SYSCTL_BASE+0x30, data);
++#endif /* CONFIG_I2S_FRAC_DIV */
++#else
++#if defined(CONFIG_I2S_MCLK_12MHZ)
++ /* REFCLK = MCLK = 12Mhz */
++ MSG("External REFCLK 12Mhz \n");
++ pTable = i2s_exclk_12Mhz;
++ data = i2s_inw(RALINK_SYSCTL_BASE+0x30);
++ data &= 0xFFFF00FF;
++ data |= (unsigned long)(pTable[index]);
++ data |= 0x0000C000;
++ i2s_outw(RALINK_SYSCTL_BASE+0x30, data);
++#else
++ /* REFCLK = MCLK = 12.288Mhz */
++ pTable = i2s_exclk_12p288Mhz;
++ MSG("External REFCLK 12.288Mhz \n");
++ data = i2s_inw(RALINK_SYSCTL_BASE+0x30);
++ data &= 0xFFFF00FF;
++ data |= (unsigned long)(pTable[index]);
++ data |= 0x0000C000;
++ i2s_outw(RALINK_SYSCTL_BASE+0x30, data);
++#endif /* CONFIG_I2S_MCLK_12MHZ */
++#endif /* Not CONFIG_I2S_IN_CLK */
++
++#if defined(CONFIG_I2S_WS_EDGE)
++ data = i2s_inw(I2S_I2SCFG);
++ data |= REGBIT(0x1, I2S_WS_INV);
++ i2s_outw(I2S_I2SCFG, data);
++#endif
++
++ return 0;
++}
++
++int i2s_mode_config(u32 slave_en)
++{
++ unsigned long data;
++
++ if(slave_en==0)
++ {
++ /* Master mode*/
++ _printk("This SoC is in Master mode\n");
++#if defined(CONFIG_RALINK_RT3052)
++ data = i2s_inw(I2S_I2SCFG);
++ data &= ~REGBIT(0x1, I2S_SLAVE_EN);
++ data &= ~REGBIT(0x1, I2S_CLK_OUT_DIS);
++ i2s_outw(I2S_I2SCFG, data);
++#elif defined(CONFIG_RALINK_RT3883)||defined(CONFIG_RALINK_RT3352)||\
++ defined(CONFIG_RALINK_RT5350)||defined(CONFIG_RALINK_RT6855)||\
++ defined(CONFIG_RALINK_MT7620)||defined(CONFIG_RALINK_RT6855A)||\
++ defined(CONFIG_RALINK_MT7621)||defined(CONFIG_RALINK_MT7628)||\
++ defined(CONFIG_ARCH_MT7623)
++ data = i2s_inw(I2S_I2SCFG);
++ data &= ~REGBIT(0x1, I2S_SLAVE_MODE);
++ i2s_outw(I2S_I2SCFG, data);
++#else
++ #error "a strange clock mode"
++#endif
++ }
++ else
++ {
++ /* Slave mode */
++ _printk("This SoC is in Slave mode\n");
++#if defined(CONFIG_RALINK_RT3052)
++ data = i2s_inw(I2S_I2SCFG);
++ data |= REGBIT(0x1, I2S_SLAVE_EN);
++ data |= REGBIT(0x1, I2S_CLK_OUT_DIS);
++ i2s_outw(I2S_I2SCFG, data);
++#elif defined(CONFIG_RALINK_RT3883)||defined(CONFIG_RALINK_RT3352)||\
++ defined(CONFIG_RALINK_RT5350)||defined(CONFIG_RALINK_RT6855)||\
++ defined(CONFIG_RALINK_MT7620)||defined(CONFIG_RALINK_RT6855A)||\
++ defined(CONFIG_RALINK_MT7621)||defined(CONFIG_RALINK_MT7628)||\
++ defined(CONFIG_ARCH_MT7623)
++ data = i2s_inw(I2S_I2SCFG);
++ data |= REGBIT(0x1, I2S_SLAVE_MODE);
++ i2s_outw(I2S_I2SCFG, data);
++#else
++ #error "a strange clock mode "
++#endif
++ }
++
++ return 0;
++}
++
++int i2s_codec_frequency_config(i2s_config_type* ptri2s_config, unsigned long index)
++{
++#if defined(CONFIG_I2S_WM8960)||defined(CONFIG_I2S_WM8750)||defined(CONFIG_I2S_WM8751)
++ unsigned long data;
++ unsigned long* pTable;
++#endif
++
++#if defined(CONFIG_I2S_MCLK_12MHZ)
++#if defined(CONFIG_I2S_WM8960)||defined(CONFIG_I2S_WM8750)||defined(CONFIG_I2S_WM8751)
++ pTable = i2s_codec_12Mhz;
++ data = pTable[index];
++#endif
++#if defined(CONFIG_I2S_WM8960)
++ audiohw_set_frequency(data, ptri2s_config->codec_pll_en);
++#elif defined(CONFIG_I2S_WM8750)||defined(CONFIG_I2S_WM8751)
++ audiohw_set_frequency(data|0x01);
++#endif
++#else
++#if defined(CONFIG_I2S_WM8960)||defined(CONFIG_I2S_WM8750)||defined(CONFIG_I2S_WM8751)
++#if defined(MT7623_FPGA_BOARD) && defined(CONFIG_I2S_WM8750)
++ pTable = i2s_codec_18p432Mhz;
++#else
++ pTable = i2s_codec_12p288Mhz;
++#endif
++ data = pTable[index];
++#endif
++#if defined(CONFIG_I2S_WM8960)
++ audiohw_set_frequency(data, ptri2s_config->codec_pll_en);
++#elif defined(CONFIG_I2S_WM8750)||defined(CONFIG_I2S_WM8751)
++ audiohw_set_frequency(data);
++#endif
++#endif
++ return 0;
++}
++
++/*
++ * Ralink Audio System Clock Enable
++ *
++ * I2S_WS : signal direction opposite to/same as I2S_CLK
++ *
++ * I2S_CLK : Integer division or fractional division
++ * REFCLK from Internal or External (external REFCLK not support for fractional division)
++ * Suppose external REFCLK always be the same as external MCLK
++ *
++ * MCLK : External OSC or internal generation
++ *
++ */
++int i2s_clock_enable(i2s_config_type* ptri2s_config)
++{
++ unsigned long index;
++ /* audio sampling rate decision */
++ switch(ptri2s_config->srate)
++ {
++ case 8000:
++ index = 0;
++ break;
++ case 11025:
++ index = 1;
++ break;
++ case 12000:
++ index = 2;
++ break;
++ case 16000:
++ index = 3;
++ break;
++ case 22050:
++ index = 4;
++ break;
++ case 24000:
++ index = 5;
++ break;
++ case 32000:
++ index = 6;
++ break;
++ case 44100:
++ index = 7;
++ break;
++ case 48000:
++ index = 8;
++ break;
++ case 88200:
++ index = 9;
++ break;
++ case 96000:
++ index = 10;
++ break;
++#if defined(CONFIG_RALINK_MT7628) || defined(CONFIG_ARCH_MT7623)
++ case 176000:
++ index = 11;
++ break;
++ case 192000:
++ index = 12;
++ break;
++#endif
++ default:
++ index = 7;
++ }
++#ifdef MT7621_ASIC_BOARD
++ /* Set pll config */
++ i2s_pll_config_mt7621(index);
++#endif
++#ifdef MT7623_ASIC_BOARD
++ /* Set pll config */
++ i2s_pll_config_mt7623(index);
++#endif
++
++ /* enable internal MCLK */
++#if defined(CONFIG_I2S_IN_MCLK)
++#if defined(CONFIG_RALINK_MT7621)
++ i2s_pll_refclk_set();
++#endif
++#if defined(CONFIG_I2S_MCLK_12MHZ)
++#if defined(MT7628_ASIC_BOARD) || defined(CONFIG_ARCH_MT7623)
++ i2s_driving_strength_adjust();
++#endif
++ i2s_refclk_12m_enable();
++#endif /* MCLK_12MHZ */
++#if defined(CONFIG_I2S_MCLK_12P288MHZ)
++ i2s_refclk_12p288m_enable();
++#endif /* MCLK_12P288MHZ */
++#if defined(CONFIG_I2S_MCLK_18P432MHZ)
++ i2s_refclk_18p432m_enable(index);
++#endif
++ i2s_refclk_gpio_out_config();
++
++#else
++ MSG("Disable SoC MCLK, use external OSC\n");
++ i2s_refclk_disable();
++ i2s_refclk_gpio_in_config();
++#endif /* CONFIG_I2S_IN_MCLK */
++
++ i2s_share_pin_config(ptri2s_config);
++
++ if(ptri2s_config->slave_en==0)
++ {
++ /* Setup I2S_WS and I2S_CLK */
++ i2s_ws_config(ptri2s_config, index);
++ }
++
++ i2s_mode_config(ptri2s_config->slave_en);
++
++ if(!ptri2s_config->bALSAEnable)
++ {
++#if defined(CONFIG_I2S_WM8750) || defined(CONFIG_I2S_WM8751)|| defined(CONFIG_I2S_WM8960)
++ i2s_codec_enable(ptri2s_config);
++#endif
++ i2s_codec_frequency_config(ptri2s_config,index);
++ }
++
++ return 0;
++}
++
++int i2s_clock_disable(i2s_config_type* ptri2s_config)
++{
++ if(!ptri2s_config->bALSAEnable)
++ {
++#if defined(CONFIG_I2S_WM8960) || defined(CONFIG_I2S_WM8750) || defined(CONFIG_I2S_WM8751)
++ i2s_codec_disable(ptri2s_config);
++#endif
++ }
++
++ /* disable internal MCLK */
++#if defined(CONFIG_I2S_IN_MCLK)
++ i2s_refclk_disable();
++ i2s_refclk_gpio_in_config();
++#endif
++ return 0;
++}
++
++
++int i2s_codec_enable(i2s_config_type* ptri2s_config)
++{
++
++ int AIn = 0, AOut = 0;
++#if 1
++#if defined(CONFIG_I2S_WM8960) || defined(CONFIG_I2S_WM8750) || defined(CONFIG_I2S_WM8751)
++ /* Codec initialization */
++ audiohw_preinit();
++#endif
++#endif
++
++#if defined(CONFIG_I2S_WM8960)
++ if(ptri2s_config->codec_pll_en)
++ {
++ MSG("Codec PLL EN = %d\n", pi2s_config->codec_pll_en);
++ audiohw_set_apll(ptri2s_config->srate);
++ }
++#endif
++
++#if defined(CONFIG_I2S_TXRX)
++ if((ptri2s_config->bTxDMAEnable) || (ptri2s_config->txrx_coexist))
++ AOut = 1;
++ if((ptri2s_config->bRxDMAEnable) || (ptri2s_config->txrx_coexist))
++ AIn = 1;
++#if defined(CONFIG_I2S_WM8960)
++ audiohw_postinit(!(ptri2s_config->slave_en), AIn, AOut, ptri2s_config->codec_pll_en, ptri2s_config->wordlen_24b);
++ audiohw_micboost(ptri2s_config->micboost);
++ audiohw_micin(ptri2s_config->micin);
++#elif defined(CONFIG_I2S_WM8750)
++ audiohw_postinit(!(ptri2s_config->slave_en), AIn, AOut, ptri2s_config->wordlen_24b);
++#endif
++ MSG("AOut=%d, AIn=%d\n", AOut, AIn);
++#else
++#if defined(CONFIG_I2S_WM8750)
++ audiohw_postinit(!(ptri2s_config->slave_en), 0, 1);
++#elif defined(CONFIG_I2S_WM8960)
++ audiohw_postinit(!(ptri2s_config->slave_en), 1, 1, ptri2s_config->codec_pll_en);
++#elif defined(CONFIG_I2S_WM8751)
++ if(ptri2s_config->slave_en==0)
++ audiohw_postinit(1,1);
++ else
++ audiohw_postinit(0,1);
++#endif
++#endif
++ return 0;
++}
++
++int i2s_codec_disable(i2s_config_type* ptri2s_config)
++{
++#if defined(CONFIG_I2S_WM8960) || defined(CONFIG_I2S_WM8750) || defined(CONFIG_I2S_WM8751)
++ audiohw_close();
++#endif
++ return 0;
++}
++
++int i2s_reset_config(i2s_config_type* ptri2s_config)
++{
++ unsigned long data;
++
++ /* RESET bit: write 1 clear */
++#if defined(CONFIG_RALINK_RT6855A)
++ data = i2s_inw(RALINK_SYSCTL_BASE+0x834);
++ data |= (1<<17);
++ i2s_outw(RALINK_SYSCTL_BASE+0x834, data);
++
++ data = i2s_inw(RALINK_SYSCTL_BASE+0x834);
++ data &= ~(1<<17);
++ i2s_outw(RALINK_SYSCTL_BASE+0x834, data);
++#elif defined(CONFIG_ARCH_MT7623)
++ data = i2s_inw(0xFB000000+0x34);
++ data |= (1<<17);
++ i2s_outw(0xFB000000+0x34, data);
++
++ data = i2s_inw(0xFB000000+0x34);
++ data &= ~(1<<17);
++ i2s_outw(0xFB000000+0x34, data);
++#else
++ data = i2s_inw(RALINK_SYSCTL_BASE+0x34);
++ data |= (1<<17);
++ i2s_outw(RALINK_SYSCTL_BASE+0x34, data);
++
++ data = i2s_inw(RALINK_SYSCTL_BASE+0x34);
++ data &= ~(1<<17);
++ i2s_outw(RALINK_SYSCTL_BASE+0x34, data);
++
++#if 0 /* Reset GDMA */
++ data = i2s_inw(RALINK_SYSCTL_BASE+0x34);
++ data |= (1<<14);
++ i2s_outw(RALINK_SYSCTL_BASE+0x34, data);
++
++ data = i2s_inw(RALINK_SYSCTL_BASE+0x34);
++ data &= ~(1<<14);
++ i2s_outw(RALINK_SYSCTL_BASE+0x34, data);
++#endif
++#endif
++ _printk("I2S reset complete!!\n");
++ return 0;
++}
++
++int i2s_tx_config(i2s_config_type* ptri2s_config)
++{
++ unsigned long data;
++ /* set I2S_I2SCFG */
++ data = i2s_inw(I2S_I2SCFG);
++ data &= 0xFFFFFF81;
++ data |= REGBIT(ptri2s_config->tx_ff_thres, I2S_TX_FF_THRES);
++ data |= REGBIT(ptri2s_config->tx_ch_swap, I2S_TX_CH_SWAP);
++#if defined(CONFIG_RALINK_RT6855A)
++ data |= REGBIT(1, I2S_BYTE_SWAP);
++#endif
++#if defined(CONFIG_RALINK_MT7628) || defined(CONFIG_ARCH_MT7623)
++ MSG("TX:wordLen=%d, sysEndian=%d\n", ptri2s_config->wordlen_24b, ptri2s_config->sys_endian);
++ data |= REGBIT(ptri2s_config->wordlen_24b, I2S_DATA_24BIT);
++ data |= REGBIT(ptri2s_config->sys_endian, I2S_SYS_ENDIAN);
++ data |= REGBIT(ptri2s_config->little_edn, I2S_LITTLE_ENDIAN);
++#endif
++ data &= ~REGBIT(1, I2S_TX_CH0_OFF);
++ data &= ~REGBIT(1, I2S_TX_CH1_OFF);
++ i2s_outw(I2S_I2SCFG, data);
++
++ /* set I2S_I2SCFG1 */
++ MSG("internal loopback: %d\n", ptri2s_config->lbk);
++ data = i2s_inw(I2S_I2SCFG1);
++ data |= REGBIT(ptri2s_config->lbk, I2S_LBK_EN);
++ data |= REGBIT(ptri2s_config->extlbk, I2S_EXT_LBK_EN);
++ data &= 0xFFFFFFFC;
++#if defined(CONFIG_RALINK_MT7628) || defined(CONFIG_ARCH_MT7623)
++ data |= REGBIT(ptri2s_config->fmt, I2S_DATA_FMT);
++#endif
++ i2s_outw(I2S_I2SCFG1, data);
++
++ return 0;
++}
++
++int i2s_rx_config(i2s_config_type* ptri2s_config)
++{
++ unsigned long data;
++ /* set I2S_I2SCFG */
++ data = i2s_inw(I2S_I2SCFG);
++ data &= 0xFFFF81FF;
++ data |= REGBIT(ptri2s_config->rx_ff_thres, I2S_RX_FF_THRES);
++ data |= REGBIT(ptri2s_config->rx_ch_swap, I2S_RX_CH_SWAP);
++ data &= ~REGBIT(1, I2S_RX_CH0_OFF);
++ data &= ~REGBIT(1, I2S_RX_CH1_OFF);
++#if defined(CONFIG_RALINK_MT7628) || defined(CONFIG_ARCH_MT7623)
++ MSG("RX:wordLen=%d, sysEndian=%d\n", ptri2s_config->wordlen_24b, ptri2s_config->sys_endian);
++ data |= REGBIT(ptri2s_config->wordlen_24b, I2S_DATA_24BIT);
++ data |= REGBIT(ptri2s_config->sys_endian, I2S_SYS_ENDIAN);
++ data |= REGBIT(ptri2s_config->little_edn, I2S_LITTLE_ENDIAN);
++#endif
++ i2s_outw(I2S_I2SCFG, data);
++
++ /* set I2S_I2SCFG1 */
++ data = i2s_inw(I2S_I2SCFG1);
++ data |= REGBIT(ptri2s_config->lbk, I2S_LBK_EN);
++ data |= REGBIT(ptri2s_config->extlbk, I2S_EXT_LBK_EN);
++#if defined(CONFIG_RALINK_MT7628) || defined(CONFIG_ARCH_MT7623)
++ data &= 0xFFFFFFFC;
++ data |= REGBIT(ptri2s_config->fmt, I2S_DATA_FMT);
++#endif
++ i2s_outw(I2S_I2SCFG1, data);
++
++ return 0;
++}
++
++/* Turn On Tx DMA and INT */
++int i2s_tx_enable(i2s_config_type* ptri2s_config)
++{
++ unsigned long data;
++
++#if defined(I2S_HW_INTERRUPT_EN)
++ data = i2s_inw(I2S_INT_EN);
++ data |= REGBIT(0x1, I2S_TX_INT3_EN); /* FIFO DMA fault */
++ data |= REGBIT(0x1, I2S_TX_INT2_EN); /* FIFO overrun */
++ data |= REGBIT(0x1, I2S_TX_INT1_EN); /* FIFO underrun */
++ data |= REGBIT(0x1, I2S_TX_INT0_EN); /* FIFO below threshold */
++ i2s_outw(I2S_INT_EN, data);
++#endif
++
++ data = i2s_inw(I2S_I2SCFG);
++#if defined(CONFIG_I2S_TXRX)
++ data |= REGBIT(0x1, I2S_TX_EN);
++#endif
++ data |= REGBIT(0x1, I2S_DMA_EN);
++ i2s_outw(I2S_I2SCFG, data);
++
++ data = i2s_inw(I2S_I2SCFG);
++ data |= REGBIT(0x1, I2S_EN);
++ i2s_outw(I2S_I2SCFG, data);
++
++ MSG("i2s_tx_enable done\n");
++ return I2S_OK;
++}
++
++/* Turn On Rx DMA and INT */
++int i2s_rx_enable(i2s_config_type* ptri2s_config)
++{
++ unsigned long data;
++
++#if defined(I2S_HW_INTERRUPT_EN)
++ data = i2s_inw(I2S_INT_EN);
++ data |= REGBIT(0x1, I2S_RX_INT3_EN); /* FIFO DMA fault */
++ data |= REGBIT(0x1, I2S_RX_INT2_EN); /* FIFO overrun */
++ data |= REGBIT(0x1, I2S_RX_INT1_EN); /* FIFO underrun */
++ data |= REGBIT(0x1, I2S_RX_INT0_EN); /* FIFO below threshold */
++ i2s_outw(I2S_INT_EN, data);
++#endif
++
++ data = i2s_inw(I2S_I2SCFG);
++#if defined(CONFIG_I2S_TXRX)
++ data |= REGBIT(0x1, I2S_RX_EN);
++#endif
++ data |= REGBIT(0x1, I2S_DMA_EN);
++ i2s_outw(I2S_I2SCFG, data);
++
++ data = i2s_inw(I2S_I2SCFG);
++ data |= REGBIT(0x1, I2S_EN);
++ i2s_outw(I2S_I2SCFG, data);
++
++ MSG("i2s_rx_enable done\n");
++ return I2S_OK;
++}
++/* Turn Off Tx DMA and INT */
++int i2s_tx_disable(i2s_config_type* ptri2s_config)
++{
++ unsigned long data;
++
++#if defined(I2S_HW_INTERRUPT_EN)
++ data = i2s_inw(I2S_INT_EN);
++ data &= ~REGBIT(0x1, I2S_TX_INT3_EN);
++ data &= ~REGBIT(0x1, I2S_TX_INT2_EN);
++ data &= ~REGBIT(0x1, I2S_TX_INT1_EN);
++ data &= ~REGBIT(0x1, I2S_TX_INT0_EN);
++ i2s_outw(I2S_INT_EN, data);
++#endif
++
++ data = i2s_inw(I2S_I2SCFG);
++#if defined(CONFIG_I2S_TXRX)
++ data &= ~REGBIT(0x1, I2S_TX_EN);
++#endif
++ if(ptri2s_config->bRxDMAEnable==0)
++ {
++ ptri2s_config->bTxDMAEnable = 0;
++ data &= ~REGBIT(0x1, I2S_DMA_EN);
++ data &= ~REGBIT(0x1, I2S_EN);
++ }
++ i2s_outw(I2S_I2SCFG, data);
++ return I2S_OK;
++}
++/* Turn Off Rx DMA and INT */
++int i2s_rx_disable(i2s_config_type* ptri2s_config)
++{
++ unsigned long data;
++
++#if defined(I2S_HW_INTERRUPT_EN)
++ data = i2s_inw(I2S_INT_EN);
++ data &= ~REGBIT(0x1, I2S_RX_INT3_EN);
++ data &= ~REGBIT(0x1, I2S_RX_INT2_EN);
++ data &= ~REGBIT(0x1, I2S_RX_INT1_EN);
++ data &= ~REGBIT(0x1, I2S_RX_INT0_EN);
++ i2s_outw(I2S_INT_EN, data);
++#endif
++
++ data = i2s_inw(I2S_I2SCFG);
++#if defined(CONFIG_I2S_TXRX)
++ data &= ~REGBIT(0x1, I2S_RX_EN);
++#endif
++ if(ptri2s_config->bTxDMAEnable==0)
++ {
++ ptri2s_config->bRxDMAEnable = 0;
++ data &= ~REGBIT(0x1, I2S_DMA_EN);
++ data &= ~REGBIT(0x1, I2S_EN);
++ }
++ i2s_outw(I2S_I2SCFG, data);
++ return I2S_OK;
++}
++
++int i2s_dma_tx_transf_data(i2s_config_type* ptri2s_config, u32 dma_ch)
++{
++ int tx_r_idx;
++
++ if ((pi2s_config->bALSAEnable==1) && (pi2s_config->bALSAMMAPEnable==1))
++ tx_r_idx = (pi2s_config->tx_r_idx + ALSA_MMAP_IDX_SHIFT)%MAX_I2S_PAGE;
++ else
++ tx_r_idx = pi2s_config->tx_r_idx;
++
++ if(dma_ch==GDMA_I2S_TX0)
++ {
++#if defined(CONFIG_I2S_MMAP)
++ dma_sync_single_for_device(NULL, i2s_mmap_addr[tx_r_idx], I2S_PAGE_SIZE, DMA_TO_DEVICE);
++#if defined(ARM_ARCH)
++ GdmaI2sTx(i2s_mmap_addr[tx_r_idx], I2S_TX_FIFO_WREG_PHY, 0, I2S_PAGE_SIZE, i2s_dma_tx_handler, i2s_dma_tx_unmask_handler);
++#else
++ GdmaI2sTx((u32)(pi2s_config->pMMAPTxBufPtr[tx_r_idx]), I2S_TX_FIFO_WREG, 0, I2S_PAGE_SIZE, i2s_dma_tx_handler, i2s_dma_tx_unmask_handler);
++#endif
++#else
++ memcpy(pi2s_config->pPage0TxBuf8ptr, pi2s_config->pMMAPTxBufPtr[tx_r_idx], I2S_PAGE_SIZE);
++#if defined(ARM_ARCH)
++ GdmaI2sTx(i2s_txdma_addr0, I2S_TX_FIFO_WREG_PHY, 0, I2S_PAGE_SIZE, i2s_dma_tx_handler, i2s_dma_tx_unmask_handler);
++#else
++ GdmaI2sTx((u32)(pi2s_config->pPage0TxBuf8ptr), I2S_TX_FIFO_WREG, 0, I2S_PAGE_SIZE, i2s_dma_tx_handler, i2s_dma_tx_unmask_handler);
++#endif
++#endif
++ pi2s_config->dmach = GDMA_I2S_TX0;
++ pi2s_config->tx_r_idx = (pi2s_config->tx_r_idx+1)%MAX_I2S_PAGE;
++ }
++ else
++ {
++#if defined(CONFIG_I2S_MMAP)
++ dma_sync_single_for_device(NULL, i2s_mmap_addr[tx_r_idx], I2S_PAGE_SIZE, DMA_TO_DEVICE);
++#if defined(ARM_ARCH)
++ GdmaI2sTx(i2s_mmap_addr[tx_r_idx], I2S_TX_FIFO_WREG_PHY, 1, I2S_PAGE_SIZE, i2s_dma_tx_handler, i2s_dma_tx_unmask_handler);
++#else
++ GdmaI2sTx((u32)(pi2s_config->pMMAPTxBufPtr[tx_r_idx]), I2S_TX_FIFO_WREG, 1, I2S_PAGE_SIZE, i2s_dma_tx_handler, i2s_dma_tx_unmask_handler);
++#endif
++#else
++ memcpy(pi2s_config->pPage1TxBuf8ptr, pi2s_config->pMMAPTxBufPtr[tx_r_idx], I2S_PAGE_SIZE);
++#if defined(ARM_ARCH)
++ GdmaI2sTx(i2s_txdma_addr1, I2S_TX_FIFO_WREG_PHY, 1, I2S_PAGE_SIZE, i2s_dma_tx_handler, i2s_dma_tx_unmask_handler);
++#else
++ GdmaI2sTx((u32)(pi2s_config->pPage1TxBuf8ptr), I2S_TX_FIFO_WREG, 1, I2S_PAGE_SIZE, i2s_dma_tx_handler, i2s_dma_tx_unmask_handler);
++#endif
++#endif
++ pi2s_config->dmach = GDMA_I2S_TX1;
++ pi2s_config->tx_r_idx = (pi2s_config->tx_r_idx+1)%MAX_I2S_PAGE;
++ }
++#if defined(CONFIG_I2S_WITH_AEC)
++ if(aecFuncP->AECFeEnq){
++ aecFuncP->AECFeEnq(0,pi2s_config->pMMAPTxBufPtr[pi2s_config->tx_r_idx],I2S_PAGE_SIZE);
++ }
++#endif
++ return 0;
++}
++
++int i2s_dma_tx_transf_zero(i2s_config_type* ptri2s_config, u32 dma_ch)
++{
++ if(dma_ch==GDMA_I2S_TX0)
++ {
++ memset(pi2s_config->pPage0TxBuf8ptr, 0, I2S_PAGE_SIZE);
++#if defined(ARM_ARCH)
++ GdmaI2sTx(i2s_txdma_addr0, I2S_TX_FIFO_WREG_PHY, 0, I2S_PAGE_SIZE, i2s_dma_tx_handler, i2s_dma_tx_unmask_handler);
++#else
++ GdmaI2sTx((u32)pi2s_config->pPage0TxBuf8ptr, I2S_TX_FIFO_WREG, 0, I2S_PAGE_SIZE, i2s_dma_tx_handler, i2s_dma_tx_unmask_handler);
++#endif
++ }
++ else
++ {
++ memset(pi2s_config->pPage1TxBuf8ptr, 0, I2S_PAGE_SIZE);
++#if defined(ARM_ARCH)
++ GdmaI2sTx(i2s_txdma_addr1, I2S_TX_FIFO_WREG_PHY, 1, I2S_PAGE_SIZE, i2s_dma_tx_handler, i2s_dma_tx_unmask_handler);
++#else
++ GdmaI2sTx((u32)pi2s_config->pPage1TxBuf8ptr, I2S_TX_FIFO_WREG, 1, I2S_PAGE_SIZE, i2s_dma_tx_handler, i2s_dma_tx_unmask_handler);
++#endif
++ }
++ return 0;
++}
++
++int i2s_dma_rx_transf_data(i2s_config_type* ptri2s_config, u32 dma_ch)
++{
++ int rx_w_idx;
++
++ pi2s_config->rx_w_idx = (pi2s_config->rx_w_idx+1)%MAX_I2S_PAGE;
++
++ if ((pi2s_config->bALSAEnable==1) && (pi2s_config->bALSAMMAPEnable==1))
++ rx_w_idx = (pi2s_config->rx_w_idx+ALSA_MMAP_IDX_SHIFT)%MAX_I2S_PAGE;
++ else
++ rx_w_idx = (pi2s_config->rx_w_idx)%MAX_I2S_PAGE;
++
++ if(dma_ch==GDMA_I2S_RX0)
++ {
++
++#ifdef CONFIG_I2S_MMAP
++ dma_sync_single_for_device(NULL, i2s_mmap_addr[rx_w_idx+(pi2s_config->mmap_index-MAX_I2S_PAGE)], I2S_PAGE_SIZE, DMA_FROM_DEVICE);
++#if defined(ARM_ARCH)
++ GdmaI2sRx(I2S_RX_FIFO_RREG_PHY, (u32)i2s_mmap_addr[rx_w_idx+(pi2s_config->mmap_index-MAX_I2S_PAGE)], 0, I2S_PAGE_SIZE, i2s_dma_rx_handler, i2s_dma_rx_unmask_handler);
++#else
++ GdmaI2sRx(I2S_RX_FIFO_RREG, (u32)(pi2s_config->pMMAPRxBufPtr[rx_w_idx]), 0, I2S_PAGE_SIZE, i2s_dma_rx_handler, i2s_dma_rx_unmask_handler);
++#endif
++#else
++ memcpy(pi2s_config->pMMAPRxBufPtr[rx_w_idx], pi2s_config->pPage0RxBuf8ptr, I2S_PAGE_SIZE);
++#if defined(ARM_ARCH)
++ GdmaI2sRx(I2S_RX_FIFO_RREG_PHY, i2s_rxdma_addr0, 0, I2S_PAGE_SIZE, i2s_dma_rx_handler, i2s_dma_rx_unmask_handler);
++#else
++ GdmaI2sRx(I2S_RX_FIFO_RREG, (u32)(pi2s_config->pPage0RxBuf8ptr), 0, I2S_PAGE_SIZE, i2s_dma_rx_handler, i2s_dma_rx_unmask_handler);
++#endif
++#endif
++ pi2s_config->dmach = GDMA_I2S_RX0;
++ }
++ else
++ {
++
++#ifdef CONFIG_I2S_MMAP
++ dma_sync_single_for_device(NULL, i2s_mmap_addr[rx_w_idx+(pi2s_config->mmap_index-MAX_I2S_PAGE)], I2S_PAGE_SIZE, DMA_FROM_DEVICE);
++#if defined(ARM_ARCH)
++ GdmaI2sRx(I2S_RX_FIFO_RREG_PHY, (u32)i2s_mmap_addr[rx_w_idx+(pi2s_config->mmap_index-MAX_I2S_PAGE)], 1, I2S_PAGE_SIZE, i2s_dma_rx_handler, i2s_dma_rx_unmask_handler);
++#else
++ GdmaI2sRx(I2S_RX_FIFO_RREG, (u32)(pi2s_config->pMMAPRxBufPtr[rx_w_idx]), 1, I2S_PAGE_SIZE, i2s_dma_rx_handler, i2s_dma_rx_unmask_handler);
++#endif
++#else
++ memcpy(pi2s_config->pMMAPRxBufPtr[rx_w_idx], pi2s_config->pPage1RxBuf8ptr, I2S_PAGE_SIZE);
++#if defined(ARM_ARCH)
++ GdmaI2sRx(I2S_RX_FIFO_RREG_PHY, i2s_rxdma_addr1, 1, I2S_PAGE_SIZE, i2s_dma_rx_handler, i2s_dma_rx_unmask_handler);
++#else
++ GdmaI2sRx(I2S_RX_FIFO_RREG, (u32)(pi2s_config->pPage1RxBuf8ptr), 1, I2S_PAGE_SIZE, i2s_dma_rx_handler, i2s_dma_rx_unmask_handler);
++#endif
++#endif
++ pi2s_config->dmach = GDMA_I2S_RX1;
++
++ }
++#if defined(CONFIG_I2S_WITH_AEC)
++ if(aecFuncP->AECNeEnq){
++ aecFuncP->AECNeEnq(0,pi2s_config->pMMAPRxBufPtr[rx_w_idx],I2S_PAGE_SIZE);
++ }
++#endif
++ return 0;
++}
++
++int i2s_dma_rx_transf_zero(i2s_config_type* ptri2s_config, u32 dma_ch)
++{
++ if(dma_ch==GDMA_I2S_RX0)
++ {
++ memset(pi2s_config->pPage0RxBuf8ptr, 0, I2S_PAGE_SIZE);
++#if defined(ARM_ARCH)
++ GdmaI2sRx(I2S_RX_FIFO_RREG_PHY, i2s_rxdma_addr0, 0, I2S_PAGE_SIZE, i2s_dma_rx_handler, i2s_dma_rx_unmask_handler);
++#else
++ GdmaI2sRx(I2S_RX_FIFO_RREG, (u32)pi2s_config->pPage0RxBuf8ptr, 0, I2S_PAGE_SIZE, i2s_dma_rx_handler, i2s_dma_rx_unmask_handler);
++#endif
++ }
++ else
++ {
++ memset(pi2s_config->pPage1RxBuf8ptr, 0, I2S_PAGE_SIZE);
++#if defined(ARM_ARCH)
++ GdmaI2sRx(I2S_RX_FIFO_RREG_PHY, i2s_rxdma_addr1, 1, I2S_PAGE_SIZE, i2s_dma_rx_handler, i2s_dma_rx_unmask_handler);
++#else
++ GdmaI2sRx(I2S_RX_FIFO_RREG, (u32)pi2s_config->pPage1RxBuf8ptr, 1, I2S_PAGE_SIZE, i2s_dma_rx_handler, i2s_dma_rx_unmask_handler);
++#endif
++ }
++ return 0;
++}
++
++void i2s_dma_tx_handler(u32 dma_ch)
++{
++ pi2s_config->enLable = 1; /* TX:enLabel=1; RX:enLabel=2 */
++
++ if(pi2s_config->bTxDMAEnable==0)
++ {
++ if(pi2s_config->end_cnt != 0)
++ {
++ i2s_dma_tx_transf_data(pi2s_config, dma_ch);
++ pi2s_config->end_cnt --;
++ MSG("end_cnt = %d, r_idx = %d\n", pi2s_config->end_cnt, pi2s_config->tx_r_idx);
++ }
++ else
++ {
++ pi2s_config->tx_stop_cnt++;
++ i2s_dma_tx_soft_stop(pi2s_config, dma_ch);
++ MSG("tx_stop=%d, ch=%d\n", pi2s_config->tx_stop_cnt, dma_ch);
++ if (pi2s_config->tx_stop_cnt == 3)
++ {
++ wake_up_interruptible(&(pi2s_config->i2s_tx_qh));
++ _printk("T:wake up!!\n");
++ }
++ }
++ return;
++ }
++
++ pi2s_config->tx_isr_cnt++;
++
++#ifdef I2S_STATISTIC
++ i2s_int_status(dma_ch);
++#endif
++ /* FIXME */
++ if(pi2s_config->bALSAEnable)
++ {
++ if(pi2s_config->dmaStat[STREAM_PLAYBACK])
++ {
++ if(!pi2s_config->bTrigger[STREAM_PLAYBACK]){
++ //_printk("trigger stop: rIdx:%d widx:%d\n", pi2s_config->tx_r_idx,pi2s_config->tx_w_idx);
++ i2s_dma_tx_transf_zero(pi2s_config, dma_ch);
++ if(pi2s_config->bPreTrigger[STREAM_PLAYBACK]){
++ /* mtk04880 commented:
++ * for corner case, there are cases which ALSA Trigger stop before disabling DMA.
++ * For which case, it needs to keep call snd_pcm_elapased to keep ALSA hw ptr updating.
++ * It is so called post stop handlment.
++ */
++ //_printk("post-stop\n");
++ goto EXIT;
++ }
++ else{
++ //_printk("pre-stop\n");
++ wake_up_interruptible(&(pi2s_config->i2s_tx_qh));
++ return;
++ }
++ }
++ else{
++ if(!pi2s_config->bPreTrigger[STREAM_PLAYBACK])
++ pi2s_config->bPreTrigger[STREAM_PLAYBACK] = 1;
++
++ }
++ }
++ }
++ else
++ {
++ if(pi2s_config->tx_r_idx==pi2s_config->tx_w_idx)
++ {
++ /* Buffer Empty */
++ MSG("TXBE r=%d w=%d[i=%u,c=%u]\n",pi2s_config->tx_r_idx,pi2s_config->tx_w_idx,pi2s_config->tx_isr_cnt,dma_ch);
++#ifdef I2S_STATISTIC
++ pi2s_status->txbuffer_unrun++;
++#endif
++ i2s_dma_tx_transf_zero(pi2s_config, dma_ch);
++ goto EXIT;
++ }
++ }
++
++ if(pi2s_config->pMMAPTxBufPtr[pi2s_config->tx_r_idx]==NULL)
++ {
++ MSG("mmap buf NULL [%d]\n",pi2s_config->tx_r_idx);
++ i2s_dma_tx_transf_zero(pi2s_config, dma_ch);
++
++ goto EXIT;
++ }
++
++ if(pi2s_config->tx_pause_en == 1)
++ {
++ /* Enable PAUSE */
++ MSG("TX pause now\n");
++ i2s_dma_tx_transf_zero(pi2s_config, dma_ch);
++
++ goto EXIT;
++ }
++
++#ifdef I2S_STATISTIC
++ pi2s_status->txbuffer_len--;
++#endif
++ i2s_dma_tx_transf_data(pi2s_config, dma_ch);
++
++EXIT:
++#if defined(CONFIG_SND_MT76XX_SOC)
++ if(pi2s_config->bALSAEnable == 1){
++ if(pi2s_config->pss[STREAM_PLAYBACK])
++ snd_pcm_period_elapsed(pi2s_config->pss[STREAM_PLAYBACK]);
++ }
++#endif
++ wake_up_interruptible(&(pi2s_config->i2s_tx_qh));
++ return;
++}
++
++void i2s_dma_rx_handler(u32 dma_ch)
++{
++ pi2s_config->enLable = 2; /* TX:enLabel=1; RX:enLabel=2 */
++#if defined(CONFIG_I2S_TXRX)
++ if(pi2s_config->rx_isr_cnt==0)
++ {
++ pi2s_config->next_p0_idx = 0;
++ pi2s_config->next_p1_idx = 1;
++ }
++ pi2s_config->rx_isr_cnt++;
++
++#ifdef I2S_STATISTIC
++ i2s_int_status(dma_ch);
++#endif
++
++ if (pi2s_config->bRxDMAEnable==0)
++ {
++ pi2s_config->rx_stop_cnt++;
++ i2s_dma_rx_soft_stop(pi2s_config, dma_ch);
++ MSG("rx_stop=%d\n", pi2s_config->rx_stop_cnt);
++
++ if(pi2s_config->rx_stop_cnt == 2)
++ {
++ wake_up_interruptible(&(pi2s_config->i2s_rx_qh));
++ _printk("R:wake up!!\n");
++ }
++ return;
++ }
++
++ if(pi2s_config->bALSAEnable)
++ {
++ if(pi2s_config->dmaStat[STREAM_CAPTURE]){
++ if(!pi2s_config->bTrigger[STREAM_CAPTURE]){
++ MSG("trigger stop: rIdx:%d widx:%d\n", pi2s_config->rx_r_idx,pi2s_config->rx_w_idx);
++ i2s_dma_rx_transf_zero(pi2s_config, dma_ch);
++ wake_up_interruptible(&(pi2s_config->i2s_rx_qh));
++ return;
++ }
++ }
++ }
++ else
++ {
++ if(((pi2s_config->rx_w_idx+1)%MAX_I2S_PAGE)==pi2s_config->rx_r_idx){
++ /* Buffer Full */
++ MSG("RXBF r=%d w=%d[i=%u,c=%u]\n",pi2s_config->rx_r_idx,pi2s_config->rx_w_idx,pi2s_config->rx_isr_cnt,dma_ch);
++#ifdef I2S_STATISTIC
++ pi2s_status->rxbuffer_unrun++;
++#endif
++ i2s_dma_rx_transf_zero(pi2s_config, dma_ch);
++ goto EXIT;
++ }
++ }
++
++ if(pi2s_config->rx_pause_en == 1)
++ {
++ /* Enable PAUSE */
++ i2s_dma_rx_transf_zero(pi2s_config, dma_ch);
++
++ goto EXIT;
++ }
++
++#ifdef I2S_STATISTIC
++ pi2s_status->rxbuffer_len++;
++#endif
++ i2s_dma_rx_transf_data(pi2s_config, dma_ch);
++
++EXIT:
++#if defined(CONFIG_SND_MT76XX_SOC)
++ if(pi2s_config->bALSAEnable == 1){
++ if(pi2s_config->pss[STREAM_CAPTURE])
++ snd_pcm_period_elapsed(pi2s_config->pss[STREAM_CAPTURE]);
++ }
++#endif
++ wake_up_interruptible(&(pi2s_config->i2s_rx_qh));
++#endif
++ return;
++}
++
++#ifdef I2S_STATISTIC
++void i2s_int_status(u32 dma_ch)
++{
++ u32 i2s_status;
++
++ if((pi2s_config->tx_isr_cnt>0)||(pi2s_config->rx_isr_cnt>0))
++ {
++ i2s_status = i2s_inw(I2S_INT_STATUS);
++
++ if(i2s_status&REGBIT(1, I2S_TX_DMA_FAULT))
++ {
++ pi2s_status->txdmafault++;
++ }
++ if(i2s_status&REGBIT(1, I2S_TX_OVRUN))
++ {
++ pi2s_status->txovrun++;
++ }
++ if(i2s_status&REGBIT(1, I2S_TX_UNRUN))
++ {
++ pi2s_status->txunrun++;
++ }
++ if(i2s_status&REGBIT(1, I2S_TX_THRES))
++ {
++ pi2s_status->txthres++;
++ }
++ if(i2s_status&REGBIT(1, I2S_RX_DMA_FAULT))
++ {
++ pi2s_status->rxdmafault++;
++ }
++ if(i2s_status&REGBIT(1, I2S_RX_OVRUN))
++ {
++ pi2s_status->rxovrun++;
++ }
++ if(i2s_status&REGBIT(1, I2S_RX_UNRUN))
++ {
++ pi2s_status->rxunrun++;
++ }
++ if(i2s_status&REGBIT(1, I2S_RX_THRES))
++ {
++ pi2s_status->rxthres++;
++ }
++ }
++#if 0
++ if(pi2s_config->enLable == 1)
++ {
++ if((pi2s_config->tx_isr_cnt>0) && (pi2s_config->tx_isr_cnt%40==0))
++ {
++ MSG("tisr i=%u,ch=%u,o=%u,u=%d,s=%X [r=%d,w=%d]\n",\
++ pi2s_config->tx_isr_cnt,dma_ch,pi2s_status->txovrun,pi2s_status->txunrun,\
++ i2s_inw(I2S_INT_STATUS),pi2s_config->tx_r_idx,pi2s_config->tx_w_idx);
++ }
++ }
++
++ if(pi2s_config->enLable == 2)
++ {
++ if((pi2s_config->rx_isr_cnt>0) && (pi2s_config->rx_isr_cnt%40==0))
++ {
++ MSG("risr i=%u,ch=%u,o=%u,u=%d,s=%X [r=%d,w=%d]\n",\
++ pi2s_config->rx_isr_cnt,dma_ch,pi2s_status->rxovrun,pi2s_status->rxunrun,\
++ i2s_inw(I2S_INT_STATUS),pi2s_config->rx_r_idx,pi2s_config->rx_w_idx);
++ }
++ }
++#endif
++
++ *(unsigned long*)(I2S_INT_STATUS) = 0xFFFFFFFF;
++}
++#endif
++
++#if defined(I2S_HW_INTERRUPT_EN)&&(I2S_SW_IRQ_EN)
++irqreturn_t i2s_irq_isr(int irq, void *irqaction)
++{
++ u32 i2s_status;
++
++ //MSG("i2s_irq_isr [0x%08X]\n",i2s_inw(I2S_INT_STATUS));
++ if((pi2s_config->tx_isr_cnt>0)||(pi2s_config->rx_isr_cnt>0))
++ {
++ i2s_status = i2s_inw(I2S_INT_STATUS);
++ MSG("i2s_irq_isr [0x%08X]\n",i2s_status);
++ }
++ else
++ return IRQ_HANDLED;
++
++ if(i2s_status&REGBIT(1, I2S_TX_DMA_FAULT))
++ {
++#ifdef I2S_STATISTIC
++ pi2s_status->txdmafault++;
++#endif
++ }
++ if(i2s_status&REGBIT(1, I2S_TX_OVRUN))
++ {
++#ifdef I2S_STATISTIC
++ pi2s_status->txovrun++;
++#endif
++ }
++ if(i2s_status&REGBIT(1, I2S_TX_UNRUN))
++ {
++#ifdef I2S_STATISTIC
++ pi2s_status->txunrun++;
++#endif
++ }
++ if(i2s_status&REGBIT(1, I2S_TX_THRES))
++ {
++#ifdef I2S_STATISTIC
++ pi2s_status->txthres++;
++#endif
++ }
++ if(i2s_status&REGBIT(1, I2S_RX_DMA_FAULT))
++ {
++#ifdef I2S_STATISTIC
++ pi2s_status->rxdmafault++;
++#endif
++ }
++ if(i2s_status&REGBIT(1, I2S_RX_OVRUN))
++ {
++#ifdef I2S_STATISTIC
++ pi2s_status->rxovrun++;
++#endif
++ }
++ if(i2s_status&REGBIT(1, I2S_RX_UNRUN))
++ {
++#ifdef I2S_STATISTIC
++ pi2s_status->rxunrun++;
++#endif
++ }
++ if(i2s_status&REGBIT(1, I2S_RX_THRES))
++ {
++#ifdef I2S_STATISTIC
++ pi2s_status->rxthres++;
++#endif
++ }
++ i2s_outw(I2S_INT_STATUS, 0xFFFFFFFF);
++ return IRQ_HANDLED;
++}
++#endif
++
++void i2s_tx_task(unsigned long pData)
++{
++ unsigned long flags;
++ spin_lock_irqsave(&pi2s_config->lock, flags);
++ //if (pi2s_config->bTxDMAEnable!=0)
++ {
++ if (pi2s_config->tx_unmask_ch!=0)
++ {
++ u32 dmach = pi2s_config->tx_unmask_ch;
++ u32 ch;
++ for (ch = 0; ch < 16; ch++)
++ {
++ if (dmach& (1<<ch))
++ {
++ MSG("do unmask ch%d tisr=%d in tx_isr\n",ch,pi2s_config->tx_isr_cnt);
++ GdmaUnMaskChannel(ch);
++ }
++ }
++ pi2s_config->tx_unmask_ch = 0;
++ }
++ }
++ spin_unlock_irqrestore(&pi2s_config->lock, flags);
++}
++
++void i2s_rx_task(unsigned long pData)
++{
++ unsigned long flags;
++ spin_lock_irqsave(&pi2s_config->lock, flags);
++ //if (pi2s_config->bRxDMAEnable!=0)
++ {
++ if (pi2s_config->rx_unmask_ch!=0)
++ {
++ u32 dmach = pi2s_config->rx_unmask_ch;
++ u32 ch;
++ for (ch = 0; ch < 16; ch++)
++ {
++ if (dmach& (1<<ch))
++ {
++ MSG("do unmask ch%d risr=%d in rx_isr\n",ch,pi2s_config->rx_isr_cnt);
++ GdmaUnMaskChannel(ch);
++ }
++ }
++ pi2s_config->rx_unmask_ch = 0;
++
++ }
++ }
++ spin_unlock_irqrestore(&pi2s_config->lock, flags);
++}
++
++
++void i2s_dma_unmask_handler(u32 dma_ch)
++{
++ MSG("i2s_dma_unmask_handler ch=%d\n",dma_ch);
++
++ GdmaUnMaskChannel(dma_ch);
++
++ return;
++}
++
++void i2s_dma_tx_unmask_handler(u32 dma_ch)
++{
++ MSG("i2s_dma_tx_unmask_handler ch=%d\n",dma_ch);
++ pi2s_config->tx_unmask_ch |= (1<<dma_ch);
++ tasklet_hi_schedule(&i2s_tx_tasklet);
++ return;
++}
++
++void i2s_dma_rx_unmask_handler(u32 dma_ch)
++{
++ MSG("i2s_dma_rx_unmask_handler ch=%d\n",dma_ch);
++ pi2s_config->rx_unmask_ch |= (1<<dma_ch);
++ tasklet_hi_schedule(&i2s_rx_tasklet);
++ return;
++}
++
++void i2s_dma_mask_handler(u32 dma_ch)
++{
++ MSG("i2s_dma_mask_handler ch=%d\n", dma_ch);
++ GdmaMaskChannel(dma_ch);
++ return;
++}
++
++void i2s_dma_tx_init(i2s_config_type* ptri2s_config)
++{
++ memset(pi2s_config->pPage0TxBuf8ptr, 0, I2S_PAGE_SIZE);
++ memset(pi2s_config->pPage1TxBuf8ptr, 0, I2S_PAGE_SIZE);
++#if defined(ARM_ARCH)
++ GdmaI2sTx(i2s_txdma_addr0, I2S_TX_FIFO_WREG_PHY, 0, I2S_PAGE_SIZE, i2s_dma_tx_handler, i2s_dma_tx_unmask_handler);
++ GdmaI2sTx(i2s_txdma_addr1, I2S_TX_FIFO_WREG_PHY, 1, I2S_PAGE_SIZE, i2s_dma_tx_handler, i2s_dma_tx_unmask_handler);
++#else
++ GdmaI2sTx((u32)ptri2s_config->pPage0TxBuf8ptr, I2S_FIFO_WREG, 0, I2S_PAGE_SIZE, i2s_dma_tx_handler, i2s_dma_tx_unmask_handler);
++ GdmaI2sTx((u32)ptri2s_config->pPage1TxBuf8ptr, I2S_FIFO_WREG, 1, I2S_PAGE_SIZE, i2s_dma_tx_handler, i2s_dma_tx_unmask_handler);
++#endif
++
++ return;
++}
++
++void i2s_dma_rx_init(i2s_config_type* ptri2s_config)
++{
++ memset(pi2s_config->pPage0RxBuf8ptr, 0, I2S_PAGE_SIZE);
++ memset(pi2s_config->pPage1RxBuf8ptr, 0, I2S_PAGE_SIZE);
++
++#if defined(ARM_ARCH)
++ GdmaI2sRx(I2S_RX_FIFO_RREG_PHY, i2s_rxdma_addr0, 0, I2S_PAGE_SIZE, i2s_dma_rx_handler, i2s_dma_rx_unmask_handler);
++ GdmaI2sRx(I2S_RX_FIFO_RREG_PHY, i2s_rxdma_addr1, 1, I2S_PAGE_SIZE, i2s_dma_rx_handler, i2s_dma_rx_unmask_handler);
++#else
++ GdmaI2sRx(I2S_RX_FIFO_RREG, (u32)ptri2s_config->pPage0RxBuf8ptr, 0, I2S_PAGE_SIZE, i2s_dma_rx_handler, i2s_dma_rx_unmask_handler);
++ GdmaI2sRx(I2S_RX_FIFO_RREG, (u32)ptri2s_config->pPage1RxBuf8ptr, 1, I2S_PAGE_SIZE, i2s_dma_rx_handler, i2s_dma_rx_unmask_handler);
++#endif
++
++ return;
++}
++
++void i2s_dma_tx_end_handle(i2s_config_type* ptri2s_config)
++{
++ if (ptri2s_config->tx_w_idx < ptri2s_config->tx_r_idx)
++ {
++ ptri2s_config->end_cnt = (ptri2s_config->tx_w_idx + MAX_I2S_PAGE)-ptri2s_config->tx_r_idx;
++ _printk("case1: w=%d, r=%d, end=%d\n", ptri2s_config->tx_w_idx, ptri2s_config->tx_r_idx, ptri2s_config->end_cnt);
++ }
++ else if (ptri2s_config->tx_w_idx > ptri2s_config->tx_r_idx)
++ {
++ ptri2s_config->end_cnt = ptri2s_config->tx_w_idx-ptri2s_config->tx_r_idx;
++ _printk("case2: w=%d, r=%d, end=%d\n", ptri2s_config->tx_w_idx, ptri2s_config->tx_r_idx, ptri2s_config->end_cnt);
++ }
++ else
++ {
++ _printk("case3: w=%d, r=%d, end=%d\n", ptri2s_config->tx_w_idx, ptri2s_config->tx_r_idx, ptri2s_config->end_cnt);
++
++ }
++
++ if (ptri2s_config->end_cnt > 0)
++ {
++ interruptible_sleep_on(&(ptri2s_config->i2s_tx_qh));
++ }
++
++ return;
++}
++
++void i2s_tx_end_sleep_on(i2s_config_type* ptri2s_config)
++{
++ while(ptri2s_config->tx_stop_cnt<3)
++ interruptible_sleep_on(&(ptri2s_config->i2s_tx_qh));
++
++ return;
++}
++
++void i2s_rx_end_sleep_on(i2s_config_type* ptri2s_config)
++{
++ while(ptri2s_config->rx_stop_cnt<2)
++ interruptible_sleep_on(&(ptri2s_config->i2s_rx_qh));
++ return;
++}
++
++int i2s_dma_tx_soft_stop(i2s_config_type* ptri2s_config, u32 dma_ch)
++{
++ if(dma_ch==GDMA_I2S_TX0)
++ {
++#if defined(ARM_ARCH)
++ GdmaI2sTx(i2s_txdma_addr0, I2S_TX_FIFO_WREG_PHY, 0, 4, i2s_dma_tx_handler, i2s_dma_tx_unmask_handler);
++#else
++ GdmaI2sTx((u32)pi2s_config->pPage0TxBuf8ptr, I2S_TX_FIFO_WREG, 0, 4, i2s_dma_tx_handler, i2s_dma_tx_unmask_handler);
++#endif
++ }
++ else
++ {
++#if defined(ARM_ARCH)
++ GdmaI2sTx(i2s_txdma_addr1, I2S_TX_FIFO_WREG_PHY, 1, 4, i2s_dma_tx_handler, i2s_dma_tx_unmask_handler);
++#else
++ GdmaI2sTx((u32)pi2s_config->pPage1TxBuf8ptr, I2S_TX_FIFO_WREG, 1, 4, i2s_dma_tx_handler, i2s_dma_tx_unmask_handler);
++#endif
++ }
++
++ return 0;
++}
++
++int i2s_dma_rx_soft_stop(i2s_config_type* ptri2s_config, u32 dma_ch)
++{
++ if(dma_ch==GDMA_I2S_RX0)
++ {
++ memset(pi2s_config->pPage0RxBuf8ptr, 0, I2S_PAGE_SIZE);
++#if defined(ARM_ARCH)
++ GdmaI2sRx(I2S_RX_FIFO_RREG_PHY, i2s_rxdma_addr0, 0, 4, i2s_dma_rx_handler, i2s_dma_rx_unmask_handler);
++#else
++ GdmaI2sRx(I2S_RX_FIFO_RREG, (u32)pi2s_config->pPage0RxBuf8ptr, 0, 4, i2s_dma_rx_handler, i2s_dma_rx_unmask_handler);
++#endif
++ }
++ else
++ {
++ memset(pi2s_config->pPage1RxBuf8ptr, 0, I2S_PAGE_SIZE);
++#if defined(ARM_ARCH)
++ GdmaI2sRx(I2S_RX_FIFO_RREG_PHY, i2s_rxdma_addr1, 1, 4, i2s_dma_rx_handler, i2s_dma_rx_unmask_handler);
++#else
++ GdmaI2sRx(I2S_RX_FIFO_RREG, (u32)pi2s_config->pPage1RxBuf8ptr, 1, 4, i2s_dma_rx_handler, i2s_dma_rx_unmask_handler);
++#endif
++ }
++
++ return 0;
++}
++
++void i2s_gen_test_pattern(void)
++{
++ int i;
++ for (i=0; i<I2S_PAGE_SIZE; i++)
++ {
++ test_buf[i] = 0x5A;
++ test_buf_1[i] = 0x11;
++ test_buf_2[i] = 0x22;
++
++ }
++}
++
++int i2s_put_audio(i2s_config_type* ptri2s_config, unsigned long arg)
++{
++ unsigned long flags;
++ int tx_w_idx;
++
++ do{
++ spin_lock_irqsave(&ptri2s_config->lock, flags);
++
++ if(((ptri2s_config->tx_w_idx+4)%MAX_I2S_PAGE)!=ptri2s_config->tx_r_idx)
++ {
++ ptri2s_config->tx_w_idx = (ptri2s_config->tx_w_idx+1)%MAX_I2S_PAGE;
++ tx_w_idx = ptri2s_config->tx_w_idx;
++ spin_unlock_irqrestore(&ptri2s_config->lock, flags);
++ //_printk("put TB[%d] for user write\n",ptri2s_config->tx_w_idx);
++#if defined(CONFIG_I2S_MMAP)
++ put_user(tx_w_idx, (int*)arg);
++#else
++ copy_from_user(ptri2s_config->pMMAPTxBufPtr[tx_w_idx], (char*)arg, I2S_PAGE_SIZE);
++#endif
++ pi2s_status->txbuffer_len++;
++ //spin_unlock_irqrestore(&ptri2s_config->lock, flags);
++ break;
++ }
++ else
++ {
++ /* Buffer Full */
++ //_printk("TBF tr=%d, tw=%d\n", ptri2s_config->tx_r_idx, ptri2s_config->tx_w_idx);
++ pi2s_status->txbuffer_ovrun++;
++ spin_unlock_irqrestore(&ptri2s_config->lock, flags);
++ interruptible_sleep_on(&(ptri2s_config->i2s_tx_qh));
++ if (ptri2s_config->bTxDMAEnable==0 && ptri2s_config->end_cnt==0)
++ {
++ _printk("wake up for exit i2s driver\n");
++ put_user(-1, (int*)arg);
++ break;
++ }
++ }
++ }while(1);
++
++ return 0;
++}
++
++int i2s_get_audio(i2s_config_type* ptri2s_config, unsigned long arg)
++{
++ unsigned long flags;
++ int rx_r_idx;
++
++ do{
++ spin_lock_irqsave(&ptri2s_config->lock, flags);
++ //_printk("GA rr=%d, rw=%d,i=%d\n", ptri2s_config->rx_r_idx, ptri2s_config->rx_w_idx,ptri2s_config->rx_isr_cnt);
++ if(((ptri2s_config->rx_r_idx+2)%MAX_I2S_PAGE)!=ptri2s_config->rx_w_idx)
++ {
++ rx_r_idx = ptri2s_config->rx_r_idx;
++ ptri2s_config->rx_r_idx = (ptri2s_config->rx_r_idx+1)%MAX_I2S_PAGE;
++ spin_unlock_irqrestore(&ptri2s_config->lock, flags);
++#if defined(CONFIG_I2S_MMAP)
++ put_user(rx_r_idx, (int*)arg);
++#else
++ copy_to_user((char*)arg, ptri2s_config->pMMAPRxBufPtr[rx_r_idx], I2S_PAGE_SIZE);
++#endif
++ //_printk("rx_r_idx=%d\n", ptri2s_config->rx_r_idx);
++ //ptri2s_config->rx_r_idx = (ptri2s_config->rx_r_idx+1)%MAX_I2S_PAGE;
++ pi2s_status->rxbuffer_len--;
++ //spin_unlock_irqrestore(&ptri2s_config->lock, flags);
++ break;
++ }
++ else
++ {
++ /* Buffer Full */
++ //_printk("RBF rr=%d, rw=%d\n", ptri2s_config->rx_r_idx, ptri2s_config->rx_w_idx);
++ pi2s_status->rxbuffer_ovrun++;
++ spin_unlock_irqrestore(&ptri2s_config->lock, flags);
++ interruptible_sleep_on(&(ptri2s_config->i2s_rx_qh));
++ }
++#if defined(CONFIG_I2S_WITH_AEC)
++ if(aecFuncP->AECECDeq){
++ aecFuncP->AECECDeq(0,pi2s_config->pMMAPRxBufPtr[ptri2s_config->rx_r_idx],I2S_PAGE_SIZE);
++ }
++#endif
++ }while(1);
++
++ return 0;
++}
++
++#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,35)
++long i2s_ioctl (struct file *filp, unsigned int cmd, unsigned long arg)
++#else
++int i2s_ioctl (struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)
++#endif
++{
++ int i ;
++ i2s_config_type* ptri2s_config;
++ unsigned long flags;
++
++ ptri2s_config = filp->private_data;
++ switch (cmd) {
++ case I2S_RESET:
++ spin_lock_irqsave(&ptri2s_config->lock, flags);
++ i2s_reset_config(ptri2s_config);
++ spin_unlock_irqrestore(&ptri2s_config->lock, flags);
++ break;
++ case I2S_SRATE:
++ spin_lock_irqsave(&ptri2s_config->lock, flags);
++#if defined(CONFIG_I2S_WM8960)
++ if((arg>MAX_SRATE_HZ)||(arg<MIN_SRATE_HZ))
++ {
++ MSG("Audio sampling rate %u should be %d ~ %d Hz. Set SRate to 48000Hz\n", (u32)arg, MIN_SRATE_HZ, MAX_SRATE_HZ);
++ ptri2s_config->srate = 48000;
++ spin_unlock(&ptri2s_config->lock);
++ break;
++ }
++#elif defined(CONFIG_I2S_WM8750)
++ if((arg>MAX_SRATE_HZ)||(arg<MIN_SRATE_HZ))
++ {
++ MSG("Audio sampling rate %u should be %d ~ %d Hz. Set SRate to 96000Hz\n", (u32)arg, MIN_SRATE_HZ, MAX_SRATE_HZ);
++ ptri2s_config->srate = 96000;
++ spin_unlock(&ptri2s_config->lock);
++ break;
++ }
++#endif
++ ptri2s_config->srate = arg;
++ spin_unlock_irqrestore(&ptri2s_config->lock, flags);
++ MSG("set audio sampling rate to %d Hz\n", ptri2s_config->srate);
++ break;
++ case I2S_TX_VOL:
++ spin_lock_irqsave(&ptri2s_config->lock, flags);
++
++ if((int)arg > 127)
++ ptri2s_config->txvol = 127;
++ else if((int)arg < 48)
++ ptri2s_config->txvol = 48;
++ else
++ ptri2s_config->txvol = arg;
++
++ spin_unlock_irqrestore(&ptri2s_config->lock, flags);
++
++ spin_lock_irqsave(&ptri2s_config->lock, flags);
++#if (defined(CONFIG_I2S_WM8750) || defined(CONFIG_I2S_WM8751))
++ audiohw_set_master_vol(arg,arg);
++#elif defined(CONFIG_I2S_WM8960)
++ audiohw_set_lineout_vol(1, ptri2s_config->txvol, ptri2s_config->txvol);
++#endif
++ spin_unlock_irqrestore(&ptri2s_config->lock, flags);
++ break;
++ case I2S_RX_VOL:
++ spin_lock_irqsave(&ptri2s_config->lock, flags);
++
++ if((int)arg > 63)
++ ptri2s_config->rxvol = 63;
++ else if((int)arg < 0)
++ ptri2s_config->rxvol = 0;
++ else
++ ptri2s_config->rxvol = arg;
++
++ spin_unlock_irqrestore(&ptri2s_config->lock, flags);
++ break;
++#if defined (CONFIG_RALINK_MT7628) || defined(CONFIG_ARCH_MT7623)
++ case I2S_WORD_LEN:
++ spin_lock_irqsave(&ptri2s_config->lock, flags);
++ if((int)arg == 16)
++ {
++ ptri2s_config->wordlen_24b = 0;
++ MSG("Enable 16 bit word length.\n");
++ }
++ else if ((int)arg == 24)
++ {
++ ptri2s_config->wordlen_24b = 1;
++ MSG("Enable 24 bit word length.\n");
++ }
++ else
++ {
++ MSG("MT7628 only support 16bit/24bit word length.\n");
++ spin_unlock(&ptri2s_config->lock);
++ break;
++ }
++ spin_unlock_irqrestore(&ptri2s_config->lock, flags);
++ break;
++ case I2S_ENDIAN_FMT:
++ spin_lock_irqsave(&ptri2s_config->lock, flags);
++ if((int)arg == 1)
++ {
++ ptri2s_config->little_edn = 1;
++ MSG("Little endian format.\n");
++ }
++ else
++ {
++ ptri2s_config->little_edn = 0;
++ MSG("Big endian format.\n");
++ }
++ spin_unlock_irqrestore(&ptri2s_config->lock, flags);
++ break;
++#endif
++ case I2S_INTERNAL_LBK:
++ spin_lock_irqsave(&ptri2s_config->lock, flags);
++ if((int)arg == 1)
++ {
++ ptri2s_config->lbk = 1;
++ MSG("Enable internal loopback.\n");
++ }
++ else
++ {
++ ptri2s_config->lbk = 0;
++ MSG("Disable internal loopback.\n");
++ }
++ spin_unlock_irqrestore(&ptri2s_config->lock, flags);
++ break;
++ case I2S_EXTERNAL_LBK:
++ spin_lock_irqsave(&ptri2s_config->lock, flags);
++ if((int)arg == 1)
++ {
++ ptri2s_config->extlbk = 1;
++ MSG("Enable external loopback.\n");
++ }
++ else
++ {
++ ptri2s_config->extlbk = 0;
++ MSG("Disable external loopback.\n");
++ }
++ spin_unlock_irqrestore(&ptri2s_config->lock, flags);
++ break;
++ case I2S_TXRX_COEXIST:
++ spin_lock_irqsave(&ptri2s_config->lock, flags);
++ if((int)arg == 1)
++ {
++ ptri2s_config->txrx_coexist = 1;
++ MSG("TX/RX coexist.\n");
++ }
++ else
++ {
++ ptri2s_config->txrx_coexist = 0;
++ MSG("TX/RX coexist.\n");
++ }
++ spin_unlock_irqrestore(&ptri2s_config->lock, flags);
++ break;
++
++ case I2S_TX_ENABLE:
++ spin_lock_irqsave(&ptri2s_config->lock, flags);
++ MSG("I2S_TXENABLE\n");
++
++ pi2s_config->tx_unmask_ch = 0;
++ tasklet_init(&i2s_tx_tasklet, i2s_tx_task, (u32)pi2s_config);
++
++ pi2s_config->dis_match = 0;
++ pi2s_config->start_cnt = 0;
++ i2s_gen_test_pattern();
++
++ /* allocate tx buffer */
++ i2s_txPagebuf_alloc(ptri2s_config);
++ i2s_txbuf_alloc(ptri2s_config);
++
++ /* Init two dma channels */
++ i2s_dma_tx_init(ptri2s_config);
++ spin_unlock_irqrestore(&ptri2s_config->lock, flags);
++
++ spin_lock_irqsave(&ptri2s_config->lock, flags);
++ /* Init & config all tx param */
++ i2s_reset_tx_param(ptri2s_config);
++ ptri2s_config->bTxDMAEnable = 1;
++ /* Clear all ALSA related config */
++ ptri2s_config->bALSAEnable = 0;
++ ptri2s_config->bALSAMMAPEnable = 0;
++
++ i2s_tx_config(ptri2s_config);
++
++ if(ptri2s_config->bRxDMAEnable==0)
++ i2s_clock_enable(ptri2s_config);
++ spin_unlock_irqrestore(&ptri2s_config->lock, flags);
++
++ spin_lock_irqsave(&ptri2s_config->lock, flags);
++#if defined(CONFIG_I2S_WM8960)||defined(CONFIG_I2S_WM8750)||defined(CONFIG_I2S_WM8751)
++ audiohw_set_lineout_vol(1, ptri2s_config->txvol, ptri2s_config->txvol);
++#endif
++ GdmaUnMaskChannel(GDMA_I2S_TX0);
++
++ i2s_tx_enable(ptri2s_config);
++
++ /* Kick off dma channel */
++ //GdmaUnMaskChannel(GDMA_I2S_TX0);
++
++ MSG("I2S_TXENABLE done\n");
++ spin_unlock_irqrestore(&ptri2s_config->lock, flags);
++ break;
++ case I2S_TX_DISABLE:
++ spin_lock_irqsave(&ptri2s_config->lock, flags);
++ MSG("I2S_TXDISABLE\n");
++
++ //tasklet_kill(&i2s_tx_tasklet);
++
++ /* Handle tx end data */
++ ptri2s_config->bTxDMAEnable = 0;
++ spin_unlock_irqrestore(&ptri2s_config->lock, flags);
++
++ i2s_tx_end_sleep_on(ptri2s_config);
++
++ tasklet_kill(&i2s_tx_tasklet);
++
++ spin_lock_irqsave(&ptri2s_config->lock, flags);
++ i2s_reset_tx_param(ptri2s_config);
++ i2s_tx_disable(ptri2s_config);
++ if((ptri2s_config->bRxDMAEnable==0)&&(ptri2s_config->bTxDMAEnable==0))
++ i2s_clock_disable(ptri2s_config);
++
++ i2s_txbuf_free(ptri2s_config);
++ if(ptri2s_config->mmap_index <= MAX_I2S_PAGE)
++ ptri2s_config->mmap_index = 0;
++
++ spin_unlock_irqrestore(&ptri2s_config->lock, flags);
++ break;
++ case I2S_RX_ENABLE:
++ spin_lock_irqsave(&ptri2s_config->lock, flags);
++ MSG("I2S_RXENABLE\n");
++ pi2s_config->rx_unmask_ch = 0;
++ tasklet_init(&i2s_rx_tasklet, i2s_rx_task, (u32)pi2s_config);
++
++ /* allocate rx buffer */
++ i2s_rxPagebuf_alloc(ptri2s_config);
++ i2s_rxbuf_alloc(ptri2s_config);
++
++ /* Init two dma channels */
++ i2s_dma_rx_init(ptri2s_config);
++ spin_unlock_irqrestore(&ptri2s_config->lock, flags);
++
++ spin_lock_irqsave(&ptri2s_config->lock, flags);
++ /* Init & config all rx param */
++ i2s_reset_rx_param(ptri2s_config);
++ ptri2s_config->bRxDMAEnable = 1;
++ ptri2s_config->bALSAEnable = 0;
++ ptri2s_config->bALSAMMAPEnable = 0;
++
++ i2s_rx_config(ptri2s_config);
++
++ if(ptri2s_config->bTxDMAEnable==0)
++ i2s_clock_enable(ptri2s_config);
++
++#if defined(CONFIG_I2S_TXRX)
++#if defined(CONFIG_I2S_WM8960)||defined(CONFIG_I2S_WM8750)||defined(CONFIG_I2S_WM8751)
++ audiohw_set_linein_vol(ptri2s_config->rxvol, ptri2s_config->rxvol);
++#endif
++#endif
++ spin_unlock_irqrestore(&ptri2s_config->lock, flags);
++
++ spin_lock_irqsave(&ptri2s_config->lock, flags);
++ /* Kick off dma channel */
++ GdmaUnMaskChannel(GDMA_I2S_RX0);
++
++ i2s_rx_enable(ptri2s_config);
++ spin_unlock_irqrestore(&ptri2s_config->lock, flags);
++ break;
++ case I2S_RX_DISABLE:
++ spin_lock_irqsave(&ptri2s_config->lock, flags);
++ MSG("I2S_RXDISABLE\n");
++ //tasklet_kill(&i2s_rx_tasklet);
++
++ ptri2s_config->bRxDMAEnable = 0;
++ spin_unlock_irqrestore(&ptri2s_config->lock, flags);
++
++ i2s_rx_end_sleep_on(ptri2s_config);
++ tasklet_kill(&i2s_rx_tasklet);
++
++ spin_lock_irqsave(&ptri2s_config->lock, flags);
++ i2s_reset_rx_param(ptri2s_config);
++ i2s_rx_disable(ptri2s_config);
++ if((ptri2s_config->bRxDMAEnable==0)&&(ptri2s_config->bTxDMAEnable==0))
++ i2s_clock_disable(ptri2s_config);
++
++ i2s_rxbuf_free(ptri2s_config);
++ if(ptri2s_config->mmap_index <= MAX_I2S_PAGE)
++ ptri2s_config->mmap_index = 0;
++ //i2s_rxPagebuf_free(ptri2s_config);
++ spin_unlock_irqrestore(&ptri2s_config->lock, flags);
++ break;
++ case I2S_PUT_AUDIO:
++ i2s_put_audio(ptri2s_config, arg);
++ break;
++ case I2S_GET_AUDIO:
++ i2s_get_audio(ptri2s_config, arg);
++ break;
++ case I2S_TX_STOP:
++ spin_lock_irqsave(&ptri2s_config->lock, flags);
++ MSG("TxGDMA STOP\n");
++ ptri2s_config->bTxDMAEnable = 0;
++ ptri2s_config->end_cnt = 0;
++ spin_unlock_irqrestore(&ptri2s_config->lock, flags);
++
++ while(ptri2s_config->tx_stop_cnt<3)
++ interruptible_sleep_on(&(ptri2s_config->i2s_tx_qh));
++
++ spin_lock_irqsave(&ptri2s_config->lock, flags);
++ i2s_reset_tx_param(ptri2s_config);
++ i2s_tx_disable(ptri2s_config);
++ if((ptri2s_config->bRxDMAEnable==0)&&(ptri2s_config->bTxDMAEnable==0))
++ i2s_clock_disable(ptri2s_config);
++
++ spin_unlock_irqrestore(&ptri2s_config->lock, flags);
++
++ spin_lock_irqsave(&ptri2s_config->lock, flags);
++ i2s_txbuf_free(ptri2s_config);
++ if(ptri2s_config->mmap_index <= MAX_I2S_PAGE)
++ ptri2s_config->mmap_index = 0;
++ //i2s_txPagebuf_free(ptri2s_config);
++ spin_unlock_irqrestore(&ptri2s_config->lock, flags);
++ break;
++ case I2S_TX_PAUSE:
++ spin_lock_irqsave(&ptri2s_config->lock, flags);
++ ptri2s_config->tx_pause_en = 1;
++ MSG("* tx_pause_en = 1 *\n");
++ spin_unlock_irqrestore(&ptri2s_config->lock, flags);
++ break;
++ case I2S_TX_RESUME:
++ spin_lock_irqsave(&ptri2s_config->lock, flags);
++ ptri2s_config->tx_pause_en = 0;
++ MSG("# tx_pause_en = 0 #\n");
++ spin_unlock_irqrestore(&ptri2s_config->lock, flags);
++ break;
++ case I2S_RX_STOP:
++ spin_lock_irqsave(&ptri2s_config->lock, flags);
++ MSG("I2S_RX_STOP\n");
++ ptri2s_config->bRxDMAEnable = 0;
++ spin_unlock_irqrestore(&ptri2s_config->lock, flags);
++
++ while(ptri2s_config->rx_stop_cnt<2)
++ interruptible_sleep_on(&(ptri2s_config->i2s_rx_qh));
++
++ spin_lock_irqsave(&ptri2s_config->lock, flags);
++ i2s_reset_rx_param(ptri2s_config);
++ i2s_rx_disable(ptri2s_config);
++ if((ptri2s_config->bRxDMAEnable==0)&&(ptri2s_config->bTxDMAEnable==0))
++ i2s_clock_disable(ptri2s_config);
++ spin_unlock_irqrestore(&ptri2s_config->lock, flags);
++
++ spin_lock_irqsave(&ptri2s_config->lock, flags);
++ i2s_rxbuf_free(ptri2s_config);
++ if(ptri2s_config->mmap_index <= MAX_I2S_PAGE)
++ ptri2s_config->mmap_index = 0;
++ //i2s_rxPagebuf_free(ptri2s_config);
++ spin_unlock_irqrestore(&ptri2s_config->lock, flags);
++ break;
++ case I2S_RX_PAUSE:
++ spin_lock_irqsave(&ptri2s_config->lock, flags);
++ ptri2s_config->rx_pause_en = 1;
++ MSG("* rx_pause_en = 1 *\n");
++ spin_unlock_irqrestore(&ptri2s_config->lock, flags);
++ break;
++ case I2S_RX_RESUME:
++ spin_lock_irqsave(&ptri2s_config->lock, flags);
++ ptri2s_config->rx_pause_en = 0;
++ MSG("# rx_pause_en = 0 #\n");
++ spin_unlock_irqrestore(&ptri2s_config->lock, flags);
++ break;
++ case I2S_CODEC_MIC_BOOST:
++ spin_lock_irqsave(&ptri2s_config->lock, flags);
++ if((int)arg > 3)
++ ptri2s_config->micboost = 3;
++ else if((int)arg < 0)
++ ptri2s_config->micboost = 0;
++ else
++ ptri2s_config->micboost = arg;
++ spin_unlock_irqrestore(&ptri2s_config->lock, flags);
++ break;
++ case I2S_CODEC_MIC_IN:
++ spin_lock_irqsave(&ptri2s_config->lock, flags);
++ if((int)arg == 1)
++ ptri2s_config->micin = 1;
++ else
++ ptri2s_config->micin = 0;
++ spin_unlock_irqrestore(&ptri2s_config->lock, flags);
++ break;
++ case I2S_CLOCK_ENABLE:
++ spin_lock_irqsave(&ptri2s_config->lock, flags);
++ i2s_clock_disable(ptri2s_config);
++#if defined(CONFIG_RALINK_MT7628) || defined(CONFIG_ARCH_MT7623)
++ ptri2s_config->wordlen_24b = 1;
++#endif
++ i2s_tx_config(ptri2s_config);
++ i2s_clock_enable(ptri2s_config);
++ i2s_tx_enable(ptri2s_config);
++ spin_unlock_irqrestore(&ptri2s_config->lock, flags);
++ break;
++ case I2S_DEBUG_CODEC:
++ spin_lock_irqsave(&ptri2s_config->lock, flags);
++ for (i=0; i<10; i++)
++ {
++ _printk("### i=%d ###\n", i);
++ i2s_clock_enable(ptri2s_config);
++ i2s_clock_disable(ptri2s_config);
++ }
++ spin_unlock_irqrestore(&ptri2s_config->lock, flags);
++ break;
++#if defined(CONFIG_I2S_MS_CTRL)
++ case I2S_MS_MODE_CTRL:
++ spin_lock_irqsave(&ptri2s_config->lock, flags);
++ if((int)arg == 1)
++ {
++ ptri2s_config->slave_en = 1;
++ _printk("I2S in slave mode.\n");
++ }
++ else
++ {
++ ptri2s_config->slave_en = 0;
++ _printk("I2S in master mode.\n");
++ }
++ spin_unlock_irqrestore(&ptri2s_config->lock, flags);
++ break;
++#endif
++ case I2S_DEBUG_CLKGEN:
++ case I2S_DEBUG_INLBK:
++ case I2S_DEBUG_EXLBK:
++ case I2S_DEBUG_CODECBYPASS:
++ case I2S_DEBUG_FMT:
++#if defined(CONFIG_I2S_WM8960)
++ case I2S_DEBUG_CODEC_EXLBK:
++#endif
++ case I2S_DEBUG_RESET:
++ i2s_debug_cmd(cmd, arg);
++ break;
++ default :
++ MSG("i2s_ioctl: command format error\n");
++ }
++
++ return 0;
++}
++
++/************************
++ * API for ALSA *
++ * *
++ ************************/
++char* i2s_memPool_Alloc(i2s_config_type* ptri2s_config,int dir)
++{
++ //_printk("%s\n",__func__);
++ if(!ptri2s_config)
++ return NULL;
++ if(dir == STREAM_PLAYBACK){
++#if defined(CONFIG_I2S_MMAP)
++ i2s_mmap_alloc(I2S_TOTAL_PAGE_SIZE);
++#endif
++ i2s_txbuf_alloc(ptri2s_config);
++ return ptri2s_config->pMMAPTxBufPtr[0];
++ }else{
++#if defined(CONFIG_I2S_MMAP)
++ i2s_mmap_alloc(I2S_TOTAL_PAGE_SIZE);
++#endif
++ i2s_rxbuf_alloc(ptri2s_config);
++ return ptri2s_config->pMMAPRxBufPtr[0];
++ }
++ return NULL;
++}
++
++void i2s_memPool_free(i2s_config_type* ptri2s_config,int dir)
++{
++ if(!ptri2s_config)
++ return;
++ if(dir == STREAM_PLAYBACK){
++#if defined(CONFIG_I2S_MMAP)
++ i2s_mem_unmap(ptri2s_config);
++#endif
++ i2s_txbuf_free(ptri2s_config);
++ }else{
++#if defined(CONFIG_I2S_MMAP)
++ i2s_mem_unmap(ptri2s_config);
++#endif
++ i2s_rxbuf_free(ptri2s_config);
++ }
++
++ return;
++}
++
++int i2s_page_prepare(i2s_config_type* ptri2s_config,int dir)
++{
++ if(dir == STREAM_PLAYBACK){
++ /* allocate tx buffer */
++ i2s_txPagebuf_alloc(ptri2s_config);
++ i2s_dma_tx_init(ptri2s_config);
++ }else{
++ /* allocate rx buffer */
++ i2s_rxPagebuf_alloc(ptri2s_config);
++ i2s_dma_rx_init(ptri2s_config);
++ }
++ return 0;
++}
++
++int i2s_page_release(i2s_config_type* ptri2s_config,int dir)
++{
++ if(!ptri2s_config)
++ return (-1);
++ if(dir == STREAM_PLAYBACK)
++ i2s_txPagebuf_free(ptri2s_config);
++ else
++ i2s_rxPagebuf_free(ptri2s_config);
++
++ return 0;
++}
++
++int i2s_startup(void)
++{
++ memset(pi2s_config, 0, sizeof(i2s_config_type));
++
++#ifdef I2S_STATISTIC
++ memset(pi2s_status, 0, sizeof(i2s_status_type));
++#endif
++
++ i2s_param_init(pi2s_config);
++ pi2s_config->bALSAEnable = 1;
++#if defined(CONFIG_I2S_MMAP)
++ pi2s_config->bALSAMMAPEnable = 1;
++#endif
++
++#if defined (CONFIG_RALINK_MT7628) || defined(CONFIG_ARCH_MT7623)
++ pi2s_config->little_edn = 1;
++#endif
++
++ init_waitqueue_head(&(pi2s_config->i2s_tx_qh));
++ init_waitqueue_head(&(pi2s_config->i2s_rx_qh));
++ spin_lock_init(&pi2s_config->lock);
++
++ return 0;
++}
++
++int gdma_En_Switch(i2s_config_type* ptri2s_config,int dir,int enabled){
++ if(!ptri2s_config)
++ return (-1);
++ if(dir == STREAM_PLAYBACK){
++ ptri2s_config->bTxDMAEnable = enabled;
++ //MSG("%s:%d\n",__func__,ptri2s_config->bTxDMAEnable);
++ }else{
++ ptri2s_config->bRxDMAEnable = enabled;
++ }
++ return 0;
++}
++
++int i2s_audio_exchange(i2s_config_type* ptri2s_config,int dir,unsigned long arg)
++{
++ //MSG("I2S_PUT_AUDIO\n");
++ if(!ptri2s_config)
++ return (-1);
++ if(dir == STREAM_PLAYBACK){
++ i2s_put_audio(ptri2s_config, arg);
++ }else{
++ i2s_get_audio(ptri2s_config, arg);
++ }
++ return 0;
++}
++
++void gdma_mask_handler(u32 dma_ch)
++{
++ i2s_dma_mask_handler(dma_ch);
++ return;
++}
++
++void gdma_unmask_handler(u32 dma_ch)
++{
++ i2s_dma_unmask_handler(dma_ch);
++ return;
++}
++
++u32 i2s_mmap_phys_addr(i2s_config_type* ptri2s_config)
++{
++ if((ptri2s_config->pMMAPBufPtr[0]!=NULL) && (ptri2s_config->mmap_index == MAX_I2S_PAGE))
++ return (dma_addr_t)i2s_mmap_addr[0];
++ else if((ptri2s_config->pMMAPBufPtr[MAX_I2S_PAGE]!=NULL) && (ptri2s_config->mmap_index == MAX_I2S_PAGE*2))
++ return (dma_addr_t)i2s_mmap_addr[MAX_I2S_PAGE];
++ else
++ return -1;
++}
++
++EXPORT_SYMBOL(i2s_startup);
++EXPORT_SYMBOL(i2s_mem_unmap);
++EXPORT_SYMBOL(i2s_mmap_alloc);
++EXPORT_SYMBOL(i2s_mmap_remap);
++EXPORT_SYMBOL(i2s_param_init);
++EXPORT_SYMBOL(i2s_txbuf_alloc);
++EXPORT_SYMBOL(i2s_rxbuf_alloc);
++EXPORT_SYMBOL(i2s_txPagebuf_alloc);
++EXPORT_SYMBOL(i2s_rxPagebuf_alloc);
++EXPORT_SYMBOL(i2s_txbuf_free);
++EXPORT_SYMBOL(i2s_rxbuf_free);
++EXPORT_SYMBOL(i2s_txPagebuf_free);
++EXPORT_SYMBOL(i2s_rxPagebuf_free);
++EXPORT_SYMBOL(i2s_rx_disable);
++EXPORT_SYMBOL(i2s_tx_disable);
++EXPORT_SYMBOL(i2s_rx_enable);
++EXPORT_SYMBOL(i2s_tx_enable);
++EXPORT_SYMBOL(i2s_rx_config);
++EXPORT_SYMBOL(i2s_tx_config);
++EXPORT_SYMBOL(i2s_reset_config);
++EXPORT_SYMBOL(i2s_clock_disable);
++EXPORT_SYMBOL(i2s_clock_enable);
++EXPORT_SYMBOL(i2s_reset_rx_param);
++EXPORT_SYMBOL(i2s_reset_tx_param);
++EXPORT_SYMBOL(i2s_dma_rx_handler);
++EXPORT_SYMBOL(i2s_dma_tx_handler);
++EXPORT_SYMBOL(i2s_dma_unmask_handler);
++EXPORT_SYMBOL(i2s_dma_tx_unmask_handler);
++EXPORT_SYMBOL(i2s_dma_rx_unmask_handler);
++EXPORT_SYMBOL(i2s_dma_mask_handler);
++EXPORT_SYMBOL(i2s_dma_tx_init);
++EXPORT_SYMBOL(i2s_dma_rx_init);
++EXPORT_SYMBOL(i2s_tx_end_sleep_on);
++EXPORT_SYMBOL(i2s_rx_end_sleep_on);
++EXPORT_SYMBOL(i2s_mmap_phys_addr);
++EXPORT_SYMBOL(i2s_open);
++EXPORT_SYMBOL(pi2s_config);
++#if defined(CONFIG_I2S_IN_MCLK)
++#if defined(CONFIG_I2S_MCLK_12MHZ)
++EXPORT_SYMBOL(i2s_refclk_12m_enable);
++#endif
++#if defined(CONFIG_I2S_MCLK_12P288MHZ)
++EXPORT_SYMBOL(i2s_refclk_12p288m_enable);
++#endif
++#endif
++#if defined(MT7628_ASIC_BOARD) || defined(CONFIG_ARCH_MT7623)
++EXPORT_SYMBOL(i2s_driving_strength_adjust);
++#endif
++EXPORT_SYMBOL(i2s_refclk_disable);
++EXPORT_SYMBOL(i2s_refclk_gpio_out_config);
++EXPORT_SYMBOL(i2s_refclk_gpio_in_config);
++EXPORT_SYMBOL(i2s_share_pin_config);
++EXPORT_SYMBOL(i2s_share_pin_mt7623);
++EXPORT_SYMBOL(i2s_ws_config);
++EXPORT_SYMBOL(i2s_mode_config);
++EXPORT_SYMBOL(i2s_codec_frequency_config);
++EXPORT_SYMBOL(i2s_dma_tx_transf_data);
++EXPORT_SYMBOL(i2s_dma_tx_transf_zero);
++EXPORT_SYMBOL(i2s_dma_rx_transf_data);
++EXPORT_SYMBOL(i2s_dma_rx_transf_zero);
++EXPORT_SYMBOL(i2s_dma_tx_end_handle);
++EXPORT_SYMBOL(i2s_dma_tx_soft_stop);
++EXPORT_SYMBOL(i2s_dma_rx_soft_stop);
++EXPORT_SYMBOL(i2s_tx_task);
++EXPORT_SYMBOL(i2s_rx_task);
++
++EXPORT_SYMBOL(i2s_memPool_Alloc);
++EXPORT_SYMBOL(i2s_memPool_free);
++EXPORT_SYMBOL(i2s_page_prepare);
++EXPORT_SYMBOL(i2s_page_release);
++EXPORT_SYMBOL(gdma_En_Switch);
++EXPORT_SYMBOL(i2s_audio_exchange);
++EXPORT_SYMBOL(gdma_mask_handler);
++EXPORT_SYMBOL(gdma_unmask_handler);
++#if defined(CONFIG_I2S_WITH_AEC)
++EXPORT_SYMBOL(aecFuncP);
++#endif
++module_init(i2s_mod_init);
++module_exit(i2s_mod_exit);
++
++MODULE_DESCRIPTION("Ralink SoC I2S Controller Module");
++MODULE_AUTHOR("Qwert Chin <qwert.chin@ralinktech.com.tw>");
++MODULE_SUPPORTED_DEVICE("I2S");
++MODULE_VERSION(I2S_MOD_VERSION);
++MODULE_LICENSE("GPL");
++#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,12)
++MODULE_PARM (i2sdrv_major, "i");
++#else
++module_param (i2sdrv_major, int, 0);
++#endif
+diff --git a/sound/soc/mtk/i2s_ctrl.h b/sound/soc/mtk/i2s_ctrl.h
+new file mode 100644
+index 0000000..b762c9c
+--- /dev/null
++++ b/sound/soc/mtk/i2s_ctrl.h
+@@ -0,0 +1,523 @@
++#ifndef __RALINK_I2S_H_
++#define __RALINK_I2S_H_
++
++#ifdef __KERNEL__
++//#include <asm/rt2880/rt_mmap.h>
++#endif
++
++#if defined(CONFIG_I2S_WITH_AEC)
++#include "aec/aec_api.h"
++#endif
++
++#define I2S_MAX_DEV 1
++#define I2S_MOD_VERSION "0.1"
++#define phys_to_bus(a) (a & 0x1FFFFFFF)
++
++#ifndef u32
++#define u32 unsigned int
++#endif
++
++#ifndef u16
++#define u16 unsigned short
++#endif
++
++#ifndef u8
++#define u8 unsigned char
++#endif
++
++#ifndef REGBIT
++#define REGBIT(x, n) (x << n)
++#endif
++
++#define Virtual2Physical(x) (((int)x) & 0x1fffffff)
++#define Physical2Virtual(x) (((int)x) | 0x80000000)
++#define Virtual2NonCache(x) (((int)x) | 0x20000000)
++#define Physical2NonCache(x) (((int)x) | 0xa0000000)
++#define NonCache2Virtual(x) (((int)x) & 0xDFFFFFFF)
++
++#if defined(CONFIG_I2S_MCLK_12MHZ)
++#define CONFIG_I2S_CODEC_PLL_EN 1
++#else
++#define CONFIG_I2S_CODEC_PLL_EN 0
++#endif
++
++//#define CONFIG_I2S_MS_CTRL
++//#define CONFIG_I2S_MS_MODE
++//#define memory_test
++
++#if defined (CONFIG_ARCH_MT7623)
++#define MT7623_ASIC_BOARD
++#define ARM_ARCH
++#endif
++
++#if defined (CONFIG_RALINK_MT7621)
++#define MT7621_ASIC_BOARD
++#endif
++
++#if defined (CONFIG_RALINK_MT7628)
++#define MT7628_ASIC_BOARD
++#endif
++
++//#define I2S_DEBUG_PRN
++#ifdef I2S_DEBUG_PRN
++#define MSG(fmt, args...) printk("I2S: " fmt, ## args)
++#else
++#define MSG(fmt, args...) { }
++#endif
++
++#ifdef I2S_DEBUG_PRN
++#define i2s_outw(address, value) do{printk("0x%08X = 0x%08X\n",(u32)address,(u32)value);*((volatile uint32_t *)(address)) = cpu_to_le32(value);}while(0)
++#else
++#define i2s_outw(address, value) *((volatile uint32_t *)(address)) = cpu_to_le32(value)
++#endif
++#define i2s_inw(address) le32_to_cpu(*(volatile u32 *)(address))
++
++/* HW feature definiations */
++#if defined(CONFIG_RALINK_RT3883)
++#define CONFIG_I2S_TXRX 1
++#define CONFIG_I2S_IN_MCLK 1
++//#define CONFIG_I2S_WS_EDGE 1
++#define CONFIG_I2S_FRAC_DIV 1
++#define CONFIG_I2S_IN_CLK 1
++#define CONFIG_I2S_MS_MODE 1
++#endif
++
++#if defined(CONFIG_RALINK_RT3352)||defined(CONFIG_RALINK_RT5350) || defined (CONFIG_RALINK_RT6855) \
++ || defined(CONFIG_RALINK_RT6855A) || defined(CONFIG_RALINK_MT7620) || defined(CONFIG_RALINK_MT7621) \
++ || defined (CONFIG_RALINK_MT7628) || defined(CONFIG_ARCH_MT7623)
++#define CONFIG_I2S_TXRX 1
++//#define CONFIG_I2S_WS_EDGE 1
++#define CONFIG_I2S_FRAC_DIV 1
++#define CONFIG_I2S_IN_CLK 1
++#endif
++
++#if defined(CONFIG_RALINK_RT3350)
++#define CONFIG_I2S_IN_MCLK 1
++#endif
++
++#if defined(CONFIG_RALINK_RT3052)
++#define CONFIG_I2S_MS_MODE 1
++#endif
++
++/* This is decided in menuconfig */
++#define CONFIG_I2S_MMAP 1
++
++/* For MT7623 ASIC PLL Setting */
++#if defined(CONFIG_ARCH_MT7623)
++#define AUD1PLL_CON0 (0xF0209270)
++#define AUD1PLL_CON1 (0xF0209274)
++#define AUD1PLL_CON2 (0xF0209278)
++#define AUD1PLL_PWR_CON0 (0xF020927C)
++#define AUD2PLL_CON0 (0xF02092C0)
++#define AUD2PLL_CON1 (0xF02092C4)
++#define AUD2PLL_CON2 (0xF02092C8)
++#define AUD2PLL_PWR_CON0 (0xF02092CC)
++#endif
++
++/* Register Map, Ref to RT3052 Data Sheet */
++
++/* Register Map Detail */
++#if defined(CONFIG_ARCH_MT7623)
++#define I2S_I2SCFG (ETHDMASYS_I2S_BASE+0x0000)
++#define I2S_INT_STATUS (ETHDMASYS_I2S_BASE+0x0004)
++#define I2S_INT_EN (ETHDMASYS_I2S_BASE+0x0008)
++#define I2S_FF_STATUS (ETHDMASYS_I2S_BASE+0x000c)
++#define I2S_FIFO_WREG (ETHDMASYS_I2S_BASE+0x0010)
++#define I2S_TX_FIFO_WREG I2S_FIFO_WREG
++#define I2S_RX_FIFO_RREG (ETHDMASYS_I2S_BASE+0x0014)
++#define I2S_I2SCFG1 (ETHDMASYS_I2S_BASE+0x0018)
++#define I2S_DIVINT_CFG (ETHDMASYS_I2S_BASE+0x0024)
++#define I2S_DIVCOMP_CFG (ETHDMASYS_I2S_BASE+0x0020)
++#else
++#define I2S_I2SCFG (RALINK_I2S_BASE+0x0000)
++#define I2S_INT_STATUS (RALINK_I2S_BASE+0x0004)
++#define I2S_INT_EN (RALINK_I2S_BASE+0x0008)
++#define I2S_FF_STATUS (RALINK_I2S_BASE+0x000c)
++#define I2S_FIFO_WREG (RALINK_I2S_BASE+0x0010)
++#define I2S_TX_FIFO_WREG I2S_FIFO_WREG
++#define I2S_RX_FIFO_RREG (RALINK_I2S_BASE+0x0014)
++#define I2S_I2SCFG1 (RALINK_I2S_BASE+0x0018)
++#define I2S_DIVINT_CFG (RALINK_I2S_BASE+0x0024)
++#define I2S_DIVCOMP_CFG (RALINK_I2S_BASE+0x0020)
++#endif
++
++
++/* I2SCFG bit field */
++#define I2S_EN 31
++#define I2S_DMA_EN 30
++#if defined(CONFIG_RALINK_MT7628) || defined(CONFIG_ARCH_MT7623)
++#define I2S_LITTLE_ENDIAN 29
++#define I2S_SYS_ENDIAN 28
++#elif defined(CONFIG_RALINK_RT6855A)
++#define I2S_BYTE_SWAP 28
++#endif
++#define I2S_TX_EN 24
++#define I2S_RX_EN 20
++#if defined(CONFIG_RALINK_MT7628) || defined(CONFIG_ARCH_MT7623)
++#define I2S_NORM_24BIT 18
++#define I2S_DATA_24BIT 17
++#endif
++#define I2S_SLAVE_MODE 16
++#define I2S_RX_FF_THRES 12
++#define I2S_RX_CH_SWAP 11
++#define I2S_RX_CH1_OFF 10
++#define I2S_RX_CH0_OFF 9
++#if defined(CONFIG_RALINK_RT3052)
++#define I2S_CLK_OUT_DIS 8
++#endif
++#define I2S_TX_FF_THRES 4
++#define I2S_TX_CH_SWAP 3
++#define I2S_TX_CH1_OFF 2
++#define I2S_TX_CH0_OFF 1
++#if defined(CONFIG_RALINK_RT3052)
++#define I2S_SLAVE_EN 0
++#else
++#define I2S_WS_INV 0
++#endif
++/* INT_EN bit field */
++#define I2S_RX_INT3_EN 7
++#define I2S_RX_INT2_EN 6
++#define I2S_RX_INT1_EN 5
++#define I2S_RX_INT0_EN 4
++#define I2S_TX_INT3_EN 3
++#define I2S_TX_INT2_EN 2
++#define I2S_TX_INT1_EN 1
++#define I2S_TX_INT0_EN 0
++
++/* INT_STATUS bit field */
++#define I2S_RX_DMA_FAULT 7
++#define I2S_RX_OVRUN 6
++#define I2S_RX_UNRUN 5
++#define I2S_RX_THRES 4
++#define I2S_TX_DMA_FAULT 3
++#define I2S_TX_OVRUN 2
++#define I2S_TX_UNRUN 1
++#define I2S_TX_THRES 0
++
++/* FF_STATUS bit field */
++#define I2S_RX_EPCNT 4
++#define I2S_TX_EPCNT 0
++/* I2S_DIVCOMP_CFG bit field */
++#define I2S_CLKDIV_EN 31
++
++/* I2S_CFG1 bit field */
++#define I2S_LBK_EN 31
++#define I2S_EXT_LBK_EN 30
++#if defined(CONFIG_RALINK_MT7628) || defined(CONFIG_ARCH_MT7623)
++#define I2S_DATA_FMT 0
++#endif
++
++/* FIFO_WREG bit field */
++#define I2S_FIFO_WDATA 0
++
++/* Constant definition */
++#define NFF_THRES 4
++#define I2S_PAGE_SIZE 3072//(3*4096)//(1152*2*2*2)
++#define I2S_MIN_PAGE_SIZE 4096
++#define MAX_I2S_PAGE 8
++#define I2S_TOTAL_PAGE_SIZE (I2S_PAGE_SIZE*MAX_I2S_PAGE)
++
++#if defined(CONFIG_I2S_WM8960)
++#define MAX_SRATE_HZ 48000
++#define MIN_SRATE_HZ 8000
++#elif defined(CONFIG_I2S_WM8750)
++#define MAX_SRATE_HZ 96000
++#define MIN_SRATE_HZ 8000
++#endif
++
++#define MAX_VOL_DB +0
++#define MIN_VOL_DB -127
++
++#define ALSA_MMAP_IDX_SHIFT 2
++#if defined(CONFIG_SND_MT76XX_SOC)
++#define STREAM_PLAYBACK SNDRV_PCM_STREAM_PLAYBACK
++#define STREAM_CAPTURE SNDRV_PCM_STREAM_CAPTURE
++#else
++#define STREAM_PLAYBACK 0
++#define STREAM_CAPTURE 1
++#endif
++
++/* I2S I/O command */
++#define I2S_SRATE 0
++#define I2S_VOL 1
++#define I2S_ENABLE 2
++#define I2S_DISABLE 3
++#define I2S_TX_ENABLE 27
++#define I2S_TX_DISABLE 3
++#define I2S_GET_WBUF 4
++#define I2S_PUT_WBUF 5
++#define I2S_RX_ENABLE 6
++#define I2S_RX_DISABLE 7
++#define I2S_PUT_AUDIO 4
++#define I2S_GET_AUDIO 5
++#define I2S_TX_VOL 1
++#define I2S_RX_VOL 8
++#define I2S_WORD_LEN 9
++#define I2S_ENDIAN_FMT 10
++#define I2S_INTERNAL_LBK 11
++#define I2S_TX_STOP 12
++#define I2S_DEBUG_CODEC 13
++#define I2S_MS_MODE_CTRL 14
++#define I2S_TX_PAUSE 15
++#define I2S_TX_RESUME 16
++#define I2S_RESET 17
++#define I2S_RX_STOP 18
++#define I2S_EXTERNAL_LBK 19
++#define I2S_TXRX_COEXIST 20
++#define I2S_RX_PAUSE 21
++#define I2S_RX_RESUME 22
++#define I2S_CODEC_MIC_BOOST 23
++#define I2S_CODEC_MIC_IN 24
++#define I2S_CLOCK_ENABLE 25
++#define I2S_TEST_TEST 26
++
++#define I2S_DEBUG 30
++#define I2S_DEBUG_CLKGEN 30
++#define I2S_DEBUG_INLBK 31
++#define I2S_DEBUG_EXLBK 32
++#define I2S_DEBUG_FMT 33
++#define I2S_DEBUG_RESET 34
++#define I2S_DEBUG_CODECBYPASS 35
++#if defined(CONFIG_I2S_WM8960)
++#define I2S_DEBUG_CODEC_EXLBK 36
++#endif
++
++/* configuration */
++#define CONFIG_I2S_TFF_THRES NFF_THRES
++#define CONFIG_I2S_CH_SWAP 0
++#if defined(CONFIG_I2S_MS_MODE)
++#define CONFIG_I2S_SLAVE_EN 0
++#else
++#define CONFIG_I2S_SLAVE_EN 1
++#endif
++
++/* driver status definition */
++#define I2S_OK 0
++#define I2S_OUTOFMEM 0x01
++#define I2S_GDMAFAILED 0x02
++#define I2S_REQUEST_IRQ_FAILED 0x04
++#define I2S_REG_SETUP_FAILED 0x08
++
++#define I2S_STATISTIC
++//#define I2S_HW_INTERRUPT_EN
++//#define I2S_SW_IRQ_EN
++#define I2S_MAJOR 234
++
++/* parameter for ALSA */
++/*GDMA for I2S Status*/
++#define GDMA_I2S_DIS (0)
++#define GDMA_I2S_EN (1)
++
++
++typedef struct i2s_status_t
++{
++ u32 txdmafault;
++ u32 txovrun;
++ u32 txunrun;
++ u32 txthres;
++ int txbuffer_unrun;
++ int txbuffer_ovrun;
++ int txbuffer_len;
++
++ u32 rxdmafault;
++ u32 rxovrun;
++ u32 rxunrun;
++ u32 rxthres;
++ int rxbuffer_unrun;
++ int rxbuffer_ovrun;
++ int rxbuffer_len;
++}i2s_status_type;
++
++
++typedef struct i2s_config_t
++{
++
++ int srate;
++ int txvol;
++ int rxvol;
++ u32 pos;
++ u32 tx_isr_cnt;
++ u32 rx_isr_cnt;
++ int bSleep;
++ int bTxDMAEnable;
++ int bRxDMAEnable;
++ int enLable;
++ int micboost;
++ int micin;
++
++ /* parameters fo ALSA */
++ int bALSAEnable;
++ int bALSAMMAPEnable;
++ unsigned char bTrigger[2];
++ unsigned char bPreTrigger[2];
++ unsigned char dmaStat[2];
++ unsigned char i2sStat[2];
++ unsigned int hw_base_frame[2];
++ struct snd_pcm_substream *pss[2];
++
++#ifdef __KERNEL__
++ spinlock_t lock;
++ wait_queue_head_t i2s_tx_qh, i2s_rx_qh;
++#endif
++ u32 dmach;
++ u32 tx_unmask_ch;
++ u32 rx_unmask_ch;
++ u32 dma_unmask_status;
++ u32 dma_done_status;
++ u32 tx_ff_thres;
++ u32 tx_ch_swap;
++ u32 rx_ff_thres;
++ u32 rx_ch_swap;
++ u32 slave_en;
++
++ u32 dis_match;
++ int start_cnt;
++#if defined (CONFIG_RALINK_MT7628) || defined(CONFIG_ARCH_MT7623)
++ int little_edn; /* test file's fmt: little endian->1; big endian->0 */
++ int sys_endian; /* kernal' system fmt: little endian->0; big endian->1 */
++#endif
++ int wordlen_24b;
++ int codec_pll_en;
++ int codec_num;
++ int tx_pause_en;
++ int rx_pause_en;
++ int end_cnt;
++ int txrx_coexist;
++ int tx_stop_cnt;
++ int rx_stop_cnt;
++ /* for I2S_CFG1 */
++ u32 lbk;
++ u32 extlbk;
++ u32 fmt;
++
++ int w_idx;
++ int r_idx;
++
++ int tx_w_idx;
++ int tx_r_idx;
++ int rx_w_idx;
++ int rx_r_idx;
++ int mmap_index;
++ int next_p0_idx;
++ int next_p1_idx;
++
++ u8* buf8ptr;
++ char* pMMAPBufPtr[MAX_I2S_PAGE*2];
++ char* pMMAPTxBufPtr[MAX_I2S_PAGE];
++ char* pMMAPRxBufPtr[MAX_I2S_PAGE];
++
++ union {
++ u16* pPage0TxBuf16Ptr;
++ u8* pPage0TxBuf8ptr;
++ };
++ union {
++ u16* pPage1TxBuf16Ptr;
++ u8* pPage1TxBuf8ptr;
++ };
++
++ union {
++ u16* pPage0RxBuf16Ptr;
++ u8* pPage0RxBuf8ptr;
++ };
++ union {
++ u16* pPage1RxBuf16Ptr;
++ u8* pPage1RxBuf8ptr;
++ };
++
++}i2s_config_type;
++
++
++void i2s_gen_test_pattern(void);
++int i2s_mem_unmap(i2s_config_type* ptri2s_config);
++int i2s_param_init(i2s_config_type* ptri2s_config);
++int i2s_txbuf_alloc(i2s_config_type* ptri2s_config);
++int i2s_rxbuf_alloc(i2s_config_type* ptri2s_config);
++int i2s_txPagebuf_alloc(i2s_config_type* ptri2s_config);
++int i2s_rxPagebuf_alloc(i2s_config_type* ptri2s_config);
++int i2s_txbuf_free(i2s_config_type* ptri2s_config);
++int i2s_rxbuf_free(i2s_config_type* ptri2s_config);
++int i2s_txPagebuf_free(i2s_config_type* ptri2s_config);
++int i2s_rxPagebuf_free(i2s_config_type* ptri2s_config);
++int i2s_reset_tx_param(i2s_config_type* ptri2s_config);
++int i2s_reset_rx_param(i2s_config_type* ptri2s_config);
++int i2s_tx_config(i2s_config_type* ptri2s_config);
++int i2s_rx_config(i2s_config_type* ptri2s_config);
++int i2s_tx_enable(i2s_config_type* ptri2s_config);
++int i2s_tx_disable(i2s_config_type* ptri2s_config);
++int i2s_rx_enable(i2s_config_type* ptri2s_config);
++int i2s_rx_disable(i2s_config_type* ptri2s_config);
++int i2s_codec_enable(i2s_config_type* ptri2s_config);
++int i2s_codec_disable(i2s_config_type* ptri2s_config);
++int i2s_clock_enable(i2s_config_type* ptri2s_config);
++int i2s_clock_disable(i2s_config_type* ptri2s_config);
++int i2s_reset_config(i2s_config_type* ptri2s_config);
++int i2s_refclk_disable(void);
++int i2s_refclk_gpio_out_config(void);
++int i2s_refclk_gpio_in_config(void);
++int i2s_share_pin_config(i2s_config_type* ptri2s_config);
++int i2s_share_pin_mt7623(i2s_config_type* ptri2s_config);
++int i2s_master_clock_gpio_out_mt7623(void);
++int i2s_slave_clock_gpio_in_mt7623(void);
++int i2s_ws_config(i2s_config_type* ptri2s_config, unsigned long index);
++int i2s_mode_config(u32 slave_en);
++int i2s_codec_frequency_config(i2s_config_type* ptri2s_config, unsigned long index);
++void i2s_tx_end_sleep_on(i2s_config_type* ptri2s_config);
++void i2s_rx_end_sleep_on(i2s_config_type* ptri2s_config);
++
++#if defined(CONFIG_I2S_MCLK_12MHZ)
++int i2s_refclk_12m_enable(void);
++#endif
++#if defined(CONFIG_I2S_MCLK_12P288MHZ)
++int i2s_refclk_12p288m_enable(void);
++#endif
++
++#if defined(MT7621_ASIC_BOARD)
++int i2s_pll_config_mt7621(unsigned long index);
++int i2s_pll_refclk_set(void);
++#endif
++#if defined(MT7623_ASIC_BOARD)
++int i2s_pll_config_mt7623(unsigned long index);
++#endif
++#if defined(MT7628_ASIC_BOARD) || defined(CONFIG_ARCH_MT7623)
++int i2s_driving_strength_adjust(void);
++#endif
++#if defined(I2S_STATISTIC)
++void i2s_int_status(u32 dma_ch);
++#endif
++void i2s_dma_tx_handler(u32 dma_ch);
++void i2s_dma_rx_handler(u32 dma_ch);
++void i2s_dma_unmask_handler(u32 dma_ch);
++void i2s_dma_mask_handler(u32 dma_ch);
++void i2s_dma_tx_init(i2s_config_type* ptri2s_config);
++void i2s_dma_rx_init(i2s_config_type* ptri2s_config);
++void i2s_tx_task(unsigned long pData);
++void i2s_rx_task(unsigned long pData);
++void i2s_dma_tx_unmask_handler(u32 dma_ch);
++void i2s_dma_rx_unmask_handler(u32 dma_ch);
++int i2s_dma_tx_transf_data(i2s_config_type* ptri2s_config, u32 dma_ch);
++int i2s_dma_tx_transf_zero(i2s_config_type* ptri2s_config, u32 dma_ch);
++int i2s_dma_rx_transf_data(i2s_config_type* ptri2s_config, u32 dma_ch);
++int i2s_dma_rx_transf_zero(i2s_config_type* ptri2s_config, u32 dma_ch);
++void i2s_dma_tx_end_handle(i2s_config_type* ptri2s_config);
++int i2s_dma_tx_soft_stop(i2s_config_type* ptri2s_config, u32 dma_ch);
++int i2s_dma_rx_soft_stop(i2s_config_type* ptri2s_config, u32 dma_ch);
++
++int i2s_page_prepare(i2s_config_type* ptri2s_config,int dir);
++int i2s_page_release(i2s_config_type* ptri2s_config,int dir);
++int gdma_En_Switch(i2s_config_type* ptri2s_config,int dir,int enabled);
++int i2s_startup(void);
++int i2s_audio_exchange(i2s_config_type* ptri2s_config,int dir,unsigned long arg);
++void gdma_unmask_handler(u32 dma_ch);
++char* i2s_memPool_Alloc(i2s_config_type* ptri2s_config,int dir);
++void i2s_memPool_free(i2s_config_type* ptri2s_config,int dir);
++u32 i2s_mmap_phys_addr(i2s_config_type* ptri2s_config);
++
++#if !defined(CONFIG_I2S_TXRX)
++#define GdmaI2sRx //GdmaI2sRx
++#endif
++
++#define RALINK_I2S_VERSION "1.0"
++#define I2SDRV_DEVNAME "i2s0"
++
++#endif /* __RALINK_I2S_H_ */
++
+diff --git a/sound/soc/mtk/i2s_debug.c b/sound/soc/mtk/i2s_debug.c
+new file mode 100644
+index 0000000..9f61b14
+--- /dev/null
++++ b/sound/soc/mtk/i2s_debug.c
+@@ -0,0 +1,698 @@
++#include <linux/init.h>
++#include <linux/version.h>
++#include <linux/module.h>
++#include <linux/kernel.h> /* printk() */
++#include "i2s_ctrl.h"
++#include <linux/delay.h>
++#include <linux/jiffies.h>
++#include <linux/random.h>
++#include <linux/slab.h>
++#include <asm/uaccess.h> /* copy_from/to_user */
++
++#if defined(CONFIG_SND_RALINK_SOC)
++#include <sound/soc/mtk/mtk_audio_device.h>
++#endif
++
++#if defined(CONFIG_I2S_WM8750)
++#include "../codec/i2c_wm8750.h"
++#endif
++#if defined(CONFIG_I2S_WM8751)
++#include "../codec/i2c_wm8751.h"
++#endif
++#if defined(CONFIG_I2S_WM8960)
++#include "i2c_wm8960.h"
++#endif
++
++
++//#define INTERNAL_LOOPBACK_DEBUG
++
++extern unsigned long i2s_codec_12p288Mhz[11];
++extern unsigned long i2s_codec_12Mhz[11];
++#if defined(CONFIG_RALINK_MT7628) || defined(CONFIG_ARCH_MT7623)
++extern unsigned long i2s_inclk_int_16bit[13];
++extern unsigned long i2s_inclk_comp_16bit[13];
++extern unsigned long i2s_inclk_int_24bit[13];
++extern unsigned long i2s_inclk_comp_24bit[13];
++#else
++extern unsigned long i2s_inclk_int[11];
++extern unsigned long i2s_inclk_comp[11];
++#endif
++extern int i2s_pll_config_mt7621(unsigned long index);
++extern int i2s_pll_config_mt7623(unsigned long index);
++
++#if defined(CONFIG_I2S_WM8960) || defined(CONFIG_I2S_WM8750) || defined(CONFIG_I2S_WM8751)
++extern void audiohw_loopback(int fsel);
++extern void audiohw_bypass(void);
++extern int audiohw_set_lineout_vol(int Aout, int vol_l, int vol_r);
++extern int audiohw_set_linein_vol(int vol_l, int vol_r);
++#endif
++
++#if defined(CONFIG_I2S_WM8960)
++extern void audiohw_codec_exlbk(void);
++#endif
++
++unsigned long txbuffer[512] = {
++ 0x01020304, 0x05060708, 0x090a0b0c, 0x0d0e0f10, 0x11121314, 0x15161718, 0x191a1b1c, 0x1d1e1f20,
++ 0x21222324, 0x25262728, 0x292a2b2c, 0x2d2e2f30, 0x31323334, 0x35363738, 0x393a3b3c, 0x3d3e3f40,
++ 0x41424344, 0x45464748, 0x494a4b4c, 0x4d4e4f50, 0x51525354, 0x55565758, 0x595a5b5c, 0x5d5e5f60,
++ 0x61626364, 0x65666768, 0x696a6b6c, 0x6d6e6f70, 0x71727374, 0x75767778, 0x797a7b7c, 0x7d7e7f80,
++ 0x81828384, 0x85868788, 0x898a8b8c, 0x8d8e8f90, 0x91929394, 0x95969798, 0x999a9b9c, 0x9d9e9fa0,
++ 0xa1a2a3a4, 0xa5a6a7a8, 0xa9aaabac, 0xadaeafb0, 0xb1b2b3b4, 0xb5b6b7b8, 0xb9babbbc, 0xbdbebfc0,
++ 0xc1c2c3c4, 0xc5c6c7c8, 0xc9cacbcc, 0xcdcecfd0, 0xd1d2d3d4, 0xd5d6d7d8, 0xd9dadbdc, 0xdddedfe0,
++ 0xe1e2e3e4, 0xe5e6e7e8, 0xe9eaebec, 0xedeeeff0, 0xf1f2f3f4, 0xf5f6f7f8, 0xf9fafbfc, 0xfdfeff00, //round 1
++0x01020304, 0x05060708, 0x090a0b0c, 0x0d0e0f10, 0x11121314, 0x15161718, 0x191a1b1c, 0x1d1e1f20,
++ 0x21222324, 0x25262728, 0x292a2b2c, 0x2d2e2f30, 0x31323334, 0x35363738, 0x393a3b3c, 0x3d3e3f40,
++ 0x41424344, 0x45464748, 0x494a4b4c, 0x4d4e4f50, 0x51525354, 0x55565758, 0x595a5b5c, 0x5d5e5f60,
++ 0x61626364, 0x65666768, 0x696a6b6c, 0x6d6e6f70, 0x71727374, 0x75767778, 0x797a7b7c, 0x7d7e7f80,
++ 0x81828384, 0x85868788, 0x898a8b8c, 0x8d8e8f90, 0x91929394, 0x95969798, 0x999a9b9c, 0x9d9e9fa0,
++ 0xa1a2a3a4, 0xa5a6a7a8, 0xa9aaabac, 0xadaeafb0, 0xb1b2b3b4, 0xb5b6b7b8, 0xb9babbbc, 0xbdbebfc0,
++ 0xc1c2c3c4, 0xc5c6c7c8, 0xc9cacbcc, 0xcdcecfd0, 0xd1d2d3d4, 0xd5d6d7d8, 0xd9dadbdc, 0xdddedfe0,
++ 0xe1e2e3e4, 0xe5e6e7e8, 0xe9eaebec, 0xedeeeff0, 0xf1f2f3f4, 0xf5f6f7f8, 0xf9fafbfc, 0xfdfeff00, //round 2
++0x01020304, 0x05060708, 0x090a0b0c, 0x0d0e0f10, 0x11121314, 0x15161718, 0x191a1b1c, 0x1d1e1f20,
++ 0x21222324, 0x25262728, 0x292a2b2c, 0x2d2e2f30, 0x31323334, 0x35363738, 0x393a3b3c, 0x3d3e3f40,
++ 0x41424344, 0x45464748, 0x494a4b4c, 0x4d4e4f50, 0x51525354, 0x55565758, 0x595a5b5c, 0x5d5e5f60,
++ 0x61626364, 0x65666768, 0x696a6b6c, 0x6d6e6f70, 0x71727374, 0x75767778, 0x797a7b7c, 0x7d7e7f80,
++ 0x81828384, 0x85868788, 0x898a8b8c, 0x8d8e8f90, 0x91929394, 0x95969798, 0x999a9b9c, 0x9d9e9fa0,
++ 0xa1a2a3a4, 0xa5a6a7a8, 0xa9aaabac, 0xadaeafb0, 0xb1b2b3b4, 0xb5b6b7b8, 0xb9babbbc, 0xbdbebfc0,
++ 0xc1c2c3c4, 0xc5c6c7c8, 0xc9cacbcc, 0xcdcecfd0, 0xd1d2d3d4, 0xd5d6d7d8, 0xd9dadbdc, 0xdddedfe0,
++ 0xe1e2e3e4, 0xe5e6e7e8, 0xe9eaebec, 0xedeeeff0, 0xf1f2f3f4, 0xf5f6f7f8, 0xf9fafbfc, 0xfdfeff00, //round 3
++0x01020304, 0x05060708, 0x090a0b0c, 0x0d0e0f10, 0x11121314, 0x15161718, 0x191a1b1c, 0x1d1e1f20,
++ 0x21222324, 0x25262728, 0x292a2b2c, 0x2d2e2f30, 0x31323334, 0x35363738, 0x393a3b3c, 0x3d3e3f40,
++ 0x41424344, 0x45464748, 0x494a4b4c, 0x4d4e4f50, 0x51525354, 0x55565758, 0x595a5b5c, 0x5d5e5f60,
++ 0x61626364, 0x65666768, 0x696a6b6c, 0x6d6e6f70, 0x71727374, 0x75767778, 0x797a7b7c, 0x7d7e7f80,
++ 0x81828384, 0x85868788, 0x898a8b8c, 0x8d8e8f90, 0x91929394, 0x95969798, 0x999a9b9c, 0x9d9e9fa0,
++ 0xa1a2a3a4, 0xa5a6a7a8, 0xa9aaabac, 0xadaeafb0, 0xb1b2b3b4, 0xb5b6b7b8, 0xb9babbbc, 0xbdbebfc0,
++ 0xc1c2c3c4, 0xc5c6c7c8, 0xc9cacbcc, 0xcdcecfd0, 0xd1d2d3d4, 0xd5d6d7d8, 0xd9dadbdc, 0xdddedfe0,
++ 0xe1e2e3e4, 0xe5e6e7e8, 0xe9eaebec, 0xedeeeff0, 0xf1f2f3f4, 0xf5f6f7f8, 0xf9fafbfc, 0xfdfeff00, //round 4
++0x01020304, 0x05060708, 0x090a0b0c, 0x0d0e0f10, 0x11121314, 0x15161718, 0x191a1b1c, 0x1d1e1f20,
++ 0x21222324, 0x25262728, 0x292a2b2c, 0x2d2e2f30, 0x31323334, 0x35363738, 0x393a3b3c, 0x3d3e3f40,
++ 0x41424344, 0x45464748, 0x494a4b4c, 0x4d4e4f50, 0x51525354, 0x55565758, 0x595a5b5c, 0x5d5e5f60,
++ 0x61626364, 0x65666768, 0x696a6b6c, 0x6d6e6f70, 0x71727374, 0x75767778, 0x797a7b7c, 0x7d7e7f80,
++ 0x81828384, 0x85868788, 0x898a8b8c, 0x8d8e8f90, 0x91929394, 0x95969798, 0x999a9b9c, 0x9d9e9fa0,
++ 0xa1a2a3a4, 0xa5a6a7a8, 0xa9aaabac, 0xadaeafb0, 0xb1b2b3b4, 0xb5b6b7b8, 0xb9babbbc, 0xbdbebfc0,
++ 0xc1c2c3c4, 0xc5c6c7c8, 0xc9cacbcc, 0xcdcecfd0, 0xd1d2d3d4, 0xd5d6d7d8, 0xd9dadbdc, 0xdddedfe0,
++ 0xe1e2e3e4, 0xe5e6e7e8, 0xe9eaebec, 0xedeeeff0, 0xf1f2f3f4, 0xf5f6f7f8, 0xf9fafbfc, 0xfdfeff00, //round 5
++0x01020304, 0x05060708, 0x090a0b0c, 0x0d0e0f10, 0x11121314, 0x15161718, 0x191a1b1c, 0x1d1e1f20,
++ 0x21222324, 0x25262728, 0x292a2b2c, 0x2d2e2f30, 0x31323334, 0x35363738, 0x393a3b3c, 0x3d3e3f40,
++ 0x41424344, 0x45464748, 0x494a4b4c, 0x4d4e4f50, 0x51525354, 0x55565758, 0x595a5b5c, 0x5d5e5f60,
++ 0x61626364, 0x65666768, 0x696a6b6c, 0x6d6e6f70, 0x71727374, 0x75767778, 0x797a7b7c, 0x7d7e7f80,
++ 0x81828384, 0x85868788, 0x898a8b8c, 0x8d8e8f90, 0x91929394, 0x95969798, 0x999a9b9c, 0x9d9e9fa0,
++ 0xa1a2a3a4, 0xa5a6a7a8, 0xa9aaabac, 0xadaeafb0, 0xb1b2b3b4, 0xb5b6b7b8, 0xb9babbbc, 0xbdbebfc0,
++ 0xc1c2c3c4, 0xc5c6c7c8, 0xc9cacbcc, 0xcdcecfd0, 0xd1d2d3d4, 0xd5d6d7d8, 0xd9dadbdc, 0xdddedfe0,
++ 0xe1e2e3e4, 0xe5e6e7e8, 0xe9eaebec, 0xedeeeff0, 0xf1f2f3f4, 0xf5f6f7f8, 0xf9fafbfc, 0xfdfeff00, //round 6
++0x01020304, 0x05060708, 0x090a0b0c, 0x0d0e0f10, 0x11121314, 0x15161718, 0x191a1b1c, 0x1d1e1f20,
++ 0x21222324, 0x25262728, 0x292a2b2c, 0x2d2e2f30, 0x31323334, 0x35363738, 0x393a3b3c, 0x3d3e3f40,
++ 0x41424344, 0x45464748, 0x494a4b4c, 0x4d4e4f50, 0x51525354, 0x55565758, 0x595a5b5c, 0x5d5e5f60,
++ 0x61626364, 0x65666768, 0x696a6b6c, 0x6d6e6f70, 0x71727374, 0x75767778, 0x797a7b7c, 0x7d7e7f80,
++ 0x81828384, 0x85868788, 0x898a8b8c, 0x8d8e8f90, 0x91929394, 0x95969798, 0x999a9b9c, 0x9d9e9fa0,
++ 0xa1a2a3a4, 0xa5a6a7a8, 0xa9aaabac, 0xadaeafb0, 0xb1b2b3b4, 0xb5b6b7b8, 0xb9babbbc, 0xbdbebfc0,
++ 0xc1c2c3c4, 0xc5c6c7c8, 0xc9cacbcc, 0xcdcecfd0, 0xd1d2d3d4, 0xd5d6d7d8, 0xd9dadbdc, 0xdddedfe0,
++ 0xe1e2e3e4, 0xe5e6e7e8, 0xe9eaebec, 0xedeeeff0, 0xf1f2f3f4, 0xf5f6f7f8, 0xf9fafbfc, 0xfdfeff00, //round 7
++0x01020304, 0x05060708, 0x090a0b0c, 0x0d0e0f10, 0x11121314, 0x15161718, 0x191a1b1c, 0x1d1e1f20,
++ 0x21222324, 0x25262728, 0x292a2b2c, 0x2d2e2f30, 0x31323334, 0x35363738, 0x393a3b3c, 0x3d3e3f40,
++ 0x41424344, 0x45464748, 0x494a4b4c, 0x4d4e4f50, 0x51525354, 0x55565758, 0x595a5b5c, 0x5d5e5f60,
++ 0x61626364, 0x65666768, 0x696a6b6c, 0x6d6e6f70, 0x71727374, 0x75767778, 0x797a7b7c, 0x7d7e7f80,
++ 0x81828384, 0x85868788, 0x898a8b8c, 0x8d8e8f90, 0x91929394, 0x95969798, 0x999a9b9c, 0x9d9e9fa0,
++ 0xa1a2a3a4, 0xa5a6a7a8, 0xa9aaabac, 0xadaeafb0, 0xb1b2b3b4, 0xb5b6b7b8, 0xb9babbbc, 0xbdbebfc0,
++ 0xc1c2c3c4, 0xc5c6c7c8, 0xc9cacbcc, 0xcdcecfd0, 0xd1d2d3d4, 0xd5d6d7d8, 0xd9dadbdc, 0xdddedfe0,
++ 0xe1e2e3e4, 0xe5e6e7e8, 0xe9eaebec, 0xedeeeff0, 0xf1f2f3f4, 0xf5f6f7f8, 0xf9fafbfc, 0xfdfeff00 //round 8
++ };
++
++int i2s_debug_cmd(unsigned int cmd, unsigned long arg)
++{
++ unsigned long data, index;
++ unsigned long *pTable;
++ int i;
++
++ switch(cmd)
++ {
++ case I2S_DEBUG_CLKGEN:
++ MSG("I2S_DEBUG_CLKGEN\n");
++#if defined(CONFIG_RALINK_RT3052)
++ *(volatile unsigned long*)(0xB0000060) = 0x00000016;
++ *(volatile unsigned long*)(0xB0000030) = 0x00009E00;
++ *(volatile unsigned long*)(0xB0000A00) = 0xC0000040;
++#elif defined(CONFIG_RALINK_RT3350)
++ *(volatile unsigned long*)(0xB0000060) = 0x00000018;
++ *(volatile unsigned long*)(0xB000002C) = 0x00000100;
++ *(volatile unsigned long*)(0xB0000030) = 0x00009E00;
++ *(volatile unsigned long*)(0xB0000A00) = 0xC0000040;
++#elif defined(CONFIG_RALINK_RT3883)
++ *(volatile unsigned long*)(0xB0000060) = 0x00000018;
++ *(volatile unsigned long*)(0xB000002C) = 0x00003000;
++ *(volatile unsigned long*)(0xB0000A00) = 0xC1104040;
++ *(volatile unsigned long*)(0xB0000A24) = 0x00000027;
++ *(volatile unsigned long*)(0xB0000A20) = 0x80000020;
++#elif (defined(CONFIG_RALINK_RT3352)||defined(CONFIG_RALINK_RT5350)) || defined (CONFIG_RALINK_RT6855)
++ *(volatile unsigned long*)(0xB0000060) = 0x00000018;
++ *(volatile unsigned long*)(0xB000002C) = 0x00000300;
++ *(volatile unsigned long*)(0xB0000A00) = 0xC1104040;
++ *(volatile unsigned long*)(0xB0000A24) = 0x00000027;
++ *(volatile unsigned long*)(0xB0000A20) = 0x80000020;
++#elif defined(CONFIG_RALINK_RT6855A)
++ *(volatile unsigned long*)(RALINK_SYSCTL_BASE+0x860) = 0x00008080;
++ *(volatile unsigned long*)(RALINK_SYSCTL_BASE+0x82C) = 0x00000300;
++ *(volatile unsigned long*)(RALINK_I2S_BASE+0x00) = 0xC1104040;
++ *(volatile unsigned long*)(RALINK_I2S_BASE+0x24) = 0x00000027;
++ *(volatile unsigned long*)(RALINK_I2S_BASE+0x20) = 0x80000020;
++#else
++//#error "I2S debug mode not support this Chip"
++#endif
++ break;
++ case I2S_DEBUG_INLBK:
++ MSG("I2S_DEBUG_INLBK\n");
++#if defined(CONFIG_RALINK_MT7621)
++ switch(96000)
++ {
++ case 8000:
++ index = 0;
++ break;
++ case 11025:
++ index = 1;
++ break;
++ case 12000:
++ index = 2;
++ break;
++ case 16000:
++ index = 3;
++ break;
++ case 22050:
++ index = 4;
++ break;
++ case 24000:
++ index = 5;
++ break;
++ case 32000:
++ index = 6;
++ break;
++ case 44100:
++ index = 7;
++ break;
++ case 48000:
++ index = 8;
++ break;
++ case 88200:
++ index = 9;
++ break;
++ case 96000:
++ index = 10;
++ break;
++ case 192000:
++ index = 11;
++ break;
++ default:
++ index = 7;
++ }
++ i2s_pll_config_mt7621(index);
++#elif defined(CONFIG_ARCH_MT7623)
++ i2s_pll_config_mt7623(11);
++#endif
++
++
++#if defined(CONFIG_RALINK_RT3052)
++ break;
++#endif
++#if defined(CONFIG_RALINK_RT6855A)
++ *(volatile unsigned long*)(RALINK_SYSCTL_BASE+0x834) |= 0x00020000;
++ *(volatile unsigned long*)(RALINK_SYSCTL_BASE+0x834) &= 0xFFFDFFFF;
++ *(volatile unsigned long*)(RALINK_I2S_BASE+0x0) &= 0x7FFFFFFF; //Rest I2S to default vaule
++ *(volatile unsigned long*)(RALINK_SYSCTL_BASE+0x860) |= 0x00008080;
++ *(volatile unsigned long*)(RALINK_SYSCTL_BASE+0x82C) = 0x00000300;
++#elif defined(CONFIG_RALINK_MT7621)
++ *(volatile unsigned long*)(RALINK_SYSCTL_BASE+0x34) |= 0x00020000;
++ *(volatile unsigned long*)(RALINK_SYSCTL_BASE+0x34) &= 0xFFFDFFFF;
++ *(volatile unsigned long*)(RALINK_I2S_BASE+0x0) &= 0x7FFFFFFF; //Rest I2S to default vaule
++ *(volatile unsigned long*)(RALINK_SYSCTL_BASE+0x60) = 0x00000010; //GPIO purpose selection
++#elif defined(CONFIG_RALINK_MT7628)
++ *(volatile unsigned long*)(RALINK_SYSCTL_BASE+0x34) |= 0x00020000;
++ *(volatile unsigned long*)(RALINK_SYSCTL_BASE+0x34) &= 0xFFFDFFFF;
++ *(volatile unsigned long*)(RALINK_I2S_BASE+0x0) &= 0x7FFFFFFF; //Rest I2S to default vaule
++ *(volatile unsigned long*)(RALINK_SYSCTL_BASE+0x60) &= ~((0x3)<<6); //GPIO purpose selection /*FIXME*/
++#elif defined(CONFIG_ARCH_MT7623)
++ *(volatile unsigned long*)(0xFB000034) |= 0x00020000;
++ *(volatile unsigned long*)(0xFB000034) &= 0xFFFDFFFF;
++ *(volatile unsigned long*)(ETHDMASYS_I2S_BASE+0x0) &= 0x7FFFFFFF; //Rest I2S to default vaule
++
++ *(volatile unsigned long*)(0xF0005840) &= ~((0x7)<<12);
++ *(volatile unsigned long*)(0xF0005840) |= ((0x6)<<12);
++ *(volatile unsigned long*)(0xF0005840) &= ~((0x7)<<9);
++ *(volatile unsigned long*)(0xF0005840) |= ((0x6)<<9);
++ *(volatile unsigned long*)(0xF0005040) |= ((0x1)<<10);
++ *(volatile unsigned long*)(0xF0005040) |= ((0x1)<<9);
++
++ *(volatile unsigned long*)(0xF00057F0) &= ~((0x7)<<12);
++ *(volatile unsigned long*)(0xF00057F0) |= ((0x6)<<12);
++ *(volatile unsigned long*)(0xF0005030) |= ((0x1)<<1);
++
++ *(volatile unsigned long*)(0xF0005840) &= ~((0x7)<<6);
++ *(volatile unsigned long*)(0xF0005840) |= ((0x6)<<6);
++ *(volatile unsigned long*)(0xF0005040) &= ~((0x1)<<8);
++
++ *(volatile unsigned long*)(0xF00058F0) &= ~((0x7)<<3);
++ *(volatile unsigned long*)(0xF00058F0) |= ((0x6)<<3);
++ *(volatile unsigned long*)(0xF0005070) |= ((0x1)<<14);
++
++
++#else
++ *(volatile unsigned long*)(0xB0000034) |= 0x00020000;
++ *(volatile unsigned long*)(0xB0000034) &= 0xFFFDFFFF;
++ *(volatile unsigned long*)(0xB0000A00) &= 0x7FFFFFFF; //Rest I2S to default vaule
++ *(volatile unsigned long*)(0xB0000060) = 0x00000018;
++
++#if defined(CONFIG_RALINK_RT3883)
++ *(volatile unsigned long*)(0xB000002C) = 0x00003000;
++#elif defined(CONFIG_ARCH_MT7623)
++
++#else
++ *(volatile unsigned long*)(0xB000002C) = 0x00000300;
++#endif
++#endif
++#if defined(CONFIG_RALINK_MT7621)
++ *(volatile unsigned long*)(RALINK_I2S_BASE+0x18) = 0x80000000;
++ *(volatile unsigned long*)(RALINK_I2S_BASE+0x00) = 0xc1104040;
++
++ pTable = i2s_inclk_int;
++ data = pTable[index];
++ //*(volatile unsigned long*)(RALINK_I2S_BASE+0x24) = data;
++ i2s_outw(RALINK_I2S_BASE+0x24, data);
++
++ pTable = i2s_inclk_comp;
++ data = pTable[index];
++ //*(volatile unsigned long*)(RALINK_I2S_BASE+0x20) = data;
++ i2s_outw(RALINK_I2S_BASE+0x20, (data|0x80000000));
++#elif defined(CONFIG_RALINK_MT7628)
++ index =11; /* SR: 192k */
++ *(volatile unsigned long*)(RALINK_I2S_BASE+0x18) = 0x80000000;
++ *(volatile unsigned long*)(RALINK_I2S_BASE+0x00) = 0xc1104040;
++
++ pTable = i2s_inclk_int_16bit;
++ //pTable = i2s_inclk_int_24bit;
++ data = pTable[index];
++ //*(volatile unsigned long*)(RALINK_I2S_BASE+0x24) = data;
++ i2s_outw(RALINK_I2S_BASE+0x24, data);
++
++ pTable = i2s_inclk_comp_16bit;
++ //pTable = i2s_inclk_comp_24bit;
++ data = pTable[index];
++ //*(volatile unsigned long*)(RALINK_I2S_BASE+0x20) = data;
++ i2s_outw(RALINK_I2S_BASE+0x20, (data|0x80000000));
++ mdelay(5);
++#elif defined(CONFIG_ARCH_MT7623)
++ index = 11;
++ *(volatile unsigned long*)(I2S_I2SCFG1) = 0x80000000;
++ *(volatile unsigned long*)(I2S_I2SCFG) = 0xE1104040;
++ *(volatile unsigned long*)(ETHDMASYS_SYSCTL_BASE+0x30) |= 0x00020000;
++ *(volatile unsigned long*)(ETHDMASYS_SYSCTL_BASE+0x2c) |= 0x00000080;
++
++ pTable = i2s_inclk_int_16bit;
++ //pTable = i2s_inclk_int_24bit;
++ data = pTable[index];
++ i2s_outw(I2S_DIVINT_CFG, data);
++
++ pTable = i2s_inclk_comp_16bit;
++ //pTable = i2s_inclk_comp_24bit;
++ data = pTable[index];
++ i2s_outw(I2S_DIVCOMP_CFG, (data|0x80000000));
++ mdelay(5);
++#else
++ *(volatile unsigned long*)(RALINK_I2S_BASE+0x18) = 0x80000000;
++ *(volatile unsigned long*)(RALINK_I2S_BASE+0x00) = 0xC1104040;
++ *(volatile unsigned long*)(RALINK_I2S_BASE+0x24) = 0x00000006;
++ *(volatile unsigned long*)(RALINK_I2S_BASE+0x20) = 0x80000105;
++#endif
++ {
++ int count = 0;
++ int k=0;
++ int enable_cnt=0;
++ unsigned long param[4];
++ unsigned long data;
++ //unsigned long data_tmp;
++ unsigned long ff_status;
++ //unsigned long* txbuffer;
++#if 0
++ int j=0;
++ int temp = 0;
++#endif
++#if defined (INTERNAL_LOOPBACK_DEBUG)
++ int count2 = 0;
++#endif
++ memset(param, 0, 4*sizeof(unsigned long) );
++ copy_from_user(param, (unsigned long*)arg, sizeof(long)*2);
++#if 0
++ txbuffer = (unsigned long*)kcalloc(param[0], sizeof(unsigned long), GFP_KERNEL);
++ if(txbuffer == NULL)
++ return -1;
++#endif
++
++ //ff_status = *(volatile unsigned long*)(RALINK_I2S_BASE+0x0C);
++ ff_status = *(volatile unsigned long*)(I2S_FF_STATUS);
++ printk("ff status=[0x%08X]\n",(u32)ff_status);
++
++#if 0
++ for(i = 0; i < param[0]; i++)
++ {
++ if (i==0)
++ {
++ txbuffer[i] = 0x555A555A;
++ printk("%d: 0x%8lx\n", i, txbuffer[i]);
++ }
++ else
++ {
++ #if LINUX_VERSION_CODE < KERNEL_VERSION(3,10,14)
++ srandom32(jiffies);
++ txbuffer[i] = random32()%(0x555A555A)+1;
++ //printk("%d: 0x%8x\n", i, txbuffer[i]);
++ #else
++ //TODO:do we need to implement random32()
++ txbuffer[i] = 0x01010101;
++ #endif
++ }
++ }
++#endif
++
++ for( i = 0 ; i < param[0] ; i ++ )
++ {
++ ff_status = *(volatile unsigned long*)(I2S_FF_STATUS);
++ #if defined(CONFIG_RALINK_MT7628) || defined(CONFIG_ARCH_MT7623)
++ if((ff_status&0xFF) > 0)
++ #else
++ if((ff_status&0x0F) > 0)
++ #endif
++ {
++ *(volatile unsigned long*)(I2S_TX_FIFO_WREG) = txbuffer[i];
++ mdelay(1);
++ }
++ else
++ {
++ mdelay(1);
++ printk("[%d]NO TX FREE FIFO ST=[0x%08X]\n", i, (u32)ff_status);
++ continue;
++ }
++
++ //if(i >= 16)
++ {
++
++ ff_status = *(volatile unsigned long*)(I2S_FF_STATUS);
++ #if defined(CONFIG_RALINK_MT7628)
++ if(((ff_status>>8)&0xFF) > 0)
++ #else
++ if(((ff_status>>4)&0x0F) > 0)
++ #endif
++ {
++ data = *(volatile unsigned long*)(I2S_RX_FIFO_RREG);
++ //data_tmp = *(volatile unsigned long*)(I2S_RX_FIFO_RREG);
++ //MSG("[0x%08X] vs [0x%08X]\n", (u32)data, (u32)data_tmp);
++ }
++ else
++ {
++ printk("*[%d]NO RX FREE FIFO ST=[0x%08X]\n", i, (u32)ff_status);
++ continue;
++ }
++
++ if (data == txbuffer[0])
++ {
++ k = i;
++ enable_cnt = 1;
++ }
++ if (enable_cnt==1)
++ {
++ if(data!= txbuffer[i-k])
++ {
++ MSG("[%d][0x%08X] vs [0x%08X]\n", (i-k), (u32)data, (u32)txbuffer[i-k]);
++ }
++ else
++ {
++ //MSG("**[%d][0x%08X] vs [0x%08X]\n" ,(i-k), (u32)data , (u32)txbuffer[i-k]);
++ count++;
++ data=0;
++ }
++ }
++
++ }
++ }
++#if 0
++ temp = i-k;
++ for (j=0; j<k; j++)
++ {
++
++ //ff_status = *(volatile unsigned long*)(RALINK_I2S_BASE+0x0C);
++ ff_status = *(volatile unsigned long*)(I2S_FF_STATUS);
++ #if defined(CONFIG_RALINK_MT7628) || defined(CONFIG_ARCH_MT7623)
++ if(((ff_status>>8)&0xFF) > 0)
++ #else
++ if(((ff_status>>4)&0x0F) > 0)
++ #endif
++ {
++ //data = *(volatile unsigned long*)(RALINK_I2S_BASE+0x14);
++ data = *(volatile unsigned long*)(I2S_RX_FIFO_RREG);
++ }
++ else
++ {
++ printk("*NO RX FREE FIFO ST=[0x%08X]\n", (u32)ff_status);
++ continue;
++ }
++
++ if(data!= txbuffer[temp+j])
++ {
++ MSG("[%d][0x%08X] vs [0x%08X]\n", (temp+j), (u32)data, (u32)txbuffer[temp+j]);
++ }
++ else
++ {
++ //MSG("&&[%d][0x%08X] vs [0x%08X]\n" ,(temp+j), (u32)data , (u32)txbuffer[temp+j]);
++ count++;
++ data=0;
++ }
++ if ((temp+j)==128)
++ {
++ //ff_status = *(volatile unsigned long*)(RALINK_I2S_BASE+0x0C);
++ ff_status = *(volatile unsigned long*)(I2S_FF_STATUS);
++ //printk("[%d]FIFO ST=[0x%08X]\n", (temp+j), (u32)ff_status);
++ }
++ }
++#endif
++
++#if defined (INTERNAL_LOOPBACK_DEBUG)
++ for( i = 0 ; i < param[0] ; i ++ )
++ {
++ //ff_status = *(volatile unsigned long*)(RALINK_I2S_BASE+0x0C);
++ ff_status = *(volatile unsigned long*)(I2S_FF_STATUS);
++ #if defined(CONFIG_RALINK_MT7628)|| defined(CONFIG_ARCH_MT7623)
++ if((ff_status&0xFF) > 0)
++ #else
++ if((ff_status&0x0F) > 0)
++ #endif
++ {
++ //*(volatile unsigned long*)(RALINK_I2S_BASE+0x10) = txbuffer[i];
++ *(volatile unsigned long*)(I2S_TX_FIFO_WREG) = txbuffer[i];
++ mdelay(1);
++ }
++ else
++ {
++ mdelay(1);
++ printk("[%d]NO TX FREE FIFO ST=[0x%08X]\n", i, (u32)ff_status);
++ continue;
++ }
++
++ //if(i >= 16)
++ {
++
++ //ff_status = *(volatile unsigned long*)(RALINK_I2S_BASE+0x0C);
++ ff_status = *(volatile unsigned long*)(I2S_FF_STATUS);
++ #if defined(CONFIG_RALINK_MT7628)|| defined(CONFIG_ARCH_MT7623)
++ if(((ff_status>>8)&0xFF) > 0)
++ #else
++ if(((ff_status>>4)&0x0F) > 0)
++ #endif
++ {
++ //data = *(volatile unsigned long*)(RALINK_I2S_BASE+0x14);
++ data = *(volatile unsigned long*)(I2S_RX_FIFO_RREG);
++ }
++ else
++ {
++ printk("*[%d]NO RX FREE FIFO ST=[0x%08X]\n", i, (u32)ff_status);
++ continue;
++ }
++
++ {
++ if(data!= txbuffer[i])
++ {
++ MSG("[%d][0x%08X] vs [0x%08X]\n", (i), (u32)data, (u32)txbuffer[i]);
++ }
++ else
++ {
++ MSG("**[%d][0x%08X] vs [0x%08X]\n" ,(i), (u32)data , (u32)txbuffer[i]);
++ count2++;
++ data=0;
++ }
++ }
++
++ }
++ }
++ printk("Pattern match done count2=%d.\n", count2);
++#endif
++ printk("Pattern match done count=%d.\n", count);
++
++ }
++#if defined(CONFIG_ARCH_MT7623)
++ *(volatile unsigned long*)(0xFB000034) |= 0x00020000;
++ *(volatile unsigned long*)(0xFB000034) &= 0xFFFDFFFF;
++ *(volatile unsigned long*)(ETHDMASYS_I2S_BASE+0x0) &= 0x7FFFFFFF; //Rest I2S to default vaule
++#endif
++
++#if !defined(CONFIG_RALINK_RT3052)
++ break;
++#endif
++ case I2S_DEBUG_EXLBK:
++ MSG("I2S_DEBUG_EXLBK\n");
++#if !defined(CONFIG_ARCH_MT7623)
++ switch(arg)
++ {
++ case 8000:
++ index = 0;
++ break;
++ case 11025:
++ index = 1;
++ break;
++ case 12000:
++ index = 2;
++ break;
++ case 16000:
++ index = 3;
++ break;
++ case 22050:
++ index = 4;
++ break;
++ case 24000:
++ index = 5;
++ break;
++ case 32000:
++ index = 6;
++ break;
++ case 44100:
++ index = 7;
++ break;
++ case 48000:
++ index = 8;
++ break;
++ case 88200:
++ index = 9;
++ break;
++ case 96000:
++ index = 10;
++ break;
++ default:
++ index = 7;
++ }
++#if defined(CONFIG_RALINK_RT3052)
++ break;
++#endif
++#if defined(CONFIG_RALINK_RT6855A)
++ *(volatile unsigned long*)(RALINK_SYSCTL_BASE+0x860) = 0x00008080;
++ //*(volatile unsigned long*)(RALINK_SYSCTL_BASE+0x82C) = 0x00000300;
++#else
++ *(volatile unsigned long*)(RALINK_SYSCTL_BASE+0x60) = 0x00000018;
++#if defined(CONFIG_RALINK_RT3883)
++ *(volatile unsigned long*)(RALINK_SYSCTL_BASE+0x2C) = 0x00003000;
++#else
++ *(volatile unsigned long*)(RALINK_SYSCTL_BASE+0x2C) = 0x00000300;
++#endif
++#endif
++
++ *(volatile unsigned long*)(RALINK_I2S_BASE+0x18) = 0x40000000;
++ *(volatile unsigned long*)(RALINK_I2S_BASE+0x00) = 0x81104040;
++#if defined(CONFIG_RALINK_MT7628)
++ pTable = i2s_inclk_int_16bit;
++#else
++ pTable = i2s_inclk_int;
++#endif
++ data = (volatile unsigned long)(pTable[index]);
++ i2s_outw(I2S_DIVINT_CFG, data);
++#if defined(CONFIG_RALINK_MT7628)
++ pTable = i2s_inclk_comp_16bit;
++#else
++ pTable = i2s_inclk_comp;
++#endif
++ data = (volatile unsigned long)(pTable[index]);
++ data |= REGBIT(1, I2S_CLKDIV_EN);
++ i2s_outw(I2S_DIVCOMP_CFG, data);
++
++ #if defined(CONFIG_I2S_MCLK_12MHZ)
++ pTable = i2s_codec_12Mhz;
++ #if defined(CONFIG_I2S_WM8960)
++ data = pTable[index];
++ #else
++ data = pTable[index]|0x01;
++ #endif
++ #else
++ pTable = i2s_codec_12p288Mhz;
++ data = pTable[index];
++ #endif
++
++ #if defined(CONFIG_I2S_WM8960) || defined(CONFIG_I2S_WM8750) || defined(CONFIG_I2S_WM8751)
++ audiohw_preinit();
++ #endif
++
++
++ #if defined (CONFIG_I2S_WM8960)
++ audiohw_postinit(1, 1, 1, 1, 0); // for codec apll enable, 16 bit word length
++ #elif defined(CONFIG_I2S_WM8750) || defined(CONFIG_I2S_WM8751)
++ audiohw_postinit(1, 1, 1, 0); // for 16 bit word length
++ #endif
++
++
++ #if defined (CONFIG_I2S_WM8960)
++ audiohw_set_frequency(data, 1); // for codec apll enable
++ #elif defined(CONFIG_I2S_WM8750) || defined(CONFIG_I2S_WM8751)
++ audiohw_set_frequency(data|0x1);
++ #endif
++
++
++ #if defined(CONFIG_I2S_WM8960) || defined(CONFIG_I2S_WM8750) || defined(CONFIG_I2S_WM8751)
++ audiohw_set_lineout_vol(1, 100, 100);
++ audiohw_set_linein_vol(100, 100);
++ #endif
++
++
++ #if defined(CONFIG_I2S_TXRX)
++ //audiohw_loopback(data);
++ #endif
++ #if !defined(CONFIG_RALINK_RT3052)
++ break;
++ #endif
++#endif
++ case I2S_DEBUG_CODECBYPASS:
++ #if defined(CONFIG_I2S_TXRX)
++ #if defined(CONFIG_RALINK_MT7628)
++ data = i2s_inw(RALINK_SYSCTL_BASE+0x60);
++ //data &= ~(0x3<<4);
++ data &= ~(0x3<<6);
++ data &= ~(0x3<<16);
++ data &= ~(0x1<<14);
++ i2s_outw(RALINK_SYSCTL_BASE+0x60, data);
++
++ data = i2s_inw(RALINK_SYSCTL_BASE+0x2c);
++ data &= ~(0x07<<9);
++ i2s_outw(RALINK_SYSCTL_BASE+0x2c, data);
++ #endif
++
++ #if defined(CONFIG_I2S_WM8960) || defined(CONFIG_I2S_WM8750) || defined(CONFIG_I2S_WM8751)
++ audiohw_bypass(); /* did not work */
++ #endif
++ #endif
++ break;
++ case I2S_DEBUG_FMT:
++ break;
++ case I2S_DEBUG_RESET:
++ break;
++#if defined(CONFIG_I2S_WM8960)
++ case I2S_DEBUG_CODEC_EXLBK:
++ audiohw_codec_exlbk();
++ break;
++#endif
++ default:
++ MSG("Not support this debug cmd [%d]\n", cmd);
++ break;
++ }
++
++ return 0;
++}
+diff --git a/sound/soc/mtk/mt76xx_i2s.c b/sound/soc/mtk/mt76xx_i2s.c
+new file mode 100644
+index 0000000..7615b51
+--- /dev/null
++++ b/sound/soc/mtk/mt76xx_i2s.c
+@@ -0,0 +1,304 @@
++/*
++ * mtk_audio_drv.c
++ *
++ * Created on: 2013/8/20
++ * Author: MTK04880
++ */
++#include <linux/init.h>
++#include <linux/version.h>
++#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,35)
++#include <linux/sched.h>
++#endif
++#include <linux/module.h>
++#include <linux/kernel.h> /* printk() */
++#include <linux/slab.h> /* kmalloc() */
++#include <linux/fs.h> /* everything... */
++#include <linux/errno.h> /* error codes */
++#include <linux/types.h> /* size_t */
++#include <linux/proc_fs.h>
++#include <linux/fcntl.h> /* O_ACCMODE */
++#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,36)
++#include <asm/system.h> /* cli(), *_flags */
++#endif
++#include <asm/uaccess.h> /* copy_from/to_user */
++#include <linux/interrupt.h>
++#include <linux/mm.h>
++#include <linux/dma-mapping.h>
++#include <sound/core.h>
++#include <linux/pci.h>
++#include <sound/pcm.h>
++#include <sound/pcm_params.h>
++#include <sound/soc.h>
++#include <sound/soc-dapm.h>
++#include <sound/initval.h>
++#include "ralink_gdma.h"
++#include "mt76xx_i2s.h"
++
++/****************************/
++/*GLOBAL VARIABLE DEFINITION*/
++/****************************/
++extern i2s_config_type* pi2s_config;
++
++/****************************/
++/*FUNCTION DECLRATION */
++/****************************/
++static int mt76xx_i2s_set_fmt(struct snd_soc_dai *cpu_dai,\
++ unsigned int fmt);
++
++//static int mt76xx_i2s_shutdown(struct snd_pcm_substream *substream,
++// struct snd_soc_dai *dai);
++static int mt76xx_i2s_startup(struct snd_pcm_substream *substream,
++ struct snd_soc_dai *dai);
++static int mt76xx_i2s_hw_params(struct snd_pcm_substream *substream,\
++ struct snd_pcm_hw_params *params,\
++ struct snd_soc_dai *dai);
++static int mt76xx_i2s_play_prepare(struct snd_pcm_substream *substream,struct snd_soc_dai *dai);
++static int mt76xx_i2s_rec_prepare(struct snd_pcm_substream *substream,struct snd_soc_dai *dai);
++static int mt76xx_i2s_hw_free(struct snd_pcm_substream *substream,struct snd_soc_dai *dai);
++static int mt76xx_i2s_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai);
++
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,20)
++static int mt76xx_i2s_drv_probe(struct platform_device *pdev);
++static int mt76xx_i2s_drv_remove(struct platform_device *pdev);
++#endif
++/****************************/
++/*STRUCTURE DEFINITION */
++/****************************/
++
++
++static struct snd_soc_dai_ops mt76xx_i2s_dai_ops = {
++ .startup = mt76xx_i2s_startup,
++ .hw_params = mt76xx_i2s_hw_params,
++ .hw_free = mt76xx_i2s_hw_free,
++ //.shutdown = mt76xx_i2s_shutdown,
++ .prepare = mt76xx_i2s_prepare,
++ .set_fmt = mt76xx_i2s_set_fmt,
++ //.set_sysclk = mt76xx_i2s_set_sysclk,
++};
++
++const struct snd_soc_component_driver mt76xx_i2s_component = {
++ .name = "mt76xx-i2s",
++};
++
++struct snd_soc_dai_driver mt76xx_i2s_dai = {
++ .playback = {
++ .channels_min = 1,
++ .channels_max = 2,
++ .rates = (SNDRV_PCM_RATE_8000|SNDRV_PCM_RATE_11025|\
++ SNDRV_PCM_RATE_16000|SNDRV_PCM_RATE_22050|SNDRV_PCM_RATE_32000|\
++ SNDRV_PCM_RATE_44100|SNDRV_PCM_RATE_48000),
++
++ .formats = (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
++ SNDRV_PCM_FMTBIT_S24_LE),
++ },
++ .capture = {
++ .channels_min = 1,
++ .channels_max = 2,
++ .rates = (SNDRV_PCM_RATE_8000|SNDRV_PCM_RATE_11025|\
++ SNDRV_PCM_RATE_16000|SNDRV_PCM_RATE_22050|SNDRV_PCM_RATE_32000|\
++ SNDRV_PCM_RATE_44100|SNDRV_PCM_RATE_48000),
++ .formats = (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
++ SNDRV_PCM_FMTBIT_S24_LE),
++ },
++ .ops = &mt76xx_i2s_dai_ops,
++ .symmetric_rates = 1,
++};
++
++/****************************/
++/*FUNCTION BODY */
++/****************************/
++
++static int mt76xx_i2s_set_fmt(struct snd_soc_dai *cpu_dai,
++ unsigned int fmt)
++{//TODO
++
++ //printk("******* %s *******\n", __func__);
++ return 0;
++}
++
++static int mt76xx_i2s_play_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
++{
++ //printk("******* %s *******\n", __func__);
++ i2s_config_type* rtd = (i2s_config_type*)substream->runtime->private_data;
++ rtd->pss[SNDRV_PCM_STREAM_PLAYBACK] = substream;
++ if(! rtd->i2sStat[SNDRV_PCM_STREAM_PLAYBACK]){
++ i2s_reset_tx_param( rtd);
++ i2s_tx_config( rtd);
++ gdma_En_Switch(rtd, STREAM_PLAYBACK, GDMA_I2S_EN);
++
++ if( rtd->bRxDMAEnable==0)
++ i2s_clock_enable( rtd);
++
++ i2s_tx_enable( rtd);
++ rtd->i2sStat[SNDRV_PCM_STREAM_PLAYBACK] = 1;
++ MSG("I2S_TXENABLE done\n");
++ }
++
++ return 0;
++}
++
++static int mt76xx_i2s_rec_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
++{
++
++ //printk("******* %s *******\n", __func__);
++ i2s_config_type* rtd = (i2s_config_type*)substream->runtime->private_data;
++ rtd->pss[SNDRV_PCM_STREAM_CAPTURE] = substream;
++ if(! rtd->i2sStat[SNDRV_PCM_STREAM_CAPTURE]) {
++ i2s_reset_rx_param(rtd);
++ i2s_rx_config(rtd);
++ gdma_En_Switch(rtd, STREAM_CAPTURE, GDMA_I2S_EN);
++
++ if(rtd->bTxDMAEnable==0)
++ i2s_clock_enable(rtd);
++
++ i2s_rx_enable(rtd);
++ rtd->i2sStat[SNDRV_PCM_STREAM_CAPTURE] = 1;
++ }
++ return 0;
++}
++
++/*static int mt76xx_i2s_shutdown(struct snd_pcm_substream *substream,
++ struct snd_soc_dai *dai)
++{
++ //i2s_config_type* rtd = (i2s_config_type*)substream->runtime->private_data;
++ //printk("******* %s *******\n", __func__);
++ return 0;
++}
++*/
++static int mt76xx_i2s_startup(struct snd_pcm_substream *substream,
++ struct snd_soc_dai *dai)
++{
++
++ //printk("******* %s *******\n", __func__);
++ if((!pi2s_config->i2sStat[SNDRV_PCM_STREAM_PLAYBACK]) && (!pi2s_config->i2sStat[SNDRV_PCM_STREAM_CAPTURE])){
++ i2s_startup();
++ if(!pi2s_config)
++ return -1;
++ i2s_reset_config(pi2s_config);
++ }
++ substream->runtime->private_data = pi2s_config;
++ return 0;
++}
++
++static int mt76xx_i2s_hw_params(struct snd_pcm_substream *substream,\
++ struct snd_pcm_hw_params *params,\
++ struct snd_soc_dai *dai){
++ unsigned int srate = 0;
++ //unsigned long data;
++ struct snd_pcm_runtime *runtime = substream->runtime;
++ i2s_config_type* rtd = runtime->private_data;
++
++ //printk("******* %s *******\n", __func__);
++ switch(params_rate(params)){
++ case 8000:
++ srate = 8000;
++ break;
++ case 16000:
++ srate = 16000;
++ break;
++ case 32000:
++ srate = 32000;
++ break;
++ case 44100:
++ srate = 44100;
++ break;
++ case 48000:
++ srate = 48000;
++ break;
++ default:
++ srate = 44100;
++ //MSG("audio sampling rate %u should be %d ~ %d Hz\n", (u32)params_rate(params), MIN_SRATE_HZ, MAX_SRATE_HZ);
++ break;
++ }
++ if(srate){
++ if((rtd->bRxDMAEnable != GDMA_I2S_EN) && (rtd->bTxDMAEnable != GDMA_I2S_EN)){
++ rtd->srate = srate;
++ MSG("set audio sampling rate to %d Hz\n", rtd->srate);
++ }
++ }
++
++ return 0;
++}
++static int mt76xx_i2s_hw_free(struct snd_pcm_substream *substream,struct snd_soc_dai *dai){
++
++ //printk("******* %s *******\n", __func__);
++ i2s_config_type* rtd = (i2s_config_type*)substream->runtime->private_data;
++ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK){
++ if(rtd->i2sStat[SNDRV_PCM_STREAM_PLAYBACK]){
++ MSG("I2S_TXDISABLE\n");
++ i2s_reset_tx_param(rtd);
++
++ if((rtd->bRxDMAEnable==0)&&(rtd->bTxDMAEnable==0)){
++ i2s_clock_disable(rtd);
++ }
++ rtd->i2sStat[SNDRV_PCM_STREAM_PLAYBACK] = 0;
++ }
++ }
++ else{
++ if(rtd->i2sStat[SNDRV_PCM_STREAM_CAPTURE]){
++ MSG("I2S_RXDISABLE\n");
++ i2s_reset_rx_param(rtd);
++
++ if((rtd->bRxDMAEnable==0)&&(rtd->bTxDMAEnable==0)){
++ i2s_clock_disable(rtd);
++ }
++ rtd->i2sStat[SNDRV_PCM_STREAM_CAPTURE] = 0;
++ }
++ }
++ return 0;
++}
++static int mt76xx_i2s_prepare(struct snd_pcm_substream *substream,struct snd_soc_dai *dai)
++{
++
++ //printk("******* %s *******\n", __func__);
++ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
++ return mt76xx_i2s_play_prepare(substream, dai);
++ else
++ return mt76xx_i2s_rec_prepare(substream, dai);
++
++ return 0;
++}
++
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,20)
++static int mt76xx_i2s_drv_probe(struct platform_device *pdev)
++{
++ //printk("****** %s ******\n", __func__);
++ return snd_soc_register_component(&pdev->dev, &mt76xx_i2s_component,
++ &mt76xx_i2s_dai, 1);
++}
++
++static int mt76xx_i2s_drv_remove(struct platform_device *pdev)
++{
++ snd_soc_unregister_component(&pdev->dev);
++ return 0;
++}
++
++static struct platform_driver mt76xx_i2s_driver = {
++ .probe = mt76xx_i2s_drv_probe,
++ .remove = mt76xx_i2s_drv_remove,
++ .driver = {
++ .name = "mt76xx-i2s",
++ .owner = THIS_MODULE,
++ },
++};
++
++static int __init mt76xx_i2s_init(void)
++{
++
++ //printk("****** %s ******\n", __func__);
++ return platform_driver_register(&mt76xx_i2s_driver);
++}
++
++static void __exit mt76xx_i2s_exit(void)
++{
++ //printk("****** %s ******\n", __func__);
++ platform_driver_unregister(&mt76xx_i2s_driver);
++}
++
++module_init(mt76xx_i2s_init);
++module_exit(mt76xx_i2s_exit);
++
++MODULE_AUTHOR("Dora Chen");
++MODULE_DESCRIPTION("Stretch MT76xx I2S Interface");
++MODULE_LICENSE("GPL");
++#endif
+diff --git a/sound/soc/mtk/mt76xx_i2s.h b/sound/soc/mtk/mt76xx_i2s.h
+new file mode 100644
+index 0000000..9ae0e50
+--- /dev/null
++++ b/sound/soc/mtk/mt76xx_i2s.h
+@@ -0,0 +1,18 @@
++/*
++ * mtk_i2s.h
++ *
++ * Created on: 2013/8/20
++ * Author: MTK04880
++ */
++
++#ifndef MTK_I2S_H_
++#define MTK_I2S_H_
++
++
++#ifdef __KERNEL__
++//#include <asm/rt2880/rt_mmap.h>
++#include <linux/fs.h>
++#endif
++
++#include "i2s_ctrl.h"
++#endif /* MTK_I2S_H_ */
+diff --git a/sound/soc/mtk/mt76xx_machine.c b/sound/soc/mtk/mt76xx_machine.c
+new file mode 100644
+index 0000000..00d2145
+--- /dev/null
++++ b/sound/soc/mtk/mt76xx_machine.c
+@@ -0,0 +1,317 @@
++/*
++ * mt76xx_machine.c
++ *
++ */
++#include <linux/init.h>
++#include <linux/version.h>
++#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,35)
++#include <linux/sched.h>
++#endif
++#include <linux/module.h>
++#include <linux/kernel.h> /* printk() */
++#include <linux/slab.h> /* kmalloc() */
++#include <linux/fs.h> /* everything... */
++#include <linux/errno.h> /* error codes */
++#include <linux/types.h> /* size_t */
++#include <linux/proc_fs.h>
++#include <linux/fcntl.h> /* O_ACCMODE */
++#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,36)
++#include <asm/system.h> /* cli(), *_flags */
++#endif
++#include <asm/uaccess.h> /* copy_from/to_user */
++#include <linux/interrupt.h>
++#include <linux/mm.h>
++#include <linux/dma-mapping.h>
++#include <sound/core.h>
++#include <linux/pci.h>
++#include <sound/pcm.h>
++#include <sound/pcm_params.h>
++#include <sound/soc.h>
++#include <sound/soc-dapm.h>
++#include <sound/initval.h>
++#include <linux/i2c.h>
++#include <linux/ioport.h>
++#include <linux/delay.h>
++#include "ralink_gdma.h"
++#include "mt76xx_i2s.h"
++#include "mt76xx_machine.h"
++#if defined(CONFIG_SND_SOC_WM8960)
++#include "../codecs/wm8960.h"
++#endif
++
++#define I2C_AUDIO_DEV_ID (0)
++/****************************/
++/*FUNCTION DECLRATION */
++/****************************/
++extern unsigned long i2s_codec_12p288Mhz[11];
++extern unsigned long i2s_codec_12Mhz[11];
++
++
++static int mt76xx_codec_clock_hwparams(struct snd_pcm_substream *substream,\
++ struct snd_pcm_hw_params *params);
++static int mt76xx_codec_startup(struct snd_pcm_substream *substream);
++static int mt76xx_codec_init(struct snd_soc_pcm_runtime *rtd);
++extern struct snd_soc_dai_driver mt76xx_i2s_dai;
++extern struct snd_soc_platform_driver mt76xx_soc_platform;
++struct platform_device *mt76xx_audio_device;
++
++#if defined(CONFIG_SND_SOC_WM8960)
++extern struct snd_soc_dai wm8960_dai;
++extern struct snd_soc_codec_device soc_codec_dev_wm8960;
++#endif
++
++static struct snd_soc_ops mtk_audio_ops = {
++ .hw_params = mt76xx_codec_clock_hwparams,
++ .startup = mt76xx_codec_startup,
++};
++
++static struct snd_soc_dai_link mtk_audio_dai = {
++ .name = "mtk_dai",
++ .stream_name = "WMserious PCM",
++ .cpu_dai_name = "mt76xx-i2s",
++ .codec_dai_name = "wm8960-hifi",
++ .codec_name = "wm8960.0-001a",
++ .platform_name = "mt76xx-pcm",
++ .ignore_pmdown_time = true,
++ .init = mt76xx_codec_init,
++ .ops = &mtk_audio_ops,
++};
++
++static struct snd_soc_card mtk_audio_card = {
++ .name = "MTK APSoC I2S",
++ .owner = THIS_MODULE,
++ .dai_link = &mtk_audio_dai,//I2S/Codec
++ .num_links = 1,
++};
++
++static int mt76xx_codec_clock_hwparams(struct snd_pcm_substream *substream,
++ struct snd_pcm_hw_params *params)
++{
++ struct snd_soc_pcm_runtime *p = substream->private_data;
++ struct snd_soc_dai *codec_dai = p->codec_dai;
++ struct snd_pcm_runtime *runtime = substream->runtime;
++ i2s_config_type* rtd = runtime->private_data;
++ unsigned long data,index = 0;
++ unsigned long* pTable;
++ int mclk,ret,targetClk = 0;
++
++ /*For duplex mode, avoid setting twice.*/
++ if((rtd->bRxDMAEnable == GDMA_I2S_EN) || (rtd->bTxDMAEnable == GDMA_I2S_EN))
++ return 0;
++#if defined(CONFIG_I2S_MCLK_12MHZ)
++ mclk = 12000000;
++#elif defined(CONFIG_I2S_MCLK_12P288MHZ)
++ mclk = 12288000;
++#else
++ mclk = 12000000;
++#endif
++ //snd_soc_dai_set_sysclk(codec_dai,0,mclk, SND_SOC_CLOCK_IN);
++
++ switch(params_rate(params)){
++ case 8000:
++ index = 0;
++ targetClk = 12288000;
++ break;
++ case 12000:
++ index = 2;
++ targetClk = 12288000;
++ break;
++ case 16000:
++ index = 3;
++ targetClk = 12288000;
++ break;
++ case 24000:
++ index = 5;
++ targetClk = 12288000;
++ break;
++ case 32000:
++ index = 6;
++ targetClk = 12288000;
++ break;
++ case 48000:
++ index = 8;
++ targetClk = 12288000;
++ break;
++ case 11025:
++ index = 1;
++ targetClk = 11289600;
++ break;
++ case 22050:
++ index = 4;
++ targetClk = 11289600;
++ break;
++ case 44100:
++ index = 7;
++ targetClk = 11289600;
++ break;
++ case 88200:
++ index = 9;
++ targetClk = 11289600;
++ break;
++ case 96000:
++ index = 10;
++ targetClk = 11289600;
++ break;
++ default:
++ index = 7;
++ targetClk = 12288000;
++ //MSG("audio sampling rate %u should be %d ~ %d Hz\n", (u32)params_rate(params), MIN_SRATE_HZ, MAX_SRATE_HZ);
++ break;
++ }
++#if defined(CONFIG_SND_SOC_WM8960)
++ /*
++ * There is a fixed divide by 4 in the PLL and a selectable
++ * divide by N after the PLL which should be set to divide by 2 to meet this requirement.
++ * */
++ ret = snd_soc_dai_set_pll(codec_dai, 0, 0,mclk, targetClk*2);
++ /* From app notes: allow Vref to stabilize to reduce clicks */
++ if(rtd->slave_en){
++ //printk("WM8960 is in master mode\n");
++ ret = snd_soc_dai_set_clkdiv(codec_dai, WM8960_DCLKDIV, 0x1c4);
++ ret = snd_soc_dai_set_clkdiv(codec_dai, WM8960_SYSCLKDIV, 0x5);
++ }
++
++#endif
++ if(!rtd->slave_en)
++ snd_soc_dai_set_fmt(codec_dai,SND_SOC_DAIFMT_CBS_CFS|SND_SOC_DAIFMT_I2S|SND_SOC_DAIFMT_NB_NF);
++ else{
++ snd_soc_dai_set_fmt(codec_dai,SND_SOC_DAIFMT_CBM_CFM|SND_SOC_DAIFMT_I2S|SND_SOC_DAIFMT_NB_NF);
++ }
++ mdelay(5);
++
++#if defined(CONFIG_SND_SOC_WM8960)
++#if defined(CONFIG_I2S_MCLK_12MHZ)
++ pTable = i2s_codec_12Mhz;
++ data = pTable[index];
++#else
++ pTable = i2s_codec_12p288Mhz;
++ data = pTable[index];
++#endif
++ if(rtd->codec_pll_en)
++ ret = snd_soc_dai_set_clkdiv(codec_dai, WM8960_DACDIV, (data<<3)|0x5);
++ else
++ ret = snd_soc_dai_set_clkdiv(codec_dai, WM8960_DACDIV, (data<<3|0x4));
++#endif
++
++ return 0;
++}
++
++static int mt76xx_codec_startup(struct snd_pcm_substream *substream)
++{
++ //printk("******* %s *******\n", __func__);
++ return 0;
++}
++static int mt76xx_codec_init(struct snd_soc_pcm_runtime *rtd)
++{
++
++ //printk("******* %s *******\n", __func__);
++ return 0;
++}
++
++static struct i2c_board_info i2c_board_info[] = {
++ {
++#if defined(CONFIG_SND_SOC_WM8750)
++ I2C_BOARD_INFO("wm8750", (0x36 >> 1)),
++#elif defined(CONFIG_SND_SOC_WM8960)
++ I2C_BOARD_INFO("codec_wm8960", (0x34)),
++ }, {
++ I2C_BOARD_INFO("wm8960", (0x34 >> 1)),
++#endif
++ }
++};
++
++static struct platform_device *soc_mtk_i2s_dev;
++static struct platform_device *soc_mtk_pcm_dev;
++
++static int __init mt76xx_machine_init(void)
++{
++ //struct snd_soc_device *socdev = &mtk_audio_devdata;
++ //struct i2c_adapter *adapter = NULL;
++ //struct i2c_client *client = NULL;
++ int ret = 0;
++ struct i2c_adapter *adapter = NULL;
++ struct i2c_client *client = NULL;
++
++ adapter = i2c_get_adapter(I2C_AUDIO_DEV_ID);
++ if (!adapter)
++ return -ENODEV;
++ client = i2c_new_device(adapter, &i2c_board_info[0]);
++ if (!client)
++ return -ENODEV;
++ i2c_get_clientdata(client);
++
++ client = i2c_new_device(adapter, &i2c_board_info[1]);
++ if (!client)
++ return -ENODEV;
++ i2c_get_clientdata(client);
++
++ i2c_put_adapter(adapter);
++
++ soc_mtk_i2s_dev =
++ platform_device_register_simple("mt76xx-i2s", -1, NULL, 0);
++ if (IS_ERR(soc_mtk_i2s_dev))
++ return PTR_ERR(soc_mtk_i2s_dev);
++
++ soc_mtk_pcm_dev =
++ platform_device_register_simple("mt76xx-pcm", -1, NULL, 0);
++ if (IS_ERR(soc_mtk_pcm_dev))
++ return PTR_ERR(soc_mtk_pcm_dev);
++
++ mt76xx_audio_device = platform_device_alloc("soc-audio",-1);
++ if (mt76xx_audio_device == NULL) {
++ ret = -ENOMEM;
++ goto err_device_alloc;
++ }
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38)
++ platform_set_drvdata(mt76xx_audio_device, &mtk_audio_card);
++#else
++ platform_set_drvdata(mt76xx_audio_device, &mtk_audio_devdata);
++ mtk_audio_devdata.dev = &mt76xx_audio_device->dev;
++#endif
++
++ /*Ralink I2S register process end*/
++ ret = platform_device_add(mt76xx_audio_device);
++ if (ret) {
++ printk("mtk audio device : platform_device_add failed (%d)\n",ret);
++ goto err_device_add;
++ }
++
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38)
++#else
++ snd_soc_register_dai(&mt76xx_i2s_dai);
++#endif
++
++ return 0;
++
++err_device_add:
++ if (mt76xx_audio_device!= NULL) {
++ platform_device_put(mt76xx_audio_device);
++ mt76xx_audio_device = NULL;
++ }
++err_device_alloc:
++ return ret;
++}
++
++
++static void __exit mt76xx_machine_exit(void)
++{
++
++ platform_device_unregister(mt76xx_audio_device);
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,20)
++ /* Do nothing */
++#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38)
++ snd_soc_unregister_platform(&mt76xx_audio_device->dev);
++#else
++ snd_soc_unregister_platform(&mt76xx_soc_platform);
++#endif
++ platform_device_unregister(soc_mtk_i2s_dev);
++ platform_device_unregister(soc_mtk_pcm_dev);
++
++ mt76xx_audio_device = NULL;
++}
++
++//module_init(mt76xx_machine_init);
++late_initcall(mt76xx_machine_init);
++module_exit(mt76xx_machine_exit);
++//EXPORT_SYMBOL_GPL(mt76xx_soc_platform);
++MODULE_LICENSE("GPL");
+diff --git a/sound/soc/mtk/mt76xx_machine.h b/sound/soc/mtk/mt76xx_machine.h
+new file mode 100644
+index 0000000..79532b5
+--- /dev/null
++++ b/sound/soc/mtk/mt76xx_machine.h
+@@ -0,0 +1,21 @@
++/*
++ * mtk_audio_device.h
++ *
++ * Created on: 2013/10/23
++ * Author: MTK04880
++ */
++
++#ifndef MT76XX_MACHINE_H_
++#define MT76XX_MACHINE_H_
++#include <sound/pcm.h>
++#include <sound/pcm_params.h>
++#include <sound/soc.h>
++#include <sound/soc-dapm.h>
++
++#if 0
++#ifdef CONFIG_I2S_MMAP
++#undef CONFIG_I2S_MMAP
++#endif
++#endif
++
++#endif /* MT76XX_MACHINE_H_ */
+diff --git a/sound/soc/mtk/mt76xx_pcm.c b/sound/soc/mtk/mt76xx_pcm.c
+new file mode 100644
+index 0000000..1100ee0
+--- /dev/null
++++ b/sound/soc/mtk/mt76xx_pcm.c
+@@ -0,0 +1,499 @@
++/*
++ * mt76xx_pcm.c
++ *
++ * Created on: 2013/9/6
++ * Author: MTK04880
++ */
++
++#include <linux/init.h>
++#include <linux/version.h>
++#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,35)
++#include <linux/sched.h>
++#endif
++#include <linux/module.h>
++#include <linux/kernel.h> /* printk() */
++#include <linux/slab.h> /* kmalloc() */
++#include <linux/fs.h> /* everything... */
++#include <linux/errno.h> /* error codes */
++#include <linux/types.h> /* size_t */
++#include <linux/proc_fs.h>
++#include <linux/fcntl.h> /* O_ACCMODE */
++#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,36)
++#include <asm/system.h> /* cli(), *_flags */
++#endif
++#include <asm/uaccess.h> /* copy_from/to_user */
++#include <linux/interrupt.h>
++#include <linux/mm.h>
++#include <linux/dma-mapping.h>
++#include <sound/core.h>
++#include <linux/pci.h>
++#include <sound/pcm.h>
++#include <sound/pcm_params.h>
++#include <sound/soc.h>
++#include <sound/soc-dapm.h>
++#include <sound/initval.h>
++#include "ralink_gdma.h"
++#include "mt76xx_i2s.h"
++
++#define GDMA_PAGE_SIZE I2S_PAGE_SIZE
++#define GDMA_PAGE_NUM MAX_I2S_PAGE
++#define GDMA_TOTAL_PAGE_SIZE I2S_TOTAL_PAGE_SIZE
++
++dma_addr_t i2s_txdma_addr, i2s_rxdma_addr;
++dma_addr_t i2s_mmap_addr[GDMA_PAGE_NUM*2];
++
++extern struct tasklet_struct i2s_tx_tasklet;
++extern struct tasklet_struct i2s_rx_tasklet;
++extern int i2s_mmap_remap(struct vm_area_struct *vma, unsigned long size);
++extern void i2s_tx_end_sleep_on(i2s_config_type* ptri2s_config);
++extern void i2s_rx_end_sleep_on(i2s_config_type* ptri2s_config);
++
++static int mt76xx_pcm_open(struct snd_pcm_substream *substream);
++static int mt76xx_pcm_new(struct snd_soc_pcm_runtime *rtd);
++static void mt76xx_pcm_free(struct snd_pcm *pcm);
++static int mt76xx_pcm_close(struct snd_pcm_substream *substream);
++static snd_pcm_uframes_t mt76xx_pcm_pointer(struct snd_pcm_substream *substream);
++static int mt76xx_pcm_trigger(struct snd_pcm_substream *substream, int cmd);
++static int mt76xx_pcm_prepare(struct snd_pcm_substream *substream);
++static int mt76xx_pcm_hw_params(struct snd_pcm_substream *substream,\
++ struct snd_pcm_hw_params *hw_params);
++static int mt76xx_pcm_copy(struct snd_pcm_substream *substream, int channel,\
++ snd_pcm_uframes_t pos,void __user *buf, snd_pcm_uframes_t count);
++static int mt76xx_pcm_mmap(struct snd_pcm_substream *substream, struct vm_area_struct *vma);
++static int mt76xx_pcm_hw_free(struct snd_pcm_substream *substream);
++
++static int mt76xx_pcm_free_dma_buffer(struct snd_pcm_substream *substream,int stream);
++static int mt76xx_pcm_allocate_dma_buffer(struct snd_pcm_substream *substream,int stream);
++
++#if LINUX_VERSION_CODE > KERNEL_VERSION(3,10,20)
++static int mt76xx_platform_drv_probe(struct platform_device *pdev);
++static int mt76xx_platform_drv_remove(struct platform_device *pdev);
++#endif
++
++static const struct snd_pcm_hardware mt76xx_pcm_hwparam = {
++#if defined(CONFIG_I2S_MMAP)
++ .info = (SNDRV_PCM_INFO_INTERLEAVED |
++ SNDRV_PCM_INFO_PAUSE |
++ SNDRV_PCM_INFO_RESUME |
++ SNDRV_PCM_INFO_MMAP |
++ SNDRV_PCM_INFO_MMAP_VALID),
++#else
++ .info = (SNDRV_PCM_INFO_INTERLEAVED |
++ SNDRV_PCM_INFO_PAUSE |
++ SNDRV_PCM_INFO_RESUME),
++#endif
++ .formats = SNDRV_PCM_FMTBIT_S16_LE,
++ .period_bytes_min = GDMA_PAGE_SIZE,
++ .period_bytes_max = GDMA_PAGE_SIZE,
++ .periods_min = 1,
++ .periods_max = GDMA_PAGE_NUM,
++ .buffer_bytes_max = GDMA_TOTAL_PAGE_SIZE,
++};
++
++static struct snd_pcm_ops mt76xx_pcm_ops = {
++
++ .open = mt76xx_pcm_open,
++ .ioctl = snd_pcm_lib_ioctl,
++ .hw_params = mt76xx_pcm_hw_params,
++ .hw_free = mt76xx_pcm_hw_free,
++ .trigger = mt76xx_pcm_trigger,
++ .prepare = mt76xx_pcm_prepare,
++ .pointer = mt76xx_pcm_pointer,
++ .close = mt76xx_pcm_close,
++#if defined(CONFIG_I2S_MMAP)
++ .mmap = mt76xx_pcm_mmap,
++#endif
++ .copy = mt76xx_pcm_copy,
++};
++#if LINUX_VERSION_CODE > KERNEL_VERSION(3,10,0)
++struct snd_soc_platform_driver mt76xx_soc_platform = {
++ .ops = &mt76xx_pcm_ops,
++ .pcm_new = mt76xx_pcm_new,
++ .pcm_free = mt76xx_pcm_free,
++};
++#else
++struct snd_soc_platform mt76xx_soc_platform = {
++ .name = "mtk-dma",
++ .pcm_ops = &mt76xx_pcm_ops,
++ .pcm_new = mt76xx_pcm_new,
++ .pcm_free = mt76xx_pcm_free,
++};
++#endif
++
++static int mt76xx_pcm_close(struct snd_pcm_substream *substream){
++
++ //printk("******* %s *********\n", __func__);
++ return 0;
++}
++
++static snd_pcm_uframes_t mt76xx_pcm_pointer(struct snd_pcm_substream *substream)
++{
++ struct snd_pcm_runtime *runtime = substream->runtime;
++ i2s_config_type* rtd = runtime->private_data;
++ unsigned int offset = 0;
++ //int buff_frame_bond = bytes_to_frames(runtime, GDMA_PAGE_SIZE);
++ //printk("\n******* %s *********\n", __func__);
++
++ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK){
++ offset = bytes_to_frames(runtime, GDMA_PAGE_SIZE*rtd->tx_r_idx);
++ //printk("r:%d w:%d (%d) \n",rtd->tx_r_idx,rtd->tx_w_idx,(runtime->control->appl_ptr/buff_frame_bond)%GDMA_PAGE_NUM);
++ }
++ else{
++ offset = bytes_to_frames(runtime, GDMA_PAGE_SIZE*rtd->rx_w_idx);
++ //printk("w:%d r:%d appl_ptr:%x\n",rtd->rx_w_idx,rtd->rx_r_idx,(runtime->control->appl_ptr/buff_frame_bond)%GDMA_PAGE_NUM);
++ }
++ return offset;
++}
++
++
++static int mt76xx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
++{
++ int ret = 0;
++ i2s_config_type* rtd = (i2s_config_type*)substream->runtime->private_data;
++ //struct snd_pcm_runtime *runtime= substream->runtime;
++
++ //printk("******* %s *********\n", __func__);
++/* printk("trigger cmd:%s\n",(cmd==SNDRV_PCM_TRIGGER_START)?"START":\
++ (cmd==SNDRV_PCM_TRIGGER_RESUME)?"RESUME":\
++ (cmd==SNDRV_PCM_TRIGGER_PAUSE_RELEASE)?"PAUSE_RELEASE":\
++ (cmd==SNDRV_PCM_TRIGGER_STOP)?"STOP":\
++ (cmd==SNDRV_PCM_TRIGGER_SUSPEND)?"SUSPEND":\
++ (cmd==SNDRV_PCM_TRIGGER_PAUSE_PUSH)?"PAUSE_PUSH":"default");
++*/
++ switch (cmd) {
++ case SNDRV_PCM_TRIGGER_START:
++ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
++ rtd->bTrigger[SNDRV_PCM_STREAM_PLAYBACK] = 1;
++ } else {
++ rtd->bTrigger[SNDRV_PCM_STREAM_CAPTURE] = 1;
++ }
++ break;
++ case SNDRV_PCM_TRIGGER_STOP:
++ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
++ rtd->bTrigger[SNDRV_PCM_STREAM_PLAYBACK] = 0;
++ } else {
++ rtd->bTrigger[SNDRV_PCM_STREAM_CAPTURE] = 0;
++ }
++ break;
++ case SNDRV_PCM_TRIGGER_RESUME:
++ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
++ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK){
++ rtd->tx_pause_en = 0;
++ } else {
++ rtd->rx_pause_en = 0;
++ }
++ break;
++
++ case SNDRV_PCM_TRIGGER_SUSPEND:
++ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
++ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK){
++ rtd->tx_pause_en = 1;
++ } else {
++ rtd->rx_pause_en = 1;
++ }
++ break;
++ default:
++ ret = -EINVAL;
++ break;
++ }
++ return ret;
++}
++
++static int mt76xx_pcm_copy(struct snd_pcm_substream *substream, int channel,\
++ snd_pcm_uframes_t pos,void __user *buf, snd_pcm_uframes_t count)
++{
++ struct snd_pcm_runtime *runtime= substream->runtime;
++ i2s_config_type* rtd = runtime->private_data;
++ int tx_w_idx = 0;
++ int rx_r_idx = 0;
++ char *hwbuf = NULL;
++
++ //printk("******* %s *********\n", __func__);
++ hwbuf = runtime->dma_area + frames_to_bytes(runtime, pos);
++ //MSG("%s bur:%x\n",__func__,hwbuf);
++ //printk("hw_ptr:%d, buffer_size:%d, appl_prt:%d, boundary:%d\n",
++ // runtime->status->hw_ptr, runtime->buffer_size, runtime->control->appl_ptr, runtime->boundary);
++
++ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK){
++ rtd->tx_w_idx = (rtd->tx_w_idx+1)%MAX_I2S_PAGE;
++ tx_w_idx = rtd->tx_w_idx;
++ //printk("put TB[%d - %x] for user write\n",rtd->tx_w_idx,pos);
++ copy_from_user(rtd->pMMAPTxBufPtr[tx_w_idx], (char*)buf, I2S_PAGE_SIZE);
++ }
++ else{
++ rx_r_idx = rtd->rx_r_idx;
++ rtd->rx_r_idx = (rtd->rx_r_idx+1)%MAX_I2S_PAGE;
++ copy_to_user((char*)buf, rtd->pMMAPRxBufPtr[rx_r_idx], I2S_PAGE_SIZE);
++ }
++ return 0;
++}
++
++static int mt76xx_pcm_mmap(struct snd_pcm_substream *substream, struct vm_area_struct *vma)
++{
++ int ret;
++ unsigned long size;
++
++ size = vma->vm_end-vma->vm_start;
++ printk("******* %s: size :%lx end:%lx start:%lx *******\n", __func__,size,vma->vm_end,vma->vm_start);
++ ret = i2s_mmap_remap(vma, size);
++
++ return ret;
++}
++
++
++static int mt76xx_pcm_prepare(struct snd_pcm_substream *substream)
++{
++ struct snd_pcm_runtime *runtime= substream->runtime;
++ i2s_config_type *rtd = (i2s_config_type*)runtime->private_data;
++ //runtime->buffer_size = GDMA_PAGE_NUM*GDMA_PAGE_SIZE;
++ //runtime->boundary = (GDMA_PAGE_NUM*GDMA_PAGE_SIZE)/4;
++
++ //printk("******* %s *******\n", __func__);
++ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK){
++ //printk("===== %s:%s:%d =====\n", __FILE__, __func__, __LINE__);
++ mt76xx_pcm_allocate_dma_buffer(substream,SNDRV_PCM_STREAM_PLAYBACK);
++
++ if(! rtd->dmaStat[SNDRV_PCM_STREAM_PLAYBACK]){
++ i2s_page_prepare(rtd,STREAM_PLAYBACK);
++ tasklet_init(&i2s_tx_tasklet, i2s_tx_task, (u32)rtd);
++ rtd->dmaStat[SNDRV_PCM_STREAM_PLAYBACK] = 1;
++ gdma_unmask_handler(GDMA_I2S_TX0);
++ }
++ } else {
++ mt76xx_pcm_allocate_dma_buffer(substream,SNDRV_PCM_STREAM_CAPTURE);
++
++ if(! rtd->dmaStat[SNDRV_PCM_STREAM_CAPTURE]){
++ i2s_page_prepare(rtd,STREAM_CAPTURE); /* TX:enLabel=1; RX:enLabel=2 */
++ tasklet_init(&i2s_rx_tasklet, i2s_rx_task, (u32)rtd);
++ rtd->dmaStat[SNDRV_PCM_STREAM_CAPTURE] = 1;
++ gdma_unmask_handler(GDMA_I2S_RX0);
++ }
++ }
++
++ return 0;
++}
++
++
++static int mt76xx_pcm_hw_params(struct snd_pcm_substream *substream,
++ struct snd_pcm_hw_params *hw_params)
++{
++ /*struct snd_pcm_runtime *runtime = substream->runtime;
++ i2s_config_type *rtd = (i2s_config_type*)runtime->private_data;
++ */
++ int ret,i;
++ ret = i = 0;
++
++ //printk("******* %s *******\n", __func__);
++ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK){
++ //i2s_page_prepare(rtd,STREAM_PLAYBACK);
++ } else {
++ //i2s_page_prepare(rtd,STREAM_CAPTURE);
++ }
++
++ return ret;
++}
++
++static int mt76xx_pcm_hw_free(struct snd_pcm_substream *substream)
++{
++ i2s_config_type* rtd = (i2s_config_type*)substream->runtime->private_data;
++ //struct snd_dma_buffer *buf = &substream->dma_buffer;
++
++ //printk("******* %s *******\n", __func__);
++ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK){
++ if(rtd->dmaStat[SNDRV_PCM_STREAM_PLAYBACK]){
++
++ gdma_En_Switch(rtd,STREAM_PLAYBACK,GDMA_I2S_DIS);
++ i2s_tx_end_sleep_on(rtd);
++ tasklet_kill(&i2s_tx_tasklet);
++ i2s_tx_disable(rtd);
++ //mt76xx_pcm_free_dma_buffer(substream,substream->stream);
++ i2s_page_release(rtd,STREAM_PLAYBACK);
++ rtd->dmaStat[SNDRV_PCM_STREAM_PLAYBACK] = 0;
++ }
++ mt76xx_pcm_free_dma_buffer(substream,substream->stream);
++ }
++ else{
++ if(rtd->dmaStat[SNDRV_PCM_STREAM_CAPTURE]){
++
++ gdma_En_Switch(rtd,STREAM_CAPTURE,GDMA_I2S_DIS);
++ i2s_tx_end_sleep_on(rtd);
++ tasklet_kill(&i2s_rx_tasklet);
++ i2s_rx_disable(rtd);
++ //mt76xx_pcm_free_dma_buffer(substream,substream->stream);
++ i2s_page_release(rtd,STREAM_CAPTURE);
++ rtd->dmaStat[SNDRV_PCM_STREAM_CAPTURE] = 0;
++ }
++ mt76xx_pcm_free_dma_buffer(substream,substream->stream);
++ }
++ return 0;
++}
++
++static int mt76xx_pcm_free_dma_buffer(struct snd_pcm_substream *substream,
++ int stream)
++{
++
++ //struct snd_pcm_substream *substream = pcm->streams[stream].substream;
++ struct snd_dma_buffer *buf = &substream->dma_buffer;
++ i2s_config_type* rtd = (i2s_config_type*)substream->runtime->private_data;
++
++ //printk("******* %s *******\n", __func__);
++ if (!buf->area)
++ return 0;
++ if(substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
++ i2s_memPool_free(rtd,STREAM_PLAYBACK);
++ else
++ i2s_memPool_free(rtd,STREAM_CAPTURE);
++ buf->area = NULL;
++ snd_pcm_set_runtime_buffer(substream, NULL);
++ return 0;
++}
++
++static int mt76xx_pcm_allocate_dma_buffer(struct snd_pcm_substream *substream,
++ int stream)
++{
++ //struct snd_pcm_substream *substream = pcm->streams[stream].substream;
++ struct snd_dma_buffer *buf = &substream->dma_buffer;
++ i2s_config_type* rtd = (i2s_config_type*)substream->runtime->private_data;
++
++ //printk("******* %s *******\n", __func__);
++ if(!buf->area){
++#if defined(CONFIG_I2S_MMAP)
++ printk("\n############## MMAP ##############\n");
++ buf->dev.type = SNDRV_DMA_TYPE_DEV;
++#else
++ buf->dev.type = SNDRV_DMA_TYPE_UNKNOWN;
++#endif
++ buf->dev.dev = NULL;
++ buf->private_data = NULL;
++ if(stream == SNDRV_PCM_STREAM_PLAYBACK)
++ buf->area = i2s_memPool_Alloc(rtd,STREAM_PLAYBACK);
++ else
++ buf->area = i2s_memPool_Alloc(rtd,STREAM_CAPTURE);
++
++ if (!buf->area)
++ return -ENOMEM;
++ buf->bytes = GDMA_TOTAL_PAGE_SIZE;
++#if defined(CONFIG_I2S_MMAP)
++ buf->addr = i2s_mmap_phys_addr(rtd);
++#endif
++ snd_pcm_set_runtime_buffer(substream, buf);
++ } else{
++ //printk("Buffer have been allocated!\n");
++ }
++
++ return 0;
++}
++
++static int mt76xx_pcm_open(struct snd_pcm_substream *substream)
++{
++ struct snd_pcm_runtime *runtime= substream->runtime;
++ struct snd_dma_buffer *buf = &substream->dma_buffer;
++ int stream = substream->stream;
++ int ret = 0;
++
++ //printk("******* %s *******\n", __func__);
++ snd_soc_set_runtime_hwparams(substream, &mt76xx_pcm_hwparam);
++ /* ensure that buffer size is a multiple of period size */
++ ret = snd_pcm_hw_constraint_integer(runtime,
++ SNDRV_PCM_HW_PARAM_PERIODS);
++ if (ret < 0)
++ goto out;
++
++#if 1
++ if(stream == SNDRV_PCM_STREAM_PLAYBACK){
++ ret = mt76xx_pcm_allocate_dma_buffer(substream,
++ SNDRV_PCM_STREAM_PLAYBACK);
++ }
++ else{
++ ret = mt76xx_pcm_allocate_dma_buffer(substream,
++ SNDRV_PCM_STREAM_CAPTURE);
++ }
++#endif
++
++ if (ret)
++ goto out;
++
++ if(buf)
++ memset(buf->area,0,sizeof(I2S_PAGE_SIZE*MAX_I2S_PAGE));
++
++ out:
++ return ret;
++}
++
++
++
++static int mt76xx_pcm_new(struct snd_soc_pcm_runtime *rtd)
++{
++// int ret = 0;
++
++ //printk("******* %s *******\n", __func__);
++ return 0;
++}
++
++static void mt76xx_pcm_free(struct snd_pcm *pcm)
++{
++ /*struct snd_pcm_substream *substream;
++ struct snd_dma_buffer *buf;
++ i2s_config_type* rtd;
++ int stream;
++*/
++ //printk("******* %s *******\n", __func__);
++ //return 0;
++}
++
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,20)
++static int mt76xx_platform_drv_probe(struct platform_device *pdev)
++{
++ //printk("******* %s *******\n", __func__);
++ return snd_soc_register_platform(&pdev->dev, &mt76xx_soc_platform);
++}
++
++static int mt76xx_platform_drv_remove(struct platform_device *pdev)
++{
++ //printk("******* %s *******\n", __func__);
++ snd_soc_unregister_platform(&pdev->dev);
++ return 0;
++}
++
++static struct platform_driver mt76xx_pcm_driver = {
++ .driver = {
++ .name = "mt76xx-pcm",
++ .owner = THIS_MODULE,
++ },
++
++ .probe = mt76xx_platform_drv_probe,
++ .remove = mt76xx_platform_drv_remove,
++};
++
++static int __init mt76xx_pcm_init(void)
++{
++
++ printk("******* %s *******\n", __func__);
++ return platform_driver_register(&mt76xx_pcm_driver);
++}
++
++static void __exit mt76xx_pcm_exit(void)
++{
++ platform_driver_unregister(&mt76xx_pcm_driver);
++}
++#else
++static int __init mt76xx_pcm_init(void)
++{
++
++ printk("******* %s *******\n", __func__);
++ return snd_soc_register_platform(&mt76xx_soc_platform);
++}
++
++static void __exit mt76xx_pcm_exit(void)
++{
++ printk("******* %s *******\n", __func__);
++ snd_soc_unregister_platform(&mt76xx_soc_platform);
++}
++#endif
++module_init(mt76xx_pcm_init);
++module_exit(mt76xx_pcm_exit);
++
++MODULE_AUTHOR("Dora Chen");
++MODULE_DESCRIPTION("MTK APSoC I2S DMA driver");
++MODULE_LICENSE("GPL");
++
+diff --git a/sound/soc/mtk/ralink_gdma.c b/sound/soc/mtk/ralink_gdma.c
+new file mode 100644
+index 0000000..b385f05
+--- /dev/null
++++ b/sound/soc/mtk/ralink_gdma.c
+@@ -0,0 +1,918 @@
++/*
++ ***************************************************************************
++ * Ralink Tech Inc.
++ * 5F., No.36, Taiyuan St., Jhubei City,
++ * Hsinchu County 302,
++ * Taiwan, R.O.C.
++ *
++ * (c) Copyright, Ralink Technology, Inc.
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the
++ * Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.
++ *
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
++ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
++ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
++ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ *
++ ***************************************************************************
++ *
++ Module Name:
++ ralink_gdma.c
++
++ Abstract:
++
++ Revision History:
++ Who When What
++ -------- ---------- ----------------------------------------------
++ Name Date Modification logs
++ Steven Liu 2009-03-24 Support RT3883
++ *
++ */
++#include <linux/init.h>
++#include <linux/version.h>
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/interrupt.h>
++#include <linux/fs.h>
++#if defined (CONFIG_MIPS)
++ #include <asm/uaccess.h>
++ #include <asm/addrspace.h>
++#endif
++
++#include "ralink_gdma.h"
++
++/*
++ * RT305x:
++ * Ch0 : Pcm0_Rx0 | Pcm0_Rx0 | ALL
++ * Ch1 : Pcm0_Rx1 | Pcm0_Rx1 | ALL
++ * Ch2 : Pcm0_Tx0 | Pcm0_Tx0 | ALL
++ * Ch3 : Pcm0_Tx1 | Pcm0_Tx1 | ALL
++ * Ch4 : Pcm1_Rx0 | I2S_Tx0 | ALL
++ * Ch5 : Pcm1_Rx1 | I2S_Tx1 | ALL
++ * Ch6 : Pcm1_Tx0 | ALL | ALL
++ * Ch7 : Pcm1_Tx1 | ALL | ALL
++ *
++ * RT3883:
++ * Ch0 : Pcm0_Rx0 | Pcm0_Rx0 | ALL
++ * Ch1 : Pcm0_Rx1 | Pcm0_Rx1 | ALL
++ * Ch2 : Pcm0_Tx0 | Pcm0_Tx0 | ALL
++ * Ch3 : Pcm0_Tx1 | Pcm0_Tx1 | ALL
++ * Ch4 : Pcm1_Rx0 | I2S_Tx0 | ALL
++ * Ch5 : Pcm1_Rx1 | I2S_Tx1 | ALL
++ * Ch6 : Pcm1_Tx0 | I2S_Rx0 | ALL
++ * Ch7 : Pcm1_Tx1 | I2S_Rx1 | ALL
++ * Ch8 : ALL | ALL | ALL
++ * Ch9 : ALL | ALL | ALL
++ * Ch10 : ALL | ALL | ALL
++ * Ch11 : ALL | ALL | ALL
++ * Ch12 : ALL | ALL | ALL PCI TX
++ * Ch13 : ALL | ALL | ALL PCI RX
++ * Ch14 : ALL | ALL | ALL
++ * Ch15 : ALL | ALL | ALL
++ *
++ */
++
++spinlock_t gdma_lock;
++spinlock_t gdma_lock_mem;
++spinlock_t gdma_int_lock;
++void (*GdmaDoneIntCallback[MAX_GDMA_CHANNEL])(uint32_t);
++void (*GdmaUnMaskIntCallback[MAX_GDMA_CHANNEL])(uint32_t);
++
++
++/**
++ * @brief Get free GDMA channel
++ *
++ * @param ChNum GDMA channel number
++ * @retval 1 channel is available
++ * @retval 0 channels are all busy
++ */
++int _GdmaGetFreeCh(uint32_t *ChNum)
++{
++ unsigned long flags;
++ uint32_t Data=0;
++ uint32_t Ch=0;
++#if defined (CONFIG_GDMA_DEBUG)
++ static uint32_t Ch_RR=0;
++#endif
++
++ spin_lock_irqsave(&gdma_lock, flags);
++
++#if defined (CONFIG_GDMA_PCM_ONLY)
++#if defined (CONFIG_RALINK_RT3883) || defined (CONFIG_RALINK_RT3352) || defined (CONFIG_RALINK_RT5350) || defined (CONFIG_RALINK_RT6855) || defined (CONFIG_RALINK_RT6855A) || defined (CONFIG_RALINK_MT7620) || defined (CONFIG_RALINK_MT7621) || defined (CONFIG_RALINK_MT7628) || defined (CONFIG_ARCH_MT7623)
++ for(Ch=14; Ch<MAX_GDMA_CHANNEL;Ch++) //channel 14~max_channe, channel 0~13 be usedl
++#else
++ for(Ch=MAX_GDMA_CHANNEL; Ch<MAX_GDMA_CHANNEL;Ch++) //no free channel
++#endif
++#elif defined (CONFIG_GDMA_PCM_I2S_OTHERS)
++#if defined (CONFIG_RALINK_RT3883) || defined (CONFIG_RALINK_RT3352) || defined (CONFIG_RALINK_RT5350) || defined (CONFIG_RALINK_RT6855) || defined (CONFIG_RALINK_RT6855A) || defined (CONFIG_RALINK_MT7620) || defined (CONFIG_RALINK_MT7621) || defined (CONFIG_RALINK_MT7628) || defined (CONFIG_ARCH_MT7623)
++ for(Ch=14; Ch<MAX_GDMA_CHANNEL;Ch++) //channel 14~max_channe, channel 0~13 be usedl
++#else
++ for(Ch=6; Ch<MAX_GDMA_CHANNEL;Ch++) //channel 6~max_channel
++#endif
++#elif defined (CONFIG_GDMA_EVERYBODY)
++ for(Ch=0; Ch<MAX_GDMA_CHANNEL;Ch++) //all channel
++#elif defined (CONFIG_GDMA_DEBUG)
++ for(Ch=(Ch_RR++)%MAX_GDMA_CHANNEL; Ch<MAX_GDMA_CHANNEL;Ch++) //round robin
++#endif
++ {
++ Data=GDMA_READ_REG(GDMA_CTRL_REG(Ch));
++
++ /* hardware will reset this bit if transaction is done.
++ * It means channel is free */
++ if((Data & (0x01<<CH_EBL_OFFSET))==0) {
++ *ChNum = Ch;
++ spin_unlock_irqrestore(&gdma_lock, flags);
++ return 1; //Channel is free
++ }
++ }
++
++ spin_unlock_irqrestore(&gdma_lock, flags);
++ return 0; // Channels are all busy
++
++}
++
++/**
++ * @brief Set channel is masked
++ *
++ * When channel is masked, the GDMA transaction will stop.
++ * When GDMA controller comes back from another channel (chain feature)
++ *
++ * >> Channel Mask=0: It's strange, and turns on related bit in GDMA interrupt
++ * status register (16:23 Unmasked)
++ *
++ * >> Channel Mask=1: It'll start GDMA transation, and clear this bit.
++ *
++ * @param ChNum GDMA channel number
++ * @retval 1 success
++ * @retval 0 fail
++ */
++int GdmaMaskChannel(uint32_t ChNum)
++{
++ uint32_t Data=0;
++
++ Data=GDMA_READ_REG(GDMA_CTRL_REG1(ChNum));
++ Data |= ( 0x01 << CH_MASK_OFFSET);
++ GDMA_WRITE_REG(GDMA_CTRL_REG1(ChNum), Data);
++ GDMA_PRINT("%s: Write %0X to %X\n", __FUNCTION__, Data, GDMA_CTRL_REG1(ChNum));
++
++ return 1;
++}
++
++/**
++ * @brief Set channel is unmasked
++ *
++ * You can unmask the channel to start GDMA transaction.
++ *
++ * When GDMA controller comes back from another channel (chain feature)
++ *
++ * >> Channel Mask=0: It's strange, and turns on related bit in GDMA interrupt
++ * status register (16:23 Unmasked)
++ *
++ * >> Channel Mask=1: It'll start GDMA transation, and clear this bit.
++ *
++ * @param ChNum GDMA channel number
++ * @retval 1 success
++ * @retval 0 fail
++ */
++int GdmaUnMaskChannel(uint32_t ChNum)
++{
++ uint32_t Data=0;
++
++ Data=GDMA_READ_REG(GDMA_CTRL_REG1(ChNum));
++ Data &= ~( 0x01 << CH_MASK_OFFSET);
++ GDMA_WRITE_REG(GDMA_CTRL_REG1(ChNum), Data);
++ GDMA_PRINT("%s: Write %0X to %X\n", __FUNCTION__, Data, GDMA_CTRL_REG1(ChNum));
++
++ return 1;
++}
++
++/**
++ * @brief Insert new GDMA entry to start GDMA transaction
++ *
++ * @param ChNum GDMA channel number
++ * @retval 1 success
++ * @retval 0 fail
++ */
++int GdmaReqQuickIns(uint32_t ChNum)
++{
++ uint32_t Data=0;
++
++ //Mask Channel
++ Data = GDMA_READ_REG(GDMA_CTRL_REG1(ChNum));
++ Data |= ( 0x1 << CH_MASK_OFFSET);
++ GDMA_WRITE_REG(GDMA_CTRL_REG1(ChNum), Data);
++
++ //Channel Enable
++ Data = GDMA_READ_REG(GDMA_CTRL_REG(ChNum));
++ Data |= (0x01<<CH_EBL_OFFSET);
++ GDMA_WRITE_REG(GDMA_CTRL_REG(ChNum), Data);
++
++ return 1;
++
++}
++
++int _GdmaReqEntryIns(GdmaReqEntry *NewEntry)
++{
++ uint32_t Data=0;
++
++ GDMA_PRINT("== << GDMA Control Reg (Channel=%d) >> ===\n", NewEntry->ChNum);
++ GDMA_PRINT(" Channel Source Addr = %x \n", NewEntry->Src);
++ GDMA_PRINT(" Channel Dest Addr = %x \n", NewEntry->Dst);
++ GDMA_PRINT(" Transfer Count=%d\n", NewEntry->TransCount);
++ GDMA_PRINT(" Source DMA Req= DMA_REQ%d\n", NewEntry->SrcReqNum);
++ GDMA_PRINT(" Dest DMA Req= DMA_REQ%d\n", NewEntry->DstReqNum);
++ GDMA_PRINT(" Source Burst Mode=%s\n", NewEntry->SrcBurstMode ? "Fix" : "Inc");
++ GDMA_PRINT(" Dest Burst Mode=%s\n", NewEntry->DstBurstMode ? "Fix" : "Inc");
++ GDMA_PRINT(" Burst Size=%s\n", NewEntry->BurstSize ==0 ? "1 transfer" : \
++ NewEntry->BurstSize ==1 ? "2 transfer" :\
++ NewEntry->BurstSize ==2 ? "4 transfer" :\
++ NewEntry->BurstSize ==3 ? "8 transfer" :\
++ NewEntry->BurstSize ==4 ? "16 transfer" :\
++ "Error");
++ GDMA_PRINT(" Hardware/Software Mode = %s\n", NewEntry->SoftMode ?
++ "Soft" : "Hw");
++ GDMA_PRINT("== << GDMA Control Reg1 (Channel=%d) >> =\n", NewEntry->ChNum);
++ GDMA_PRINT("Channel Done Interrput=%s\n", (NewEntry->DoneIntCallback!=NULL) ?
++ "Enable" : "Disable");
++ GDMA_PRINT("Channel Unmasked Int=%s\n", (NewEntry->UnMaskIntCallback!=NULL) ?
++ "Enable" : "Disable");
++#if !defined (CONFIG_RALINK_RT3052) && !defined (CONFIG_RALINK_RT3883)
++ GDMA_PRINT("Coherent Interrupt =%s\n", (NewEntry->CoherentIntEbl==1)?
++ "Enable" : "Disable");
++#endif
++ GDMA_PRINT("Next Unmasked Channel=%d\n", NewEntry->NextUnMaskCh);
++ GDMA_PRINT("Channel Mask=%d\n", NewEntry->ChMask);
++ GDMA_PRINT("========================================\n");
++
++ GDMA_WRITE_REG(GDMA_SRC_REG(NewEntry->ChNum), NewEntry->Src);
++ GDMA_PRINT("SrcAddr: Write %0X to %X\n", \
++ NewEntry->Src, GDMA_SRC_REG(NewEntry->ChNum));
++
++ GDMA_WRITE_REG(GDMA_DST_REG(NewEntry->ChNum), NewEntry->Dst);
++ GDMA_PRINT("DstAddr: Write %0X to %X\n", \
++ NewEntry->Dst, GDMA_DST_REG(NewEntry->ChNum));
++
++ Data |= ( (NewEntry->NextUnMaskCh) << NEXT_UNMASK_CH_OFFSET);
++ Data |= ( NewEntry->ChMask << CH_MASK_OFFSET);
++#if !defined (CONFIG_RALINK_RT3052) && !defined (CONFIG_RALINK_RT3883)
++ Data |= ( NewEntry->CoherentIntEbl << COHERENT_INT_EBL_OFFSET);
++#endif
++
++ if(NewEntry->UnMaskIntCallback!=NULL) {
++ Data |= (0x01<<CH_UNMASKINT_EBL_OFFSET);
++ GdmaUnMaskIntCallback[NewEntry->ChNum] = NewEntry->UnMaskIntCallback;
++ }
++
++#if defined (CONFIG_RALINK_RT3883) || defined (CONFIG_RALINK_RT3352) || defined (CONFIG_RALINK_RT5350) || defined (CONFIG_RALINK_RT6855) || defined (CONFIG_RALINK_RT6855A) || defined (CONFIG_RALINK_MT7620) || defined (CONFIG_RALINK_MT7621) || defined (CONFIG_RALINK_MT7628) || defined (CONFIG_ARCH_MT7623)
++ Data |= (NewEntry->SrcReqNum << SRC_DMA_REQ_OFFSET);
++ Data |= (NewEntry->DstReqNum << DST_DMA_REQ_OFFSET);
++#endif
++
++ GDMA_WRITE_REG(GDMA_CTRL_REG1(NewEntry->ChNum), Data);
++ GDMA_PRINT("CTRL1: Write %08X to %8X\n", Data, GDMA_CTRL_REG1(NewEntry->ChNum));
++
++ Data = ((NewEntry->TransCount) << TRANS_CNT_OFFSET);
++#if defined (CONFIG_RALINK_RT3052)
++ Data |= (NewEntry->SrcReqNum << SRC_DMA_REQ_OFFSET);
++ Data |= (NewEntry->DstReqNum << DST_DMA_REQ_OFFSET);
++#endif
++ Data |= (NewEntry->SrcBurstMode << SRC_BRST_MODE_OFFSET);
++ Data |= (NewEntry->DstBurstMode << DST_BRST_MODE_OFFSET);
++ Data |= (NewEntry->BurstSize << BRST_SIZE_OFFSET);
++
++ if(NewEntry->DoneIntCallback!=NULL) {
++ Data |= (0x01<<CH_DONEINT_EBL_OFFSET);
++ GdmaDoneIntCallback[NewEntry->ChNum] = NewEntry->DoneIntCallback;
++ }
++
++ if(NewEntry->SoftMode) {
++ Data |= (0x01<<MODE_SEL_OFFSET);
++ }
++
++ Data |= (0x01<<CH_EBL_OFFSET);
++ GDMA_WRITE_REG(GDMA_CTRL_REG(NewEntry->ChNum), Data);
++ //GDMA_READ_REG(GDMA_CTRL_REG(NewEntry->ChNum));
++ GDMA_PRINT("CTRL: Write %08X to %8X\n", Data, GDMA_CTRL_REG(NewEntry->ChNum));
++ //if there is no interrupt handler, this function will
++ //return 1 until GDMA done.
++ if(NewEntry->DoneIntCallback==NULL) {
++ //wait for GDMA processing done
++#if defined (CONFIG_RALINK_RT3052)
++ while((GDMA_READ_REG(RALINK_GDMAISTS) &
++ (0x1<<NewEntry->ChNum))==0);
++ //write 1 clear
++ GDMA_WRITE_REG(RALINK_GDMAISTS, 1<< NewEntry->ChNum);
++#elif defined (CONFIG_RALINK_RT3883) || defined (CONFIG_RALINK_RT3352) || defined (CONFIG_RALINK_RT5350) || defined (CONFIG_RALINK_RT6855) || defined (CONFIG_RALINK_RT6855A) || defined (CONFIG_RALINK_MT7620) || defined (CONFIG_RALINK_MT7621) || defined (CONFIG_RALINK_MT7628) || defined (CONFIG_ARCH_MT7623)
++ while((GDMA_READ_REG(RALINK_GDMA_DONEINT) &
++ (0x1<<NewEntry->ChNum))==0);
++ //write 1 clear
++ GDMA_WRITE_REG(RALINK_GDMA_DONEINT, 1<< NewEntry->ChNum);
++#endif
++ }
++
++ return 1;
++
++}
++
++#if defined(CONFIG_RALINK_MT7620) || defined (CONFIG_RALINK_MT7621) || defined (CONFIG_RALINK_MT7628) || defined (CONFIG_ARCH_MT7623)
++/**
++ * @brief Start GDMA transaction for sending data to SPI
++ *
++ * @param *Src source address
++ * @param *Dst destination address
++
++ * @param TransCount data length
++ * @param *DoneIntCallback callback function when transcation is done
++ * @param *UnMaskIntCallback callback func when ch mask field is incorrect
++ * @retval 1 success
++ * @retval 0 fail
++ */
++int GdmaSpiTx(
++ uint32_t Src,
++ uint32_t Dst,
++ uint16_t TransCount,
++ void (*DoneIntCallback)(uint32_t data),
++ void (*UnMaskIntCallback)(uint32_t data)
++ )
++{
++ GdmaReqEntry Entry;
++
++ #if defined (CONFIG_MIPS)
++ Entry.Src= (Src & 0x1FFFFFFF);
++ Entry.Dst= (Dst & 0x1FFFFFFF);
++ #else
++ Entry.Src= Src;
++ Entry.Dst= Dst;
++ #endif
++ Entry.TransCount = TransCount;
++ Entry.SrcBurstMode=INC_MODE;
++ Entry.DstBurstMode=FIX_MODE;
++ Entry.BurstSize=BUSTER_SIZE_4B;
++ Entry.SrcReqNum=DMA_MEM_REQ;
++ Entry.DstReqNum=DMA_SPI_TX_REQ;
++ Entry.DoneIntCallback=DoneIntCallback;
++ Entry.UnMaskIntCallback=UnMaskIntCallback;
++ Entry.SoftMode=0;
++ Entry.ChMask=0;
++ Entry.CoherentIntEbl=0;
++
++ //enable chain feature
++ Entry.ChNum = GDMA_SPI_TX;
++ Entry.NextUnMaskCh = GDMA_SPI_TX;
++
++ return _GdmaReqEntryIns(&Entry);
++}
++
++int GdmaSpiRx(
++ uint32_t Src,
++ uint32_t Dst,
++ uint16_t TransCount,
++ void (*DoneIntCallback)(uint32_t data),
++ void (*UnMaskIntCallback)(uint32_t data)
++ )
++{
++ GdmaReqEntry Entry;
++
++ #if defined (CONFIG_MIPS)
++ Entry.Src= (Src & 0x1FFFFFFF);
++ Entry.Dst= (Dst & 0x1FFFFFFF);
++ #else
++ Entry.Src= Src;
++ Entry.Dst= Dst;
++ #endif
++ Entry.TransCount = TransCount;
++ Entry.SrcBurstMode=FIX_MODE;
++ Entry.DstBurstMode=INC_MODE;
++ Entry.BurstSize=BUSTER_SIZE_4B;
++ Entry.SrcReqNum=DMA_SPI_RX_REQ;
++ Entry.DstReqNum=DMA_MEM_REQ;
++ Entry.DoneIntCallback=DoneIntCallback;
++ Entry.UnMaskIntCallback=UnMaskIntCallback;
++ Entry.SoftMode=0;
++ Entry.ChMask=0;
++ Entry.CoherentIntEbl=1;
++
++
++ //enable chain feature
++ Entry.ChNum=GDMA_SPI_RX;
++ Entry.NextUnMaskCh=GDMA_SPI_RX;
++
++
++ return _GdmaReqEntryIns(&Entry);
++
++}
++#endif
++
++
++/**
++ * @brief Start GDMA transaction for sending data to I2S
++ *
++ * @param *Src source address
++ * @param *Dst destination address
++ * @param TxNo I2S Tx number
++ * @param TransCount data length
++ * @param *DoneIntCallback callback function when transcation is done
++ * @param *UnMaskIntCallback callback func when ch mask field is incorrect
++ * @retval 1 success
++ * @retval 0 fail
++ */
++int GdmaI2sTx(
++ uint32_t Src,
++ uint32_t Dst,
++ uint8_t TxNo,
++ uint16_t TransCount,
++ void (*DoneIntCallback)(uint32_t data),
++ void (*UnMaskIntCallback)(uint32_t data)
++ )
++{
++ GdmaReqEntry Entry;
++
++ #if defined (CONFIG_MIPS)
++ Entry.Src= (Src & 0x1FFFFFFF);
++ Entry.Dst= (Dst & 0x1FFFFFFF);
++ #else
++ Entry.Src= Src;
++ Entry.Dst= Dst;
++ #endif
++ Entry.TransCount = TransCount;
++ Entry.SrcBurstMode=INC_MODE;
++ Entry.DstBurstMode=FIX_MODE;
++ Entry.BurstSize=BUSTER_SIZE_4B;
++ Entry.SrcReqNum=DMA_MEM_REQ;
++ Entry.DstReqNum=DMA_I2S_TX_REQ;
++ Entry.DoneIntCallback=DoneIntCallback;
++ Entry.UnMaskIntCallback=UnMaskIntCallback;
++ Entry.SoftMode=0;
++ Entry.ChMask=1;
++ Entry.CoherentIntEbl=0;
++
++ if(TxNo==0) { //TX0
++ //enable chain feature
++ Entry.ChNum=GDMA_I2S_TX0;
++ Entry.NextUnMaskCh= (TransCount==4) ? GDMA_I2S_TX0 : GDMA_I2S_TX1;
++ }else if(TxNo==1) { //TX1
++ //enable chain feature
++ Entry.ChNum=GDMA_I2S_TX1;
++ Entry.NextUnMaskCh= (TransCount==4) ? GDMA_I2S_TX1 : GDMA_I2S_TX0;
++ }else {
++ GDMA_PRINT("I2S Tx Number %x is invalid\n", TxNo);
++ return 0;
++ }
++
++ return _GdmaReqEntryIns(&Entry);
++
++}
++
++
++#if defined (CONFIG_RALINK_RT3883) || defined (CONFIG_RALINK_RT3352) || defined (CONFIG_RALINK_RT5350) || defined (CONFIG_RALINK_RT6855) || defined (CONFIG_RALINK_RT6855A) || defined (CONFIG_RALINK_MT7620) || defined (CONFIG_RALINK_MT7621) || defined (CONFIG_RALINK_MT7628) || defined (CONFIG_ARCH_MT7623)
++/**
++ * @brief Start GDMA transaction for receiving data to I2S
++ *
++ * @param *Src source address
++ * @param *Dst destination address
++ * @param TxNo I2S Tx number
++ * @param TransCount data length
++ * @param *DoneIntCallback callback function when transcation is done
++ * @param *UnMaskIntCallback callback func when ch mask field is incorrect
++ * @retval 1 success
++ * @retval 0 fail
++ */
++int GdmaI2sRx(
++ uint32_t Src,
++ uint32_t Dst,
++ uint8_t RxNo,
++ uint16_t TransCount,
++ void (*DoneIntCallback)(uint32_t data),
++ void (*UnMaskIntCallback)(uint32_t data)
++ )
++{
++ GdmaReqEntry Entry;
++ #if defined (CONFIG_MIPS)
++ Entry.Src= (Src & 0x1FFFFFFF);
++ Entry.Dst= (Dst & 0x1FFFFFFF);
++ #else
++ Entry.Src= Src;
++ Entry.Dst= Dst;
++ #endif
++ Entry.TransCount = TransCount;
++ Entry.SrcBurstMode=FIX_MODE;
++ Entry.DstBurstMode=INC_MODE;
++ Entry.BurstSize=BUSTER_SIZE_4B;
++ Entry.SrcReqNum=DMA_I2S_RX_REQ;
++ Entry.DstReqNum=DMA_MEM_REQ;
++ Entry.DoneIntCallback=DoneIntCallback;
++ Entry.UnMaskIntCallback=UnMaskIntCallback;
++ Entry.SoftMode=0;
++ Entry.ChMask=1;
++ Entry.CoherentIntEbl=1;
++
++ if(RxNo==0) { //RX0
++ //enable chain feature
++ Entry.ChNum=GDMA_I2S_RX0;
++ Entry.NextUnMaskCh=(TransCount==4) ? GDMA_I2S_RX0 : GDMA_I2S_RX1;
++ }else if(RxNo==1) { //RX1
++ //enable chain feature
++ Entry.ChNum=GDMA_I2S_RX1;
++ Entry.NextUnMaskCh=(TransCount==4) ? GDMA_I2S_RX1 : GDMA_I2S_RX0;
++ }else {
++ GDMA_PRINT("I2S Rx Number %x is invalid\n", RxNo);
++ return 0;
++ }
++
++ return _GdmaReqEntryIns(&Entry);
++
++}
++
++#endif
++
++/**
++ * @brief Start GDMA transaction for receiving data from PCM
++ *
++ * @param *Src source address
++ * @param *Dst destination address
++ * @param TransCount data length
++ * @param PcmNo PCM channel
++ * @param RxNo PCM Rx number
++ * @param *DoneIntCallback callback function when transcation is done
++ * @param *UnMaskIntCallback callback func when ch mask field is incorrect
++ * @retval 1 success
++ * @retval 0 fail
++ */
++int GdmaPcmRx(
++ uint32_t Src,
++ uint32_t Dst,
++ uint8_t PcmNo,
++ uint8_t RxNo,
++ uint16_t TransCount,
++ void (*DoneIntCallback)(uint32_t data),
++ void (*UnMaskIntCallback)(uint32_t data)
++ )
++{
++ GdmaReqEntry Entry;
++
++ #if defined (CONFIG_MIPS)
++ Entry.Src= (Src & 0x1FFFFFFF);
++ Entry.Dst= (Dst & 0x1FFFFFFF);
++ #else
++ Entry.Src= Src;
++ Entry.Dst= Dst;
++ #endif
++ Entry.TransCount = TransCount;
++ Entry.SrcBurstMode=FIX_MODE;
++ Entry.DstBurstMode=INC_MODE;
++ Entry.BurstSize=BUSTER_SIZE_4B;
++ Entry.DstReqNum=DMA_MEM_REQ;
++ Entry.DoneIntCallback=DoneIntCallback;
++ Entry.UnMaskIntCallback=UnMaskIntCallback;
++ Entry.SoftMode=0;
++ Entry.ChMask=1;
++ Entry.CoherentIntEbl=1;
++
++ if(RxNo > 2) {
++ GDMA_PRINT("PCM Rx Number %x is invalid\n", RxNo);
++ return 0;
++ }
++
++ switch(PcmNo)
++ {
++ case 0:
++ Entry.SrcReqNum=DMA_PCM_RX0_REQ;
++ break;
++ case 1:
++ Entry.SrcReqNum=DMA_PCM_RX1_REQ;
++ break;
++#if defined(CONFIG_RALINK_MT7620) || defined (CONFIG_RALINK_MT7621) || defined (CONFIG_RALINK_MT7628) || defined (CONFIG_ARCH_MT7623)
++ case 2:
++ Entry.SrcReqNum=DMA_PCM_RX2_REQ;
++ break;
++ case 3:
++ Entry.SrcReqNum=DMA_PCM_RX3_REQ;
++ break;
++#endif
++ default:
++ GDMA_PRINT("PCM Channel %x is invalid\n", PcmNo);
++ return 0;
++ }
++ Entry.ChNum=GDMA_PCM_RX(PcmNo,RxNo);
++ Entry.NextUnMaskCh=GDMA_PCM_RX(PcmNo,1-RxNo);
++
++ return _GdmaReqEntryIns(&Entry);
++
++}
++
++/**
++ * @brief Start GDMA transaction for sending data to PCM
++ *
++ * @param *Src source address
++ * @param *Dst destination address
++ * @param TransCount data length
++ * @param PcmNo PCM channel
++ * @param TxNo PCM Tx number
++ * @param *DoneIntCallback callback func when transcation is done
++ * @param *UnMaskIntCallback callback func when ch mask field is incorrect
++ * @retval 1 success
++ * @retval 0 fail
++ */
++int GdmaPcmTx(
++ uint32_t Src,
++ uint32_t Dst,
++ uint8_t PcmNo,
++ uint8_t TxNo,
++ uint16_t TransCount,
++ void (*DoneIntCallback)(uint32_t data),
++ void (*UnMaskIntCallback)(uint32_t data)
++ )
++{
++ GdmaReqEntry Entry;
++
++ #if defined (CONFIG_MIPS)
++ Entry.Src= (Src & 0x1FFFFFFF);
++ Entry.Dst= (Dst & 0x1FFFFFFF);
++ #else
++ Entry.Src= Src;
++ Entry.Dst= Dst;
++ #endif
++ Entry.TransCount = TransCount;
++ Entry.SrcBurstMode=INC_MODE;
++ Entry.DstBurstMode=FIX_MODE;
++ Entry.BurstSize=BUSTER_SIZE_4B;
++ Entry.SrcReqNum=DMA_MEM_REQ;
++ Entry.DoneIntCallback=DoneIntCallback;
++ Entry.UnMaskIntCallback=UnMaskIntCallback;
++ Entry.SoftMode=0; //Hardware Mode
++ Entry.ChMask=1;
++ Entry.CoherentIntEbl=0;
++
++ if(TxNo > 2) {
++ GDMA_PRINT("PCM Tx Number %x is invalid\n", TxNo);
++ return 0;
++ }
++ switch(PcmNo)
++ {
++ case 0:
++ Entry.DstReqNum=DMA_PCM_TX0_REQ;
++ break;
++ case 1:
++ Entry.DstReqNum=DMA_PCM_TX1_REQ;
++ break;
++#if defined(CONFIG_RALINK_MT7620) || defined (CONFIG_RALINK_MT7621) || defined (CONFIG_RALINK_MT7628) || defined (CONFIG_ARCH_MT7623)
++ case 2:
++ Entry.DstReqNum=DMA_PCM_TX2_REQ;
++ break;
++ case 3:
++ Entry.DstReqNum=DMA_PCM_TX3_REQ;
++ break;
++#endif
++ default:
++ GDMA_PRINT("PCM Channel %x is invalid\n", PcmNo);
++ return 0;
++ }
++ Entry.ChNum=GDMA_PCM_TX(PcmNo,TxNo);
++ Entry.NextUnMaskCh=GDMA_PCM_TX(PcmNo,1-TxNo);
++
++ return _GdmaReqEntryIns(&Entry);
++
++}
++
++
++/**
++ * @brief Start GDMA transaction for memory to memory copy
++ *
++ * @param *Src source address
++ * @param *Dst destination address
++ * @param TransCount data length
++ * @param *DoneIntCallback callback function when transcation is done
++ * @retval 1 success
++ * @retval 0 fail
++ */
++int GdmaMem2Mem(
++ uint32_t Src,
++ uint32_t Dst,
++ uint16_t TransCount,
++ void (*DoneIntCallback)(uint32_t data)
++ )
++
++{
++
++ GdmaReqEntry Entry;
++ #if defined (CONFIG_MIPS)
++ Entry.Src= (Src & 0x1FFFFFFF);
++ Entry.Dst= (Dst & 0x1FFFFFFF);
++ #else
++ Entry.Src= Src;
++ Entry.Dst= Dst;
++ #endif
++
++ //Entry.Src= virt_to_phys(Src);
++ //Entry.Dst= virt_to_phys(Dst);
++
++
++
++ Entry.TransCount = TransCount;
++ Entry.SrcBurstMode=INC_MODE;
++ Entry.DstBurstMode=INC_MODE;
++ Entry.BurstSize=BUSTER_SIZE_64B;
++ Entry.SrcReqNum=DMA_MEM_REQ;
++ Entry.DstReqNum=DMA_MEM_REQ;
++ Entry.DoneIntCallback=DoneIntCallback;
++ Entry.UnMaskIntCallback=NULL;
++ Entry.SoftMode=1;
++ Entry.ChMask=0;
++
++ Entry.CoherentIntEbl=1;
++
++ //No reserved channel for Memory to Memory GDMA,
++ //get free channel on demand
++ if(!_GdmaGetFreeCh(&Entry.ChNum)) {
++ GDMA_PRINT("GDMA Channels are all busy\n");
++ return 0;
++ }
++
++
++ //set next channel to their own channel
++ //to disable chain feature
++ Entry.NextUnMaskCh= Entry.ChNum;
++ //printk ("ChNum = %d\n", Entry.ChNum);
++ //set next channel to another channel
++ //to enable chain feature
++ //Entry.NextUnMaskCh= (Entry.ChNum+1) % MAX_GDMA_CHANNEL;
++
++ return _GdmaReqEntryIns(&Entry);
++
++
++}
++
++/**
++ * @brief GDMA interrupt handler
++ *
++ * When GDMA transcation is done, call related handler
++ * to do the remain job.
++ *
++ */
++irqreturn_t GdmaIrqHandler(
++ int irq,
++ void *irqaction
++ )
++{
++
++ u32 Ch=0;
++ unsigned long flags;
++#if defined (CONFIG_RALINK_RT3052)
++ u32 GdmaUnMaskStatus=GDMA_READ_REG(RALINK_GDMAISTS) & 0xFF0000;
++ u32 GdmaDoneStatus=GDMA_READ_REG(RALINK_GDMAISTS) & 0xFF;
++#elif defined (CONFIG_RALINK_RT3883) || defined (CONFIG_RALINK_RT3352) || defined (CONFIG_RALINK_RT5350) || defined (CONFIG_RALINK_RT6855) || defined (CONFIG_RALINK_RT6855A) || defined (CONFIG_RALINK_MT7620) || defined (CONFIG_RALINK_MT7621) || defined (CONFIG_RALINK_MT7628) || defined (CONFIG_ARCH_MT7623)
++ u32 GdmaUnMaskStatus=GDMA_READ_REG(RALINK_GDMA_UNMASKINT);
++ u32 GdmaDoneStatus=GDMA_READ_REG(RALINK_GDMA_DONEINT);
++#endif
++ //printk("********GDMA Interrupt*******************\n");
++
++ //GDMA_PRINT("========================================\n");
++ //GDMA_PRINT("GdmaUnMask Interrupt=%x\n",GdmaUnMaskStatus);
++ //GDMA_PRINT("GdmaDone Interrupt=%x\n",GdmaDoneStatus);
++ //GDMA_PRINT("========================================\n");
++
++ spin_lock_irqsave(&gdma_int_lock, flags);
++
++ //write 1 clear
++#if defined (CONFIG_RALINK_RT3052)
++ GDMA_WRITE_REG(RALINK_GDMAISTS, GdmaUnMaskStatus);
++#elif defined (CONFIG_RALINK_RT3883) || defined (CONFIG_RALINK_RT3352) || defined (CONFIG_RALINK_RT5350) || defined (CONFIG_RALINK_RT6855) || defined (CONFIG_RALINK_RT6855A) || defined (CONFIG_RALINK_MT7620) || defined (CONFIG_RALINK_MT7621) || defined (CONFIG_RALINK_MT7628) || defined (CONFIG_ARCH_MT7623)
++ GDMA_WRITE_REG(RALINK_GDMA_UNMASKINT, GdmaUnMaskStatus);
++#endif
++
++ //UnMask error
++ for(Ch=0;Ch<MAX_GDMA_CHANNEL;Ch++) {
++
++ if(GdmaUnMaskStatus & (0x1 << (UNMASK_INT_STATUS(Ch))) ) {
++ if(GdmaUnMaskIntCallback[Ch] != NULL) {
++ GdmaUnMaskIntCallback[Ch](Ch);
++ // printk("GdmaUnMaskIntCallback \n");
++ }
++ }
++ }
++
++ //write 1 clear
++#if defined (CONFIG_RALINK_RT3052)
++ GDMA_WRITE_REG(RALINK_GDMAISTS, GdmaDoneStatus);
++#elif defined (CONFIG_RALINK_RT3883) || defined (CONFIG_RALINK_RT3352) || defined (CONFIG_RALINK_RT5350) || defined (CONFIG_RALINK_RT6855) || defined (CONFIG_RALINK_RT6855A) || defined (CONFIG_RALINK_MT7620) || defined (CONFIG_RALINK_MT7621) || defined (CONFIG_RALINK_MT7628) || defined (CONFIG_ARCH_MT7623)
++ GDMA_WRITE_REG(RALINK_GDMA_DONEINT, GdmaDoneStatus);
++#endif
++
++ //printk("interrupt status = %x \n", GdmaDoneStatus);
++ //processing done
++ for(Ch=0;Ch<MAX_GDMA_CHANNEL;Ch++) {
++ if(GdmaDoneStatus & (0x1<<Ch)) {
++ if(GdmaDoneIntCallback[Ch] != NULL) {
++ //printk("*************Interrupt Ch=%d***********\n", Ch);
++ GdmaDoneIntCallback[Ch](Ch);
++ }
++ }
++ }
++
++//printk("interrupt status clear = %x \n", GDMA_READ_REG(RALINK_GDMA_DONEINT));
++ spin_unlock_irqrestore(&gdma_int_lock, flags);
++
++ return IRQ_HANDLED;
++
++}
++
++static int RalinkGdmaInit(void)
++{
++
++ uint32_t Ret=0;
++ uint32_t val = 0;
++ printk("Enable Ralink GDMA Controller Module \n");
++#if defined (CONFIG_RALINK_RT3883) || defined (CONFIG_RALINK_RT3352) || defined (CONFIG_RALINK_RT5350) || defined (CONFIG_RALINK_RT6855) || defined (CONFIG_RALINK_RT6855A) || defined (CONFIG_RALINK_MT7620) || defined (CONFIG_RALINK_MT7621) || defined (CONFIG_RALINK_MT7628) || defined (CONFIG_ARCH_MT7623)
++ printk("GDMA IP Version=%d\n", GET_GDMA_IP_VER);
++#endif
++spin_lock_init(&gdma_int_lock);
++spin_lock_init(&gdma_lock);
++//spin_lock_init(&gdma_lock_mem);
++
++#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,35)
++ #if defined (CONFIG_MIPS)
++ Ret = request_irq(SURFBOARDINT_DMA, GdmaIrqHandler, \
++ IRQF_DISABLED, "Ralink_DMA", NULL);
++ #else
++ Ret = request_irq(SURFBOARDINT_DMA, GdmaIrqHandler, \
++ IRQF_TRIGGER_LOW, "Ralink_DMA", NULL);
++ #endif
++#else
++ Ret = request_irq(SURFBOARDINT_DMA, GdmaIrqHandler, \
++ SA_INTERRUPT, "Ralink_DMA", NULL);
++#endif
++
++/*
++ Ret = request_irq(131, GdmaIrqHandler, \
++ IRQF_TRIGGER_LOW, "Ralink_DMA", NULL);
++ */
++ if(Ret){
++ GDMA_PRINT("IRQ %d is not free.\n", SURFBOARDINT_DMA);
++ return 1;
++ }
++
++#if defined (CONFIG_MIPS)
++ //Enable GDMA interrupt
++ val = le32_to_cpu(*(volatile u32 *)(RALINK_REG_INTENA));
++ val |= RALINK_INTCTL_DMA;
++ GDMA_WRITE_REG(RALINK_REG_INTENA, val);
++#endif
++
++ //Channel0~Channel7 are round-robin
++#if defined (CONFIG_RALINK_RT3052)
++ GDMA_WRITE_REG(RALINK_GDMAGCT, 0x01);
++#elif defined (CONFIG_RALINK_RT3883) || defined (CONFIG_RALINK_RT3352) || defined (CONFIG_RALINK_RT5350) || defined (CONFIG_RALINK_RT6855) || defined (CONFIG_RALINK_RT6855A) || defined (CONFIG_RALINK_MT7620) || defined (CONFIG_RALINK_MT7621) || defined (CONFIG_RALINK_MT7628) || defined (CONFIG_ARCH_MT7623)
++ GDMA_WRITE_REG(RALINK_GDMA_GCT, 0x01);
++#else
++#error Please Choose System Type
++#endif
++
++ return 0;
++}
++
++static void __exit RalinkGdmaExit(void)
++{
++
++ printk("Disable Ralink GDMA Controller Module\n");
++#if defined (CONFIG_MIPS)
++ //Disable GDMA interrupt
++ GDMA_WRITE_REG(RALINK_REG_INTDIS, RALINK_INTCTL_DMA);
++#endif
++ free_irq(SURFBOARDINT_DMA, NULL);
++}
++
++module_init(RalinkGdmaInit);
++module_exit(RalinkGdmaExit);
++
++EXPORT_SYMBOL(GdmaI2sRx);
++EXPORT_SYMBOL(GdmaI2sTx);
++EXPORT_SYMBOL(GdmaPcmRx);
++EXPORT_SYMBOL(GdmaPcmTx);
++#if defined(CONFIG_RALINK_MT7620) || defined (CONFIG_RALINK_MT7621) || defined (CONFIG_RALINK_MT7628) || defined (CONFIG_ARCH_MT7623)
++EXPORT_SYMBOL(GdmaSpiRx);
++EXPORT_SYMBOL(GdmaSpiTx);
++#endif
++EXPORT_SYMBOL(GdmaMem2Mem);
++EXPORT_SYMBOL(GdmaReqQuickIns);
++EXPORT_SYMBOL(GdmaMaskChannel);
++EXPORT_SYMBOL(GdmaUnMaskChannel);
++
++
++MODULE_DESCRIPTION("Ralink SoC GDMA Controller API Module");
++MODULE_AUTHOR("Steven Liu <steven_liu@ralinktech.com.tw>");
++MODULE_LICENSE("GPL");
++MODULE_VERSION(MOD_VERSION);
+diff --git a/sound/soc/mtk/ralink_gdma.h b/sound/soc/mtk/ralink_gdma.h
+new file mode 100644
+index 0000000..95ce5f7
+--- /dev/null
++++ b/sound/soc/mtk/ralink_gdma.h
+@@ -0,0 +1,326 @@
++/*
++ ***************************************************************************
++ * Ralink Tech Inc.
++ * 5F., No.36, Taiyuan St., Jhubei City,
++ * Hsinchu County 302,
++ * Taiwan, R.O.C.
++ *
++ * (c) Copyright, Ralink Technology, Inc.
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the
++ * Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.
++ *
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
++ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
++ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
++ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ *
++ ***************************************************************************
++ */
++
++#ifndef __RALINK_DMA_CTRL_H__
++#define __RALINK_DMA_CTRL_H__
++
++//#include <asm/rt2880/rt_mmap.h>
++
++/*
++ * DEFINITIONS AND MACROS
++ */
++#define MOD_VERSION "0.4"
++
++#if defined (CONFIG_RALINK_MT7621) || defined (CONFIG_ARCH_MT7623)
++#define MAX_GDMA_CHANNEL 16
++#elif defined (CONFIG_RALINK_RT3052)
++#define MAX_GDMA_CHANNEL 8
++#elif defined (CONFIG_RALINK_RT3883) || defined (CONFIG_RALINK_RT3352) || defined (CONFIG_RALINK_RT5350) || defined (CONFIG_RALINK_RT6855) || defined (CONFIG_RALINK_RT6855A) || defined (CONFIG_RALINK_MT7620) || defined (CONFIG_RALINK_MT7628)
++#define MAX_GDMA_CHANNEL 16
++#else
++#error Please Choose System Type
++#endif
++
++
++#define RALINK_GDMA_CTRL_BASE (RALINK_GDMA_BASE)
++#if defined (CONFIG_RALINK_RT3052)
++#define RALINK_GDMAISTS (RALINK_GDMA_BASE + 0x80)
++#define RALINK_GDMAGCT (RALINK_GDMA_BASE + 0x88)
++#elif defined (CONFIG_RALINK_RT3883) || defined (CONFIG_RALINK_RT3352) || defined (CONFIG_RALINK_RT5350) || defined (CONFIG_RALINK_RT6855) || defined (CONFIG_RALINK_RT6855A) || defined (CONFIG_RALINK_MT7620) || defined (CONFIG_RALINK_MT7621) || defined (CONFIG_RALINK_MT7628) || defined (CONFIG_ARCH_MT7623)
++#define RALINK_GDMA_UNMASKINT (RALINK_GDMA_BASE + 0x200)
++#define RALINK_GDMA_DONEINT (RALINK_GDMA_BASE + 0x204)
++#define RALINK_GDMA_GCT (RALINK_GDMA_BASE + 0x220)
++#endif
++
++#define KSEG1 0xa0000000
++#define PHYS_TO_VIRT(x) ((void *)((x) | KSEG1))
++#define VIRT_TO_PHYS(x) ((unsigned long)(x) & ~KSEG1)
++
++
++
++
++#if defined (CONFIG_ARCH_MT7623)
++#include <mach/sync_write.h>
++#define GDMA_READ_REG(phys) (*(volatile unsigned int *)((phys)))
++#define GDMA_WRITE_REG(phys, val) mt65xx_reg_sync_writel((val), (phys))
++
++#else
++#define GDMA_READ_REG(addr) (le32_to_cpu(*(volatile u32 *)(addr)))
++#define GDMA_WRITE_REG(addr, val) *((volatile uint32_t *)(addr)) = cpu_to_le32(val)
++
++
++
++#endif
++
++
++#define GET_GDMA_IP_VER (GDMA_READ_REG(RALINK_GDMA_GCT) & 0x6) >> 1 //GDMA_GCT[2:1]
++
++#define RALINK_IRQ_ADDR RALINK_INTCL_BASE
++#if defined (CONFIG_RALINK_MT7621) || defined (CONFIG_ARCH_MT7628)
++#define RALINK_REG_INTENA (RALINK_IRQ_ADDR + 0x80)
++#define RALINK_REG_INTDIS (RALINK_IRQ_ADDR + 0x78)
++#else
++#define RALINK_REG_INTENA (RALINK_IRQ_ADDR + 0x34)
++#define RALINK_REG_INTDIS (RALINK_IRQ_ADDR + 0x38)
++#endif
++
++/*
++ * 12bytes=GDMA Channel n Source Address(4) +
++ * GDMA Channel n Destination Address(4) +
++ * GDMA Channel n Control Register(4)
++ *
++ */
++#define GDMA_SRC_REG(ch) (RALINK_GDMA_BASE + ch*16)
++#define GDMA_DST_REG(ch) (GDMA_SRC_REG(ch) + 4)
++#define GDMA_CTRL_REG(ch) (GDMA_DST_REG(ch) + 4)
++#define GDMA_CTRL_REG1(ch) (GDMA_CTRL_REG(ch) + 4)
++
++//GDMA Interrupt Status Register
++#if defined (CONFIG_RALINK_RT3052)
++#define UNMASK_INT_STATUS(ch) (ch+16)
++#elif defined (CONFIG_RALINK_RT3883) || defined (CONFIG_RALINK_RT3352) || defined (CONFIG_RALINK_RT5350) || defined (CONFIG_RALINK_RT6855) || defined (CONFIG_RALINK_RT6855A) || defined (CONFIG_RALINK_MT7620) || defined (CONFIG_RALINK_MT7621) || defined (CONFIG_RALINK_MT7628) || defined (CONFIG_ARCH_MT7623)
++#define UNMASK_INT_STATUS(ch) (ch)
++#endif
++#define TXDONE_INT_STATUS(ch) (ch)
++
++//Control Reg0
++#define MODE_SEL_OFFSET 0
++#define CH_EBL_OFFSET 1
++#define CH_DONEINT_EBL_OFFSET 2
++#define BRST_SIZE_OFFSET 3
++#define DST_BRST_MODE_OFFSET 6
++#define SRC_BRST_MODE_OFFSET 7
++#define TRANS_CNT_OFFSET 16
++
++//Control Reg1
++#if defined (CONFIG_RALINK_RT3052)
++#define CH_UNMASKINT_EBL_OFFSET 4
++#define NEXT_UNMASK_CH_OFFSET 1
++#elif defined (CONFIG_RALINK_RT3883) || defined (CONFIG_RALINK_RT3352) || defined (CONFIG_RALINK_RT5350) || defined (CONFIG_RALINK_RT6855) || defined (CONFIG_RALINK_RT6855A) || defined (CONFIG_RALINK_MT7620) || defined (CONFIG_RALINK_MT7621) || defined (CONFIG_RALINK_MT7628) || defined (CONFIG_ARCH_MT7623)
++#define CH_UNMASKINT_EBL_OFFSET 1
++#define NEXT_UNMASK_CH_OFFSET 3
++#endif
++#define COHERENT_INT_EBL_OFFSET 2
++#define CH_MASK_OFFSET 0
++
++
++#if defined (CONFIG_RALINK_RT3052)
++//Control Reg0
++#define DST_DMA_REQ_OFFSET 8
++#define SRC_DMA_REQ_OFFSET 12
++#elif defined (CONFIG_RALINK_RT3883) || defined (CONFIG_RALINK_RT3352) || defined (CONFIG_RALINK_RT5350) || defined (CONFIG_RALINK_RT6855) || defined (CONFIG_RALINK_RT6855A) || defined (CONFIG_RALINK_MT7620) || defined (CONFIG_RALINK_MT7621) || defined (CONFIG_RALINK_MT7628) || defined (CONFIG_ARCH_MT7623)
++//Control Reg1
++#define DST_DMA_REQ_OFFSET 8
++#define SRC_DMA_REQ_OFFSET 16
++#endif
++
++#define GDMA_PCM0_RX0 0
++#define GDMA_PCM0_RX1 1
++#define GDMA_PCM0_TX0 2
++#define GDMA_PCM0_TX1 3
++
++#define GDMA_PCM1_RX0 4
++#define GDMA_PCM1_RX1 5
++#define GDMA_PCM1_TX0 6
++#define GDMA_PCM1_TX1 7
++
++#define GDMA_PCM_RX(i,j) (0+((i)<<2)+j)
++#define GDMA_PCM_TX(i,j) (2+((i)<<2)+j)
++
++#define GDMA_I2S_TX0 4
++#define GDMA_I2S_TX1 5
++#define GDMA_I2S_RX0 6
++#define GDMA_I2S_RX1 7
++
++#define GDMA_SPI_TX 13
++#define GDMA_SPI_RX 12
++
++
++//#define GDMA_DEBUG
++#ifdef GDMA_DEBUG
++#define GDMA_PRINT(fmt, args...) printk(KERN_INFO "GDMA: " fmt, ## args)
++#else
++#define GDMA_PRINT(fmt, args...) { }
++#endif
++
++/*
++ * TYPEDEFS AND STRUCTURES
++ */
++
++enum GdmaBusterMode {
++ INC_MODE=0,
++ FIX_MODE=1
++};
++
++enum GdmaBusterSize {
++ BUSTER_SIZE_4B=0, /* 1 transfer */
++ BUSTER_SIZE_8B=1, /* 2 transfer */
++ BUSTER_SIZE_16B=2, /* 4 transfer */
++ BUSTER_SIZE_32B=3, /* 8 transfer */
++ BUSTER_SIZE_64B=4 /* 16 transfer */
++};
++
++enum GdmaDmaReqNum {
++#if defined (CONFIG_RALINK_RT3052)
++ DMA_REQ0=0,
++ DMA_NAND_REQ=1,
++ DMA_I2S_TX_REQ=2,
++ DMA_PCM_RX0_REQ=3,
++ DMA_PCM_RX1_REQ=4,
++ DMA_PCM_TX0_REQ=5,
++ DMA_PCM_TX1_REQ=6,
++ DMA_REG7=7,
++ DMA_MEM_REQ=8
++#elif defined (CONFIG_RALINK_RT3883) || defined (CONFIG_RALINK_RT3352) || defined (CONFIG_RALINK_RT5350) || defined (CONFIG_RALINK_RT6855)
++ DMA_REQ0=0,
++ DMA_NAND_REQ=1,
++ DMA_I2S_TX_REQ=2,
++ DMA_I2S_RX_REQ=3,
++ DMA_PCM_RX0_REQ=4,
++ DMA_PCM_RX1_REQ=5,
++ DMA_PCM_TX0_REQ=6,
++ DMA_PCM_TX1_REQ=7,
++ DMA_CODEC0_REQ8=8,
++ DMA_CODEC1_REQ9=9,
++ DMA_REQ10=10,
++ DMA_REQ11=11,
++ DMA_REQ12=12,
++ DMA_REQ13=13,
++ DMA_REQ14=14,
++ DMA_REQ15=15,
++
++ #if defined (CONFIG_RALINK_RT3883)
++ DMA_MEM_REQ=16
++ #elif defined (CONFIG_RALINK_RT3352) || defined (CONFIG_RALINK_RT5350) || defined (CONFIG_RALINK_RT6855)
++ DMA_MEM_REQ=32
++ #endif
++
++#elif defined(CONFIG_RALINK_MT7620) || defined (CONFIG_RALINK_MT7621) || defined (CONFIG_RALINK_MT7628) || defined (CONFIG_ARCH_MT7623)
++ DMA_REQ0=0,
++ DMA_NAND_REQ=1,
++ DMA_I2S_TX_REQ=2,
++ DMA_I2S_RX_REQ=3,
++ DMA_PCM_RX0_REQ=4,
++ DMA_PCM_RX1_REQ=5,
++ DMA_PCM_TX0_REQ=6,
++ DMA_PCM_TX1_REQ=7,
++ DMA_PCM_RX2_REQ=8,
++ DMA_PCM_RX3_REQ=9,
++ DMA_PCM_TX2_REQ=10,
++ DMA_PCM_TX3_REQ=11,
++ DMA_SPI_RX_REQ=12,
++ DMA_SPI_TX_REQ=13,
++ DMA_MEM_REQ=32
++
++#elif defined (CONFIG_RALINK_RT6855A)
++ DMA_NAND_REQ=0,
++ DMA_I2S_TX_REQ=1,
++ DMA_I2S_RX_REQ=2,
++ DMA_REQ0=3,
++ DMA_PCM_RX0_REQ=4,
++ DMA_PCM_RX1_REQ=5,
++ DMA_PCM_TX0_REQ=6,
++ DMA_PCM_TX1_REQ=7,
++ DMA_CODEC0_REQ8=8,
++ DMA_CODEC1_REQ9=9,
++ DMA_REQ10=10,
++ DMA_REQ11=11,
++ DMA_REQ12=12,
++ DMA_REQ13=13,
++ DMA_REQ14=14,
++ DMA_REQ15=15,
++ DMA_MEM_REQ=32
++#else
++#error Please Choose System Type
++#endif
++};
++
++
++
++typedef struct {
++ uint32_t Src;
++ uint32_t Dst;
++ uint16_t TransCount;
++ uint8_t SoftMode;
++ uint8_t NextUnMaskCh;
++ uint8_t ChMask;
++ uint8_t CoherentIntEbl;
++ uint32_t ChNum;
++ enum GdmaDmaReqNum SrcReqNum;
++ enum GdmaDmaReqNum DstReqNum;
++ enum GdmaBusterMode SrcBurstMode;
++ enum GdmaBusterMode DstBurstMode;
++ enum GdmaBusterSize BurstSize;
++ void (*DoneIntCallback)(uint32_t);
++ void (*UnMaskIntCallback)(uint32_t);
++} GdmaReqEntry;
++
++/*
++ * EXPORT FUNCTION
++ */
++int GdmaI2sTx(uint32_t Src, uint32_t Dst, uint8_t TxNo, uint16_t TransCount,
++ void (*DoneIntCallback)(uint32_t data),
++ void (*UnMaskIntCallback)(uint32_t data));
++
++int GdmaI2sRx(uint32_t Src, uint32_t Dst, uint8_t RxNo, uint16_t TransCount,
++ void (*DoneIntCallback)(uint32_t data),
++ void (*UnMaskIntCallback)(uint32_t data));
++
++int GdmaPcmRx(uint32_t Src, uint32_t Dst, uint8_t PcmNo, uint8_t RxNo, uint16_t TransCount,
++ void (*DoneIntCallback)(uint32_t data),
++ void (*UnMaskIntCallback)(uint32_t data));
++
++int GdmaPcmTx(uint32_t Src, uint32_t Dst, uint8_t PcmNo, uint8_t TxNo, uint16_t TransCount,
++ void (*DoneIntCallback)(uint32_t data),
++ void (*UnMaskIntCallback)(uint32_t data));
++
++int GdmaSpiTx(uint32_t Src, uint32_t Dst, uint16_t TransCount,
++ void (*DoneIntCallback)(uint32_t data),
++ void (*UnMaskIntCallback)(uint32_t data));
++
++int GdmaSpiRx(uint32_t Src, uint32_t Dst, uint16_t TransCount,
++ void (*DoneIntCallback)(uint32_t data),
++ void (*UnMaskIntCallback)(uint32_t data));
++
++
++int GdmaMem2Mem(uint32_t Src, uint32_t Dst, uint16_t TransCount,
++ void (*DoneIntCallback)(uint32_t data));
++
++int GdmaMaskChannel(uint32_t ChNum);
++
++int GdmaUnMaskChannel(uint32_t ChNum);
++
++int GdmaReqQuickIns(uint32_t ChNum);
++
++
++#endif
+diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
+index 6173d15..d9c52a7 100644
+--- a/sound/soc/soc-core.c
++++ b/sound/soc/soc-core.c
+@@ -1758,7 +1758,8 @@ static int soc_probe(struct platform_device *pdev)
+ /* Bodge while we unpick instantiation */
+ card->dev = &pdev->dev;
+
+- return snd_soc_register_card(card);
++ snd_soc_register_card(card);
++ return 0;
+ }
+
+ static int soc_cleanup_card_resources(struct snd_soc_card *card)
+--
+1.7.10.4
+