diff options
author | John Crispin <john@openwrt.org> | 2015-10-19 10:07:54 +0000 |
---|---|---|
committer | John Crispin <john@openwrt.org> | 2015-10-19 10:07:54 +0000 |
commit | 7295e9fb8be958913764eea2e6c467464dba4c41 (patch) | |
tree | a7f68a63830c8acd77cf7915c775815f99c9ca5e /target | |
parent | f5d5cb0114a18c854d3bbd19560a84f8b077521c (diff) | |
download | openwrt-7295e9fb8be958913764eea2e6c467464dba4c41.tar.gz openwrt-7295e9fb8be958913764eea2e6c467464dba4c41.tar.bz2 openwrt-7295e9fb8be958913764eea2e6c467464dba4c41.zip |
ramips: add alsa support
add the SDK alsa driver. this has only been tested on mt7628/88 and wm8960.
mt7620 is only compile tested.
Signed-off-by: John Crispin <blogic@openwrt.org>
SVN-Revision: 47205
Diffstat (limited to 'target')
-rw-r--r-- | target/linux/ramips/dts/mt7628an.dtsi | 111 | ||||
-rw-r--r-- | target/linux/ramips/modules.mk | 29 | ||||
-rw-r--r-- | target/linux/ramips/mt7620/config-3.18 | 2 | ||||
-rw-r--r-- | target/linux/ramips/mt7628/config-3.18 | 2 | ||||
-rw-r--r-- | target/linux/ramips/patches-3.18/0303-alsa.patch | 8411 |
5 files changed, 8554 insertions, 1 deletions
diff --git a/target/linux/ramips/dts/mt7628an.dtsi b/target/linux/ramips/dts/mt7628an.dtsi index 0f59cb7b36..b0d9d80816 100644 --- a/target/linux/ramips/dts/mt7628an.dtsi +++ b/target/linux/ramips/dts/mt7628an.dtsi @@ -105,6 +105,39 @@ }; }; + i2c@900 { + compatible = "mediatek,mt7628-i2c"; + reg = <0x900 0x100>; + + resets = <&rstctrl 16>; + reset-names = "i2c"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + + pinctrl-names = "default"; + pinctrl-0 = <&i2c_pins>; + }; + + i2s@a00 { + compatible = "ralink,mt7620a-i2s"; + reg = <0xa00 0x100>; + + resets = <&rstctrl 17>; + reset-names = "i2s"; + + interrupt-parent = <&intc>; + interrupts = <10>; + + dmas = <&gdma 2>, + <&gdma 3>; + dma-names = "tx", "rx"; + + status = "disabled"; + }; + spi@b00 { compatible = "ralink,mt7621-spi"; reg = <0xb00 0x100>; @@ -178,6 +211,49 @@ status = "disabled"; }; + + pwm@5000 { + compatible = "mediatek,mt7628-pwm"; + reg = <0x5000 0x1000>; + + resets = <&rstctrl 31>; + reset-names = "pwm"; + + pinctrl-names = "default"; + pinctrl-0 = <&pwm0_pins>, <&pwm1_pins>; + + status = "disabled"; + }; + + pcm@2000 { + compatible = "ralink,mt7620a-pcm"; + reg = <0x2000 0x800>; + + resets = <&rstctrl 11>; + reset-names = "pcm"; + + interrupt-parent = <&intc>; + interrupts = <4>; + + status = "disabled"; + }; + + gdma: gdma@2800 { + compatible = "ralink,mt7620a-gdma", "ralink,rt2880-gdma"; + reg = <0x2800 0x800>; + + resets = <&rstctrl 14>; + reset-names = "dma"; + + interrupt-parent = <&intc>; + interrupts = <7>; + + #dma-cells = <1>; + #dma-channels = <16>; + #dma-requests = <16>; + + status = "disabled"; + }; }; pinctrl { @@ -195,6 +271,20 @@ }; }; + spi_cs1_pins: spi_cs1 { + spi_cs1 { + ralink,group = "spi cs1"; + ralink,function = "spi cs1"; + }; + }; + + i2c_pins: i2c { + i2c { + ralink,group = "i2c"; + ralink,function = "i2c"; + }; + }; + uart0_pins: uartlite { uartlite { ralink,group = "uart0"; @@ -222,6 +312,27 @@ ralink,function = "sdxc"; }; }; + + pwm0_pins: pwm0 { + pwm0 { + ralink,group = "pwm0"; + ralink,function = "pwm0"; + }; + }; + + pwm1_pins: pwm1 { + pwm1 { + ralink,group = "pwm1"; + ralink,function = "pwm1"; + }; + }; + + pcm_i2s_pins: i2s { + i2s { + ralink,group = "i2s"; + ralink,function = "pcm"; + }; + }; }; rstctrl: rstctrl { diff --git a/target/linux/ramips/modules.mk b/target/linux/ramips/modules.mk index 503a1e55a1..bfb9bcd826 100644 --- a/target/linux/ramips/modules.mk +++ b/target/linux/ramips/modules.mk @@ -56,7 +56,7 @@ $(eval $(call KernelPackage,i2c-mt7621)) define KernelPackage/sound-mt7620 TITLE:=MT7620 PCM/I2S Alsa Driver - DEPENDS:=@TARGET_ramips_mt7620 +kmod-sound-soc-core +kmod-regmap + DEPENDS:=@TARGET_ramips_mt7620 +kmod-sound-soc-core +kmod-regmap @BROKEN KCONFIG:= \ CONFIG_SND_MT7620_SOC_I2S \ CONFIG_SND_MT7620_SOC_WM8960 @@ -73,3 +73,30 @@ define KernelPackage/sound-mt7620/description endef $(eval $(call KernelPackage,sound-mt7620)) + + +define KernelPackage/sound-mtk + TITLE:=Mediatek I2S Alsa Driver + DEPENDS:= +kmod-sound-soc-core +kmod-regmap +kmod-i2c-ralink @(TARGET_ramips_mt7628||TARGET_ramips_mt7688||TARGET_ramips_mt7620) + KCONFIG:= \ + CONFIG_SND_MT76XX_SOC \ + CONFIG_SND_MT76XX_I2S \ + CONFIG_SND_MT76XX_PCM \ + CONFIG_SND_SOC_WM8960 + FILES:= \ + $(LINUX_DIR)/sound/soc/mtk/ralink_gdma.ko \ + $(LINUX_DIR)/sound/soc/mtk/snd-soc-mt76xx-i2s-ctl.ko \ + $(LINUX_DIR)/sound/soc/mtk/snd-soc-mt76xx-i2s.ko \ + $(LINUX_DIR)/sound/soc/mtk/snd-soc-mt76xx-pcm.ko \ + $(LINUX_DIR)/sound/soc/mtk/snd-soc-mt76xx-machine.ko \ + $(LINUX_DIR)/sound/soc/mtk/i2c_wm8960.ko \ + $(LINUX_DIR)/sound/soc/codecs/snd-soc-wm8960.ko + AUTOLOAD:=$(call AutoLoad,90,ralink_gdma snd-soc-wm8960 i2c_wm8960 snd-soc-mt76xx-i2s-ctl snd-soc-mt76xx-i2s snd-soc-mt76xx-pcm snd-soc-mt76xx-machine) + $(call AddDepends/sound) +endef + +define KernelPackage/sound-mtk/description + Alsa modules for ralink i2s controller. +endef + +$(eval $(call KernelPackage,sound-mtk)) diff --git a/target/linux/ramips/mt7620/config-3.18 b/target/linux/ramips/mt7620/config-3.18 index 8a8da6a00f..0263bba3ea 100644 --- a/target/linux/ramips/mt7620/config-3.18 +++ b/target/linux/ramips/mt7620/config-3.18 @@ -166,6 +166,8 @@ CONFIG_SOC_MT7620=y # CONFIG_SOC_RT288X is not set # CONFIG_SOC_RT305X is not set # CONFIG_SOC_RT3883 is not set +CONFIG_SND_MT76XX_SOC_MT7620=y +# CONFIG_SND_MT76XX_SOC_MT7628 is not set CONFIG_SPI=y CONFIG_SPI_MASTER=y # CONFIG_SPI_MT7621 is not set diff --git a/target/linux/ramips/mt7628/config-3.18 b/target/linux/ramips/mt7628/config-3.18 index e0bc10a3e7..9ab31acdc3 100644 --- a/target/linux/ramips/mt7628/config-3.18 +++ b/target/linux/ramips/mt7628/config-3.18 @@ -164,6 +164,8 @@ CONFIG_SOC_MT7620=y # CONFIG_SOC_RT288X is not set # CONFIG_SOC_RT305X is not set # CONFIG_SOC_RT3883 is not set +# CONFIG_SND_MT76XX_SOC_MT7620 is not set +CONFIG_SND_MT76XX_SOC_MT7628=y CONFIG_SPI=y CONFIG_SPI_MASTER=y CONFIG_SPI_MT7621=y diff --git a/target/linux/ramips/patches-3.18/0303-alsa.patch b/target/linux/ramips/patches-3.18/0303-alsa.patch new file mode 100644 index 0000000000..703af4489b --- /dev/null +++ b/target/linux/ramips/patches-3.18/0303-alsa.patch @@ -0,0 +1,8411 @@ +--- a/sound/soc/Kconfig ++++ b/sound/soc/Kconfig +@@ -56,6 +56,7 @@ + source "sound/soc/tegra/Kconfig" + source "sound/soc/txx9/Kconfig" + source "sound/soc/ux500/Kconfig" ++source "sound/soc/mtk/Kconfig" + + # Supported codecs + source "sound/soc/codecs/Kconfig" +--- a/sound/soc/Makefile ++++ b/sound/soc/Makefile +@@ -33,3 +33,4 @@ + obj-$(CONFIG_SND_SOC) += tegra/ + obj-$(CONFIG_SND_SOC) += txx9/ + obj-$(CONFIG_SND_SOC) += ux500/ ++obj-$(CONFIG_SND_SOC) += mtk/ +--- a/sound/soc/codecs/Kconfig ++++ b/sound/soc/codecs/Kconfig +@@ -725,7 +725,7 @@ + tristate + + config SND_SOC_WM8960 +- tristate ++ tristate "WM8960" + + config SND_SOC_WM8961 + tristate +--- /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 ++ +--- /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 ++ ++ ++ +--- /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"); ++ +--- /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 */ +--- /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®BIT(1, I2S_TX_DMA_FAULT)) ++ { ++ pi2s_status->txdmafault++; ++ } ++ if(i2s_status®BIT(1, I2S_TX_OVRUN)) ++ { ++ pi2s_status->txovrun++; ++ } ++ if(i2s_status®BIT(1, I2S_TX_UNRUN)) ++ { ++ pi2s_status->txunrun++; ++ } ++ if(i2s_status®BIT(1, I2S_TX_THRES)) ++ { ++ pi2s_status->txthres++; ++ } ++ if(i2s_status®BIT(1, I2S_RX_DMA_FAULT)) ++ { ++ pi2s_status->rxdmafault++; ++ } ++ if(i2s_status®BIT(1, I2S_RX_OVRUN)) ++ { ++ pi2s_status->rxovrun++; ++ } ++ if(i2s_status®BIT(1, I2S_RX_UNRUN)) ++ { ++ pi2s_status->rxunrun++; ++ } ++ if(i2s_status®BIT(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®BIT(1, I2S_TX_DMA_FAULT)) ++ { ++#ifdef I2S_STATISTIC ++ pi2s_status->txdmafault++; ++#endif ++ } ++ if(i2s_status®BIT(1, I2S_TX_OVRUN)) ++ { ++#ifdef I2S_STATISTIC ++ pi2s_status->txovrun++; ++#endif ++ } ++ if(i2s_status®BIT(1, I2S_TX_UNRUN)) ++ { ++#ifdef I2S_STATISTIC ++ pi2s_status->txunrun++; ++#endif ++ } ++ if(i2s_status®BIT(1, I2S_TX_THRES)) ++ { ++#ifdef I2S_STATISTIC ++ pi2s_status->txthres++; ++#endif ++ } ++ if(i2s_status®BIT(1, I2S_RX_DMA_FAULT)) ++ { ++#ifdef I2S_STATISTIC ++ pi2s_status->rxdmafault++; ++#endif ++ } ++ if(i2s_status®BIT(1, I2S_RX_OVRUN)) ++ { ++#ifdef I2S_STATISTIC ++ pi2s_status->rxovrun++; ++#endif ++ } ++ if(i2s_status®BIT(1, I2S_RX_UNRUN)) ++ { ++#ifdef I2S_STATISTIC ++ pi2s_status->rxunrun++; ++#endif ++ } ++ if(i2s_status®BIT(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 +--- /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_ */ ++ +--- /dev/null ++++ b/sound/soc/mtk/mt76xx_i2s.c +@@ -0,0 +1,309 @@ ++/* ++ * 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:%s[%d]\n", __FILE__, __func__, __LINE__); ++ //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: ++ printk("%s:%s[%d]\n", __FILE__, __func__, __LINE__); ++ 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){ ++ printk("%s:%s[%d]\n", __FILE__, __func__, __LINE__); ++ if((rtd->bRxDMAEnable != GDMA_I2S_EN) && (rtd->bTxDMAEnable != GDMA_I2S_EN)){ ++ printk("%s:%s[%d]\n", __FILE__, __func__, __LINE__); ++ 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__); ++ printk("%s:%s[%d]\n", __FILE__, __func__, __LINE__); ++ 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 +--- /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_ */ +--- /dev/null ++++ b/sound/soc/mtk/mt76xx_machine.c +@@ -0,0 +1,319 @@ ++/* ++ * 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; ++ ++ printk("%s:%s[%d]\n", __FILE__, __func__, __LINE__); ++ /*For duplex mode, avoid setting twice.*/ ++ if((rtd->bRxDMAEnable == GDMA_I2S_EN) || (rtd->bTxDMAEnable == GDMA_I2S_EN)) ++ return 0; ++ //printk("%s:%d \n",__func__,__LINE__); ++#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); ++ ++ printk("%s:%s[%d]%d\n", __FILE__, __func__, __LINE__, params_rate(params)); ++ 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; ++ } ++printk("%s:%s[%d]\n", __FILE__, __func__, __LINE__); ++#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. ++ * */ ++ printk("%s:%s[%d]\n", __FILE__, __func__, __LINE__); ++ 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("%s:%s[%d]\n", __FILE__, __func__, __LINE__); ++ //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 ++ printk("%s:%s[%d]\n", __FILE__, __func__, __LINE__); ++ 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)); ++printk("%s:%s[%d]\n", __FILE__, __func__, __LINE__); ++#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("wm8960", (0x34 >> 1)), ++ I2C_BOARD_INFO("codec_wm8960", (0x34)), ++#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); ++ if (!client) ++ return -ENODEV; ++ ++ i2c_put_adapter(adapter); ++ i2c_get_clientdata(client); ++ ++ 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"); +--- /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_ */ +--- /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"); ++ +--- /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); +--- /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 +--- a/sound/soc/soc-core.c ++++ b/sound/soc/soc-core.c +@@ -1851,7 +1851,8 @@ + /* 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) +--- /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; ++} +--- a/sound/soc/codecs/wm8960.c ++++ b/sound/soc/codecs/wm8960.c +@@ -26,6 +26,7 @@ + #include <sound/wm8960.h> + + #include "wm8960.h" ++#include "../mtk/i2c_wm8960.h" + + /* R25 - Power 1 */ + #define WM8960_VMID_MASK 0x180 +@@ -53,10 +54,10 @@ + * 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 }, +@@ -88,8 +89,8 @@ + { 0x25, 0x0050 }, + { 0x26, 0x0000 }, + { 0x27, 0x0000 }, +- { 0x28, 0x0000 }, +- { 0x29, 0x0000 }, ++ { 0x28, 0x007b }, ++ { 0x29, 0x007b }, + { 0x2a, 0x0040 }, + { 0x2b, 0x0000 }, + { 0x2c, 0x0000 }, +@@ -127,8 +128,15 @@ + int playback_fs; + }; + ++#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) snd_soc_write(c, WM8960_RESET, 0) +- ++#endif + /* enumerated controls */ + static const char *wm8960_polarity[] = {"No Inversion", "Left Inverted", + "Right Inverted", "Stereo Inversion"}; +@@ -181,8 +189,8 @@ + 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, +@@ -200,6 +208,70 @@ + 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, -9700, 50, 0); + static const DECLARE_TLV_DB_SCALE(dac_tlv, -12700, 50, 1); + static const DECLARE_TLV_DB_SCALE(bypass_tlv, -2100, 300, 0); +@@ -542,6 +614,7 @@ + + /* set iface */ + snd_soc_write(codec, WM8960_IFACE1, iface); ++ wm8960_postinit(codec); + return 0; + } + +@@ -623,11 +696,16 @@ + break; + + case SND_SOC_BIAS_PREPARE: ++#if 0 + /* Set VMID to 2x50k */ + snd_soc_update_bits(codec, WM8960_POWER1, 0x180, 0x80); ++#endif + break; + + case SND_SOC_BIAS_STANDBY: ++#if 1 ++ wm8960_preinit(codec); ++#else + if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { + regcache_sync(wm8960->regmap); + +@@ -650,9 +728,13 @@ + + /* 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 | +@@ -661,6 +743,7 @@ + /* Disable VMID and VREF, let them discharge */ + snd_soc_write(codec, WM8960_POWER1, 0); + msleep(600); ++#endif + break; + } + +@@ -853,10 +936,15 @@ + + 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); + +@@ -876,19 +964,27 @@ + + switch (div_id) { + case WM8960_SYSCLKDIV: ++ printk("%s:%s[%d]\n", __FILE__, __func__, __LINE__); + reg = snd_soc_read(codec, WM8960_CLOCK1) & 0x1f9; + snd_soc_write(codec, WM8960_CLOCK1, reg | div); + break; + case WM8960_DACDIV: + reg = snd_soc_read(codec, WM8960_CLOCK1) & 0x1c7; ++ printk("%s:%s[%d]\n", __FILE__, __func__, __LINE__); + snd_soc_write(codec, WM8960_CLOCK1, reg | div); + break; + case WM8960_OPCLKDIV: + reg = snd_soc_read(codec, WM8960_PLL1) & 0x03f; ++ printk("%s:%s[%d]\n", __FILE__, __func__, __LINE__); + snd_soc_write(codec, WM8960_PLL1, reg | div); + break; + case WM8960_DCLKDIV: ++#if 1 ++ printk("%s:%s[%d]\n", __FILE__, __func__, __LINE__); + 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: +@@ -962,7 +1058,7 @@ + { + struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec); + struct wm8960_data *pdata = dev_get_platdata(codec->dev); +- int ret; ++ int ret = 0; + + wm8960->set_bias_level = wm8960_set_bias_level_out3; + +@@ -973,11 +1069,7 @@ + wm8960->set_bias_level = wm8960_set_bias_level_capless; + } + +- ret = wm8960_reset(codec); +- if (ret < 0) { +- dev_err(codec->dev, "Failed to issue reset\n"); +- return ret; +- } ++ wm8960_reset(codec); + + wm8960->set_bias_level(codec, SND_SOC_BIAS_STANDBY); + +--- a/sound/soc/codecs/wm8960.h ++++ b/sound/soc/codecs/wm8960.h +@@ -110,4 +110,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 |