From f98ffa1f01240407e39c1b53135312db73f044c6 Mon Sep 17 00:00:00 2001 From: John Crispin Date: Mon, 7 Dec 2015 17:30:48 +0100 Subject: [PATCH 50/53] alsa: add ralink sdk driver Signed-off-by: John Crispin --- sound/soc/Kconfig | 1 + sound/soc/Makefile | 1 + sound/soc/codecs/Kconfig | 2 +- sound/soc/codecs/wm8960.c | 120 +- sound/soc/codecs/wm8960.h | 64 + sound/soc/mtk/Kconfig | 35 + sound/soc/mtk/Makefile | 39 + sound/soc/mtk/i2c_wm8960.c | 492 ++++++ sound/soc/mtk/i2c_wm8960.h | 288 ++++ sound/soc/mtk/i2s_ctrl.c | 3524 ++++++++++++++++++++++++++++++++++++++++ sound/soc/mtk/i2s_ctrl.h | 523 ++++++ sound/soc/mtk/i2s_debug.c | 698 ++++++++ sound/soc/mtk/mt76xx_i2s.c | 304 ++++ sound/soc/mtk/mt76xx_i2s.h | 18 + sound/soc/mtk/mt76xx_machine.c | 317 ++++ sound/soc/mtk/mt76xx_machine.h | 21 + sound/soc/mtk/mt76xx_pcm.c | 499 ++++++ sound/soc/mtk/ralink_gdma.c | 918 +++++++++++ sound/soc/mtk/ralink_gdma.h | 326 ++++ sound/soc/soc-core.c | 3 +- 20 files changed, 8174 insertions(+), 19 deletions(-) create mode 100644 sound/soc/mtk/Kconfig create mode 100644 sound/soc/mtk/Makefile create mode 100644 sound/soc/mtk/i2c_wm8960.c create mode 100644 sound/soc/mtk/i2c_wm8960.h create mode 100644 sound/soc/mtk/i2s_ctrl.c create mode 100644 sound/soc/mtk/i2s_ctrl.h create mode 100644 sound/soc/mtk/i2s_debug.c create mode 100644 sound/soc/mtk/mt76xx_i2s.c create mode 100644 sound/soc/mtk/mt76xx_i2s.h create mode 100644 sound/soc/mtk/mt76xx_machine.c create mode 100644 sound/soc/mtk/mt76xx_machine.h create mode 100644 sound/soc/mtk/mt76xx_pcm.c create mode 100644 sound/soc/mtk/ralink_gdma.c create mode 100644 sound/soc/mtk/ralink_gdma.h diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig index 76ce95c..09aa2c7 100644 --- a/sound/soc/Kconfig +++ b/sound/soc/Kconfig @@ -64,6 +64,7 @@ source "sound/soc/txx9/Kconfig" source "sound/soc/ux500/Kconfig" source "sound/soc/xtensa/Kconfig" source "sound/soc/zte/Kconfig" +source "sound/soc/mtk/Kconfig" # Supported codecs source "sound/soc/codecs/Kconfig" diff --git a/sound/soc/Makefile b/sound/soc/Makefile index e9d8e0e..a3c6b43 100644 --- a/sound/soc/Makefile +++ b/sound/soc/Makefile @@ -46,3 +46,4 @@ obj-$(CONFIG_SND_SOC) += txx9/ obj-$(CONFIG_SND_SOC) += ux500/ obj-$(CONFIG_SND_SOC) += xtensa/ obj-$(CONFIG_SND_SOC) += zte/ +obj-$(CONFIG_SND_SOC) += mtk/ diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 0c9733e..276a4c5 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -816,7 +816,7 @@ config SND_SOC_WM8955 tristate config SND_SOC_WM8960 - tristate + tristate "WM8960" config SND_SOC_WM8961 tristate diff --git a/sound/soc/codecs/wm8960.c b/sound/soc/codecs/wm8960.c index dbd8840..3118f5c 100644 --- a/sound/soc/codecs/wm8960.c +++ b/sound/soc/codecs/wm8960.c @@ -27,6 +27,7 @@ #include #include "wm8960.h" +#include "../mtk/i2c_wm8960.h" /* R25 - Power 1 */ #define WM8960_VMID_MASK 0x180 @@ -57,10 +58,10 @@ static int wm8960_set_pll(struct snd_soc_codec *codec, * using 2 wire for device control, so we cache them instead. */ static const struct reg_default wm8960_reg_defaults[] = { - { 0x0, 0x00a7 }, - { 0x1, 0x00a7 }, - { 0x2, 0x0000 }, - { 0x3, 0x0000 }, + { 0x0, 0x002b }, + { 0x1, 0x002b }, + { 0x2, 0x00ff }, + { 0x3, 0x00ff }, { 0x4, 0x0000 }, { 0x5, 0x0008 }, { 0x6, 0x0000 }, @@ -92,8 +93,8 @@ static const struct reg_default wm8960_reg_defaults[] = { { 0x25, 0x0050 }, { 0x26, 0x0000 }, { 0x27, 0x0000 }, - { 0x28, 0x0000 }, - { 0x29, 0x0000 }, + { 0x28, 0x007b }, + { 0x29, 0x007b }, { 0x2a, 0x0040 }, { 0x2b, 0x0000 }, { 0x2c, 0x0000 }, @@ -138,7 +139,15 @@ struct wm8960_priv { struct wm8960_data pdata; }; +#if 1 +#define wm8960_reset(c) do{ \ + int i = 0;\ + snd_soc_write(c, WM8960_RESET, 0);\ + for(i = 0; i < 1000*HZ; i++);\ + }while(0) +#else #define wm8960_reset(c) regmap_write(c, WM8960_RESET, 0) +#endif /* enumerated controls */ static const char *wm8960_polarity[] = {"No Inversion", "Left Inverted", @@ -192,8 +201,8 @@ static int wm8960_get_deemph(struct snd_kcontrol *kcontrol, struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec); - ucontrol->value.integer.value[0] = wm8960->deemph; - return 0; + //ucontrol->value.integer.value[0] = wm8960->deemph; + return wm8960->deemph; } static int wm8960_put_deemph(struct snd_kcontrol *kcontrol, @@ -211,6 +220,71 @@ static int wm8960_put_deemph(struct snd_kcontrol *kcontrol, return wm8960_set_deemph(codec); } +static int wm8960_preinit(struct snd_soc_codec *codec) +{ + //printk("****** %s ******\n", __func__); + snd_soc_write(codec, WM8960_RESET, 0); + mdelay(500); + + return 0; +} + +static int wm8960_postinit(struct snd_soc_codec *codec) +{ + u32 data; + //printk("****** %s ******\n", __func__); + // In + data = snd_soc_read(codec, WM8960_POWER1); + snd_soc_write(codec, WM8960_POWER1, data|WM8960_PWR1_ADCL|WM8960_PWR1_ADCR|WM8960_PWR1_AINL |WM8960_PWR1_AINR|WM8960_PWR1_MICB);//0x19 + data = snd_soc_read(codec, WM8960_ADDCTL1); + snd_soc_write(codec, WM8960_ADDCTL1, data|ADDITIONAL1_DATSEL(0x01));//0x17 + snd_soc_write(codec, WM8960_LADC, LEFTGAIN_LDVU|LEFTGAIN_LDACVOL(0xc3));//0x15 + snd_soc_write(codec, WM8960_RADC, LEFTGAIN_LDVU|LEFTGAIN_LDACVOL(0xc3));//0x16 + snd_soc_write(codec, WM8960_LINPATH, 0x148);//0x20 + snd_soc_write(codec, WM8960_RINPATH, 0x148);//0x21 + snd_soc_write(codec, WM8960_POWER3, WM8960_PWR3_LMIC|WM8960_PWR3_RMIC);//0x2f + + // Out + data = snd_soc_read(codec, WM8960_POWER2); + snd_soc_write(codec, WM8960_POWER2, data|WM8960_PWR2_DACL|WM8960_PWR2_DACR|WM8960_PWR2_LOUT1|WM8960_PWR2_ROUT1|WM8960_PWR2_SPKL|WM8960_PWR2_SPKR);//0x1a + mdelay(10); + snd_soc_write(codec, WM8960_IFACE2, 0x40); + snd_soc_write(codec, WM8960_LDAC, LEFTGAIN_LDVU|LEFTGAIN_LDACVOL(0xff));//0x0a + snd_soc_write(codec, WM8960_RDAC, RIGHTGAIN_RDVU|RIGHTGAIN_RDACVOL(0xff));//0x0b + snd_soc_write(codec, WM8960_LOUTMIX, 0x100);//0x22 + snd_soc_write(codec, WM8960_ROUTMIX, 0x100);//0x25 + + data = snd_soc_read(codec, WM8960_POWER3); + snd_soc_write(codec, WM8960_POWER3, data|WM8960_PWR3_ROMIX|WM8960_PWR3_LOMIX);//0x2f + + snd_soc_write(codec, WM8960_CLASSD1, 0xf7);//0x31 + snd_soc_write(codec, WM8960_CLASSD3, 0xad);//0x33 + snd_soc_write(codec, WM8960_DACCTL1, 0x000);//0x05 + + data = snd_soc_read(codec, WM8960_POWER1); + snd_soc_write(codec, WM8960_POWER1, data|0x1c0);//0x19 + + + snd_soc_write(codec, WM8960_LOUT1, LOUT1_LO1VU|LOUT1_LO1ZC|LOUT1_LOUT1VOL(115));//0x02 + snd_soc_write(codec, WM8960_ROUT1, ROUT1_RO1VU|ROUT1_RO1ZC|ROUT1_ROUT1VOL(115));//0x03 + + snd_soc_write(codec, WM8960_LINVOL, LINV_IPVU|LINV_LINVOL(110)); //LINV(0x00)=>0x12b + snd_soc_write(codec, WM8960_RINVOL, RINV_IPVU|RINV_RINVOL(110)); //LINV(0x01)=>0x12b + + return 0; +} + +static int wm8960_close(struct snd_soc_codec *codec) +{ + snd_soc_write(codec, WM8960_DACCTL1,0x8); //0x05->0x08 + snd_soc_write(codec, WM8960_POWER1, 0x000); //0x19->0x000 + mdelay(300); + snd_soc_write(codec, WM8960_POWER2, 0x000); //0x1a->0x000 + + return 0; +} + + static const DECLARE_TLV_DB_SCALE(adc_tlv, -9750, 50, 1); static const DECLARE_TLV_DB_SCALE(inpga_tlv, -1725, 75, 0); static const DECLARE_TLV_DB_SCALE(dac_tlv, -12750, 50, 1); @@ -563,6 +637,7 @@ static int wm8960_set_dai_fmt(struct snd_soc_dai *codec_dai, /* set iface */ snd_soc_write(codec, WM8960_IFACE1, iface); + wm8960_postinit(codec); return 0; } @@ -809,9 +884,10 @@ static int wm8960_set_bias_level_out3(struct snd_soc_codec *codec, ret = wm8960_configure_clocking(codec); if (ret) return ret; - +#if 0 /* Set VMID to 2x50k */ snd_soc_update_bits(codec, WM8960_POWER1, 0x180, 0x80); +#endif break; case SND_SOC_BIAS_ON: @@ -852,12 +928,16 @@ static int wm8960_set_bias_level_out3(struct snd_soc_codec *codec, /* Disable anti-pop features */ snd_soc_write(codec, WM8960_APOP1, WM8960_BUFIOEN); } - +#if 0 /* Set VMID to 2x250k */ snd_soc_update_bits(codec, WM8960_POWER1, 0x180, 0x100); +#endif break; case SND_SOC_BIAS_OFF: +#if 1 + wm8960_close(codec); +#else /* Enable anti-pop features */ snd_soc_write(codec, WM8960_APOP1, WM8960_POBCTRL | WM8960_SOFT_ST | @@ -866,6 +946,7 @@ static int wm8960_set_bias_level_out3(struct snd_soc_codec *codec, /* Disable VMID and VREF, let them discharge */ snd_soc_write(codec, WM8960_POWER1, 0); msleep(600); +#endif break; } @@ -1101,10 +1182,15 @@ static int wm8960_set_pll(struct snd_soc_codec *codec, if (pll_div.k) { reg |= 0x20; - +#if 1 snd_soc_write(codec, WM8960_PLL2, (pll_div.k >> 16) & 0xff); snd_soc_write(codec, WM8960_PLL3, (pll_div.k >> 8) & 0xff); snd_soc_write(codec, WM8960_PLL4, pll_div.k & 0xff); +#else + snd_soc_write(codec, WM8960_PLL2, (pll_div.k >> 16) & 0xff); + snd_soc_write(codec, WM8960_PLL3, (pll_div.k >> 8) & 0xff); + snd_soc_write(codec, WM8960_PLL4, pll_div.k & 0xff); +#endif } snd_soc_write(codec, WM8960_PLL1, reg); @@ -1150,7 +1236,11 @@ static int wm8960_set_dai_clkdiv(struct snd_soc_dai *codec_dai, snd_soc_write(codec, WM8960_PLL1, reg | div); break; case WM8960_DCLKDIV: +#if 1 reg = snd_soc_read(codec, WM8960_CLOCK2) & 0x03f; +#else + reg = snd_soc_read(codec, WM8960_CLOCK2) & 0x03f; +#endif snd_soc_write(codec, WM8960_CLOCK2, reg | div); break; case WM8960_TOCLKSEL: @@ -1285,7 +1375,7 @@ static int wm8960_i2c_probe(struct i2c_client *i2c, { struct wm8960_data *pdata = dev_get_platdata(&i2c->dev); struct wm8960_priv *wm8960; - int ret; + int ret - 0; wm8960 = devm_kzalloc(&i2c->dev, sizeof(struct wm8960_priv), GFP_KERNEL); @@ -1307,11 +1397,7 @@ static int wm8960_i2c_probe(struct i2c_client *i2c, else if (i2c->dev.of_node) wm8960_set_pdata_from_of(i2c, &wm8960->pdata); - ret = wm8960_reset(wm8960->regmap); - if (ret != 0) { - dev_err(&i2c->dev, "Failed to issue reset\n"); - return ret; - } + wm8960_reset(wm8960->regmap); if (wm8960->pdata.shared_lrclk) { ret = regmap_update_bits(wm8960->regmap, WM8960_ADDCTL2, diff --git a/sound/soc/codecs/wm8960.h b/sound/soc/codecs/wm8960.h index ab3220d..5205deb 100644 --- a/sound/soc/codecs/wm8960.h +++ b/sound/soc/codecs/wm8960.h @@ -111,4 +111,68 @@ #define WM8960_OPCLK_DIV_5_5 (4 << 0) #define WM8960_OPCLK_DIV_6 (5 << 0) +/* + * WM8960 Power management + */ +#define WM8960_PWR1_VMIDSEL_DISABLED (0 << 7) +#define WM8960_PWR1_VMIDSEL_50K (1 << 7) +#define WM8960_PWR1_VMIDSEL_250K (2 << 7) +#define WM8960_PWR1_VMIDSEL_5K (3 << 7) +#define WM8960_PWR1_VREF (1 << 6) +#define WM8960_PWR1_AINL (1 << 5) +#define WM8960_PWR1_AINR (1 << 4) +#define WM8960_PWR1_ADCL (1 << 3) +#define WM8960_PWR1_ADCR (1 << 2) +#define WM8960_PWR1_MICB (1 << 1) +#define WM8960_PWR1_DIGENB (1 << 0) + +#define WM8960_PWR2_DACL (1 << 8) +#define WM8960_PWR2_DACR (1 << 7) +//#define WM8960_PWR2_LOUT1 (1 << 6) +//#define WM8960_PWR2_ROUT1 (1 << 5) +#define WM8960_PWR2_SPKL (1 << 4) +#define WM8960_PWR2_SPKR (1 << 3) +//#define WM8960_PWR2_OUT3 (1 << 1) +#define WM8960_PWR2_PLL_EN (1 << 0) + +#define WM8960_PWR3_LMIC (1 << 5) +#define WM8960_PWR3_RMIC (1 << 4) +#define WM8960_PWR3_LOMIX (1 << 3) +#define WM8960_PWR3_ROMIX (1 << 2) + +#define LEFTGAIN 0x0a +#define LEFTGAIN_LDVU (1 << 8) +#define LEFTGAIN_LDACVOL(x) ((x) & 0xff) + +#define RIGHTGAIN 0x0b +#define RIGHTGAIN_RDVU (1 << 8) +#define RIGHTGAIN_RDACVOL(x) ((x) & 0xff) + +#define ADDITIONAL1_DATSEL(x) (((x) & 0x3) << 2) + +#define AINTFCE1_WL_32 (3 << 2) +#define AINTFCE1_WL_24 (2 << 2) +#define AINTFCE1_WL_20 (1 << 2) +#define AINTFCE1_WL_16 (0 << 2) +#define AINTFCE1_FORMAT_I2S (2 << 0) + +#define LOUT1_LO1VU (1 << 8) +#define LOUT1_LO1ZC (1 << 7) +#define LOUT1_LOUT1VOL(x) ((x) & 0x7f) + +#define ROUT1_RO1VU (1 << 8) +#define ROUT1_RO1ZC (1 << 7) +#define ROUT1_ROUT1VOL(x) ((x) & 0x7f) + +#define LINV_IPVU (1 << 8) /* FIXME */ + +#define LINV_LINMUTE (1 << 7) +#define LINV_LIZC (1 << 6) +#define LINV_LINVOL(x) ((x) & 0x3f) + +#define RINV_IPVU (1 << 8) /* FIXME */ +#define RINV_RINMUTE (1 << 7) +#define RINV_RIZC (1 << 6) +#define RINV_RINVOL(x) ((x) & 0x3f) + #endif diff --git a/sound/soc/mtk/Kconfig b/sound/soc/mtk/Kconfig new file mode 100644 index 0000000..26d2531 --- /dev/null +++ b/sound/soc/mtk/Kconfig @@ -0,0 +1,35 @@ +config SND_MT76XX_SOC + tristate "SoC Audio for MT76XX APSoC Machine" + depends on SND_SOC && (SOC_MT7620 || SOC_MT7621) + + help + Say Y or M if you want to add support for codecs attached to + the MTK I2S interface. + +choice + prompt "Selected SoC type" + depends on SND_MT76XX_SOC + default SND_MT76XX_SOC_MT7620 + +config SND_MT76XX_SOC_MT7620 + bool "MT7620" + depends on SOC_MT7620 + +config SND_MT76XX_SOC_MT7628 + bool "MT7628" + depends on SOC_MT7620 + +config SND_MT76XX_SOC_MT7621 + bool "MT7621" + depends on SOC_MT7621 + +endchoice + +config SND_MT76XX_PCM + tristate "MTK SoC Audio PCM Platform" + depends on SND_MT76XX_SOC + +config SND_MT76XX_I2S + tristate "MTK SoC I2S Support" + depends on SND_MT76XX_SOC + diff --git a/sound/soc/mtk/Makefile b/sound/soc/mtk/Makefile new file mode 100644 index 0000000..00b3dff --- /dev/null +++ b/sound/soc/mtk/Makefile @@ -0,0 +1,39 @@ +KBUILD_CFLAGS += -I$(srctree) + +ifeq ($(CONFIG_SND_MT76XX_SOC_MT7620),y) +KBUILD_CFLAGS += -DCONFIG_MT7620 -DCONFIG_RALINK_MT7620 +endif +ifeq ($(CONFIG_SND_MT76XX_SOC_MT7628),y) +KBUILD_CFLAGS += -DCONFIG_MT7628 -DCONFIG_RALINK_MT7628 +endif +ifeq ($(CONFIG_SOC_MT7620),y) +KBUILD_CFLAGS += -DRALINK_SYSCTL_BASE=0xB0000000 +KBUILD_CFLAGS += -DRALINK_INTCL_BASE=0xB0000200 +KBUILD_CFLAGS += -DRALINK_PIO_BASE=0xB0000600 +KBUILD_CFLAGS += -DRALINK_I2S_BASE=0xB0000A00 +KBUILD_CFLAGS += -DRALINK_GDMA_BASE=0xB0002800 +KBUILD_CFLAGS += -DCONFIG_GDMA_EVERYBODY +KBUILD_CFLAGS += -DCONFIG_SND_MT76XX_SOC +KBUILD_CFLAGS += -DCONFIG_I2S_WM8960 +KBUILD_CFLAGS += -DCONFIG_I2S_MCLK_12P288MHZ +KBUILD_CFLAGS += -DCONFIG_GDMA_EVERYBODY +KBUILD_CFLAGS += -DSURFBOARDINT_DMA=15 +KBUILD_CFLAGS += -DRALINK_INTCTL_DMA=128 +KBUILD_CFLAGS += -DCONFIG_SND_SOC_WM8960 +endif + +# MTK APSoC Platform Support +snd-soc-mt76xx-i2s-ctl-objs := i2s_ctrl.o i2s_debug.o #i2c_wm8960.o +snd-soc-mt76xx-pcm-objs := mt76xx_pcm.o +snd-soc-mt76xx-i2s-objs := mt76xx_i2s.o + +obj-$(CONFIG_SND_MT76XX_PCM) += snd-soc-mt76xx-pcm.o +obj-$(CONFIG_SND_MT76XX_I2S) += snd-soc-mt76xx-i2s-ctl.o snd-soc-mt76xx-i2s.o + +# MTK APSoC Machine Support +snd-soc-mt76xx-machine-objs := mt76xx_machine.o + +obj-$(CONFIG_SND_MT76XX_SOC) += i2c_wm8960.o ralink_gdma.o snd-soc-mt76xx-machine.o + + + diff --git a/sound/soc/mtk/i2c_wm8960.c b/sound/soc/mtk/i2c_wm8960.c new file mode 100644 index 0000000..70f16e1 --- /dev/null +++ b/sound/soc/mtk/i2c_wm8960.c @@ -0,0 +1,492 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if defined(CONFIG_ARCH_MT7623) +#include +#include +#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 "); +MODULE_DESCRIPTION("WM8960 I2C client driver"); +MODULE_LICENSE("GPL"); + diff --git a/sound/soc/mtk/i2c_wm8960.h b/sound/soc/mtk/i2c_wm8960.h new file mode 100644 index 0000000..c769345 --- /dev/null +++ b/sound/soc/mtk/i2c_wm8960.h @@ -0,0 +1,288 @@ +/* wm8960.h -- WM8960 Soc Audio driver */ +#ifndef _WM8960_H +#define _WM8960_H + +#define bool unsigned char +#define false 0 +#define true 1 + +/* volume/balance/treble/bass interdependency */ +#define VOLUME_MIN -730 +#define VOLUME_MAX 60 + + +/* Register addresses and bits */ +#define OUTPUT_MUTED 0x2f +#define OUTPUT_0DB 0x79 + +#define LINV 0x00 +#define LINV_IPVU (1 << 8) /* FIXME */ +#define LINV_LINMUTE (1 << 7) +#define LINV_LIZC (1 << 6) +#define LINV_LINVOL(x) ((x) & 0x3f) + +#define RINV 0x01 +#define RINV_IPVU (1 << 8) /* FIXME */ +#define RINV_RINMUTE (1 << 7) +#define RINV_RIZC (1 << 6) +#define RINV_RINVOL(x) ((x) & 0x3f) + +#define LOUT1 0x02 +#define LOUT1_LO1VU (1 << 8) +#define LOUT1_LO1ZC (1 << 7) +#define LOUT1_LOUT1VOL(x) ((x) & 0x7f) + +#define ROUT1 0x03 +#define ROUT1_RO1VU (1 << 8) +#define ROUT1_RO1ZC (1 << 7) +#define ROUT1_ROUT1VOL(x) ((x) & 0x7f) + +#define CLOCKING1 0x04 /* FIXME */ +#define CLOCKING1_ADCDIV(x) (((x) & 0x7) << 6) +#define CLOCKING1_DACDIV(x) (((x) & 0x7) << 3) +#define CLOCKING1_SYSCLKDIV_1 (0 << 1) +#define CLOCKING1_SYSCLKDIV_2 (2 << 1) +#define CLOCKING1_CLKSEL_MCLK (0 << 0) +#define CLOCKING1_CLKSEL_PLL (1 << 0) + +#define DACCTRL1 0x05 +#define DACCTRL1_DATTENUATE (1 << 7) +#define DACCTRL1_DACMU (1 << 3) +#define DACCTRL1_DEEMPH_48 (3 << 1) +#define DACCTRL1_DEEMPH_44 (2 << 1) +#define DACCTRL1_DEEMPH_32 (1 << 1) +#define DACCTRL1_DEEMPH_NONE (0 << 1) +#define DACCTRL1_DEEMPH(x) ((x) & (0x3 << 1)) + +#define DACCTRL2 0x06 + +#define AINTFCE1 0x07 +#define AINTFCE1_BCLKINV (1 << 7) +#define AINTFCE1_MS (1 << 6) +#define AINTFCE1_LRSWAP (1 << 5) +#define AINTFCE1_LRP (1 << 4) +#define AINTFCE1_WL_32 (3 << 2) +#define AINTFCE1_WL_24 (2 << 2) +#define AINTFCE1_WL_20 (1 << 2) +#define AINTFCE1_WL_16 (0 << 2) +#define AINTFCE1_WL(x) (((x) & 0x3) << 2) +#define AINTFCE1_FORMAT_DSP (3 << 0) +#define AINTFCE1_FORMAT_I2S (2 << 0) +#define AINTFCE1_FORMAT_LJUST (1 << 0) +#define AINTFCE1_FORMAT_RJUST (0 << 0) +#define AINTFCE1_FORMAT(x) ((x) & 0x3) + +/* FIXME */ +#define CLOCKING2 0x08 +#define CLOCKING2_DCLKDIV(x) (((x) & 0x7) << 6) +#define CLOCKING2_BCLKDIV(x) (((x) & 0xf) << 0) + +#define AINTFCE2 0x09 +#define AINTFCE2_ALRCGPIO_ALRC (0 << 6) +#define AINTFCE2_ALRCGPIO_GPIO (1 << 6) +#define AINTFCE2_LOOPBACK (1 << 0) + +#define LEFTGAIN 0x0a +#define LEFTGAIN_LDVU (1 << 8) +#define LEFTGAIN_LDACVOL(x) ((x) & 0xff) + +#define RIGHTGAIN 0x0b +#define RIGHTGAIN_RDVU (1 << 8) +#define RIGHTGAIN_RDACVOL(x) ((x) & 0xff) + +#define RESET 0x0f +#define RESET_RESET 0x000 + +#define ALC1 0x11 +#define ALC1_ALCOFF (0x0 << 7) +#define ALC1_ALCRONLY (0x1 << 7) +#define ALC1_ALCLONLY (0x2 << 7) +#define ALC1_ALCSTEREO (0x3 << 7) +#define ALC1_ALCSEL(x) (((x) & 0x3) << 7) +#define ALC1_SET_MAXGAIN(x) ((x & 0x7) << 4) +#define ALC1_GET_MAXGAIN(x) ((x) & (0x7 << 4)) +#define ALC1_ALCL(x) ((x) & 0x0f) + +#define ALC2 0x12 +#define ALC2_MINGAIN(x) ((x & 0x7) << 4) +#define ALC2_HLD(x) ((x) & 0x0f) + +#define ALC3 0x13 +#define ALC3_SET_DCY(x) ((x & 0x0f) << 4) +#define ALC3_GET_DCY(x) ((x) & (0x0f << 4)) +#define ALC3_ATK(x) ((x) & 0x0f) + +#define NOISEGATE 0x14 +#define NOISEGATE_SET_NGTH(x) ((x & 0x1f) << 3) +#define NOISEGATE_GET_NGTH(x) ((x) & (0x1f << 3)) +#define NOISEGATE_NGAT_ENABLE 1 + +#define LADCVOL 0x15 +#define LADCVOL_LAVU_EN (1 << 8) +#define LADCVOL_LADCVOL(x) ((x) & 0x0ff) + +#define RADCVOL 0x16 +#define RADCVOL_RAVU_EN (1 << 8) +#define RADCVOL_RADCVOL(x) ((x) & 0x0ff) + +#define ADDITIONAL1 0x17 +#define ADDITIONAL1_TSDEN (1 << 8) +#define ADDITIONAL1_VSEL_LOWEST (0 << 6) +#define ADDITIONAL1_VSEL_LOW (1 << 6) +#define ADDITIONAL1_VSEL_DEFAULT2 (2 << 6) +#define ADDITIONAL1_VSEL_DEFAULT (3 << 6) +#define ADDITIONAL1_VSEL(x) (((x) & 0x3) << 6) +#define ADDITIONAL1_DMONOMIX_STEREO (0 << 4) +#define ADDITIONAL1_DMONOMIX_MONO (1 << 4) +#define ADDITIONAL1_DATSEL(x) (((x) & 0x3) << 2) +#define ADDITIONAL1_TOCLKSEL (1 << 1) +#define ADDITIONAL1_TOEN (1 << 0) + +#define ADDITIONAL2 0x18 +#define ADDITIONAL2_HPSWEN (1 << 6) +#define ADDITIONAL2_HPSWPOL (1 << 5) +#define ADDITIONAL2_TRIS (1 << 3) +#define ADDITIONAL2_LRCM_ON (1 << 2) + +#define PWRMGMT1 0x19 +#define PWRMGMT1_VMIDSEL_DISABLED (0 << 7) +#define PWRMGMT1_VMIDSEL_50K (1 << 7) +#define PWRMGMT1_VMIDSEL_250K (2 << 7) +#define PWRMGMT1_VMIDSEL_5K (3 << 7) +#define PWRMGMT1_VREF (1 << 6) +#define PWRMGMT1_AINL (1 << 5) +#define PWRMGMT1_AINR (1 << 4) +#define PWRMGMT1_ADCL (1 << 3) +#define PWRMGMT1_ADCR (1 << 2) +#define PWRMGMT1_MICB (1 << 1) +#define PWRMGMT1_DIGENB (1 << 0) + +#define PWRMGMT2 0x1a +#define PWRMGMT2_DACL (1 << 8) +#define PWRMGMT2_DACR (1 << 7) +#define PWRMGMT2_LOUT1 (1 << 6) +#define PWRMGMT2_ROUT1 (1 << 5) +#define PWRMGMT2_SPKL (1 << 4) +#define PWRMGMT2_SPKR (1 << 3) +#define PWRMGMT2_OUT3 (1 << 1) +#define PWRMGMT2_PLL_EN (1 << 0) + +#define ADDITIONAL3 0x1b +#define ADDITIONAL3_VROI (1 << 6) +#define ADDITIONAL3_OUT3CAP (1 << 3) +#define ADDITIONAL3_ADC_ALC_SR(x) ((x) & 0x7) + +#define ANTIPOP1 0x1c +#define ANTIPOP2 0x1d + +#define ADCLPATH 0x20 +#define ADCLPATH_LMN1 (1 << 8) +#define ADCLPATH_LMP3 (1 << 7) +#define ADCLPATH_LMP2 (1 << 6) +#define ADCLPATH_LMICBOOST_29DB (0x3 << 4) +#define ADCLPATH_LMICBOOST_20DB (0x2 << 4) +#define ADCLPATH_LMICBOOST_13DB (0x1 << 4) +#define ADCLPATH_SET_LMICBOOST(x) ((x & 0x3) << 4) +#define ADCLPATH_LMIC2B (1 << 3) + + +#define ADCRPATH 0x21 +#define ADCRPATH_RMN1 (1 << 8) +#define ADCRPATH_RMP3 (1 << 7) +#define ADCRPATH_RMP2 (1 << 6) +#define ADCRPATH_RMICBOOST_29DB (0x3 << 4) +#define ADCRPATH_RMICBOOST_20DB (0x2 << 4) +#define ADCRPATH_RMICBOOST_13DB (0x1 << 4) +#define ADCRPATH_SET_RMICBOOST(x) ((x & 0x3) << 4) +#define ADCRPATH_RMIC2B (1 << 3) + + +#define LEFTMIX1 0x22 +#define LEFTMIX1_LD2LO (1 << 8) +#define LEFTMIX1_LI2LO (1 << 7) +#define LEFTMIX1_LI2LO_DEFAULT (5 << 4) +#define LEFTMIX1_LI2LOVOL(x) (((x) & 0x7) << 4) + +#define RIGHTMIX2 0x25 +#define RIGHTMIX2_RD2RO (1 << 8) +#define RIGHTMIX2_RI2RO (1 << 7) +#define RIGHTMIX2_RI2RO_DEFAULT (5 << 4) +#define RIGHTMIX2_RI2ROVOL(x) (((x) & 0x7) << 4) + +#define MONOMIX1 0x26 +#define MONOMIX1_L2MO (1 << 7) + +#define MONOMIX2 0x27 +#define MONOMIX2_R2MO (1 << 7) + +#define LSPK 0x28 +#define LSPK_SPKLVU (1 << 8) +#define LSPK_SPKLZC (1 << 7) +#define LSPK_SPKLVOL(x) ((x) & 0x7f) + +#define RSPK 0x29 +#define RSPK_SPKRVU (1 << 8) +#define RSPK_SPKRZC (1 << 7) +#define RSPK_SPKRVOL(x) ((x) & 0x7f) + +#define OUT3V 0x2a +#define LINBMIX 0x2b +#define RINBMIX 0x2c +#define BYPASS1 0x2d +#define BYPASS2 0x2e + +#define PWRMGMT3 0x2f +#define PWRMGMT3_LMIC (1<<5) +#define PWRMGMT3_RMIC (1<<4) +#define PWRMGMT3_LOMIX (1<<3) +#define PWRMGMT3_ROMIX (1<<2) + +#define ADDITIONAL4 0x30 + +#define CLASSDCTRL1 0x31 +#define CLASSDCTRL1_OP_OFF (0<<6) +#define CLASSDCTRL1_OP_LSPK (1<<6) +#define CLASSDCTRL1_OP_RSPK (2<<6) +#define CLASSDCTRL1_OP_LRSPK (3<<6) + +#define CLASSDCTRL3 0x33 + +#define PLL1 0x34 +#define PLL1_OPCLKDIV_1 (0<<6) +#define PLL1_OPCLKDIV_2 (1<<6) +#define PLL1_OPCLKDIV_3 (2<<6) +#define PLL1_OPCLKDIV_4 (3<<6) +#define PLL1_OPCLKDIV_5p5 (4<<6) +#define PLL1_OPCLKDIV_6 (5<<6) +#define PLL1_SDM_INTERGER (0<<5) +#define PLL1_SDM_FRACTIONAL (1<<5) +#define PLL1_PLLPRESCALE_1 (0<<4) +#define PLL1_PLLPRESCALE_2 (1<<4) +#define PLL1_PLLN(x) ((x) & 0xf) + +#define PLL2 0x35 +#define PLL2_PLLK_23_16(x) ((x) & 0x1ff) + +#define PLL3 0x36 +#define PLL3_PLLK_15_8(x) ((x) & 0x1ff) + +#define PLL4 0x37 +#define PLL4_PLLK_7_0(x) ((x) & 0x1ff) + +/* codec API */ +void audiohw_preinit(void); +int audiohw_postinit(int bSlave, int AIn, int AOut, int pll_en, int wordLen24b); +void audiohw_close(void); +void audiohw_set_frequency(int fsel, int pll_en); +void audiohw_mute(bool mute); +void audiohw_micboost(int boostgain); +void audiohw_micin(int enableMic); +void audiohw_set_apll(int srate); +int audiohw_set_lineout_vol(int Aout, int vol_l, int vol_r); +int audiohw_set_linein_vol(int vol_l, int vol_r); +void audiohw_mute( bool mute); +void audiohw_loopback(int fsel); +void audiohw_codec_exlbk(void); +void audiohw_bypass(void); + +#endif /* _WM875x_H */ diff --git a/sound/soc/mtk/i2s_ctrl.c b/sound/soc/mtk/i2s_ctrl.c new file mode 100644 index 0000000..05034b0 --- /dev/null +++ b/sound/soc/mtk/i2s_ctrl.c @@ -0,0 +1,3524 @@ +#include +#include +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,35) +#include +#endif +#include +#include /* _printk() */ +#include /* kmalloc() */ +#include /* everything... */ +#include /* error codes */ +#include /* size_t */ +#include +#include /* O_ACCMODE */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(3,10,14) +#include /* cli(), *_flags */ +#endif +#include /* copy_from/to_user */ +#include +#include +#include +#include +#include +#include "ralink_gdma.h" +#if defined(CONFIG_I2S_WITH_AEC) +#include "../aec/aec_api.h" +#endif + +#ifdef CONFIG_DEVFS_FS +#include +static devfs_handle_t devfs_handle; +#endif + +#include "i2s_ctrl.h" + +#if defined(CONFIG_SND_MT76XX_SOC) +#include +#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; immap_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<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<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<rx_unmask_ch |= (1<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; ilock, 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)||(argsrate = 48000; + spin_unlock(&ptri2s_config->lock); + break; + } +#elif defined(CONFIG_I2S_WM8750) + if((arg>MAX_SRATE_HZ)||(argsrate = 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 "); +MODULE_SUPPORTED_DEVICE("I2S"); +MODULE_VERSION(I2S_MOD_VERSION); +MODULE_LICENSE("GPL"); +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,12) +MODULE_PARM (i2sdrv_major, "i"); +#else +module_param (i2sdrv_major, int, 0); +#endif diff --git a/sound/soc/mtk/i2s_ctrl.h b/sound/soc/mtk/i2s_ctrl.h new file mode 100644 index 0000000..b762c9c --- /dev/null +++ b/sound/soc/mtk/i2s_ctrl.h @@ -0,0 +1,523 @@ +#ifndef __RALINK_I2S_H_ +#define __RALINK_I2S_H_ + +#ifdef __KERNEL__ +//#include +#endif + +#if defined(CONFIG_I2S_WITH_AEC) +#include "aec/aec_api.h" +#endif + +#define I2S_MAX_DEV 1 +#define I2S_MOD_VERSION "0.1" +#define phys_to_bus(a) (a & 0x1FFFFFFF) + +#ifndef u32 +#define u32 unsigned int +#endif + +#ifndef u16 +#define u16 unsigned short +#endif + +#ifndef u8 +#define u8 unsigned char +#endif + +#ifndef REGBIT +#define REGBIT(x, n) (x << n) +#endif + +#define Virtual2Physical(x) (((int)x) & 0x1fffffff) +#define Physical2Virtual(x) (((int)x) | 0x80000000) +#define Virtual2NonCache(x) (((int)x) | 0x20000000) +#define Physical2NonCache(x) (((int)x) | 0xa0000000) +#define NonCache2Virtual(x) (((int)x) & 0xDFFFFFFF) + +#if defined(CONFIG_I2S_MCLK_12MHZ) +#define CONFIG_I2S_CODEC_PLL_EN 1 +#else +#define CONFIG_I2S_CODEC_PLL_EN 0 +#endif + +//#define CONFIG_I2S_MS_CTRL +//#define CONFIG_I2S_MS_MODE +//#define memory_test + +#if defined (CONFIG_ARCH_MT7623) +#define MT7623_ASIC_BOARD +#define ARM_ARCH +#endif + +#if defined (CONFIG_RALINK_MT7621) +#define MT7621_ASIC_BOARD +#endif + +#if defined (CONFIG_RALINK_MT7628) +#define MT7628_ASIC_BOARD +#endif + +//#define I2S_DEBUG_PRN +#ifdef I2S_DEBUG_PRN +#define MSG(fmt, args...) printk("I2S: " fmt, ## args) +#else +#define MSG(fmt, args...) { } +#endif + +#ifdef I2S_DEBUG_PRN +#define i2s_outw(address, value) do{printk("0x%08X = 0x%08X\n",(u32)address,(u32)value);*((volatile uint32_t *)(address)) = cpu_to_le32(value);}while(0) +#else +#define i2s_outw(address, value) *((volatile uint32_t *)(address)) = cpu_to_le32(value) +#endif +#define i2s_inw(address) le32_to_cpu(*(volatile u32 *)(address)) + +/* HW feature definiations */ +#if defined(CONFIG_RALINK_RT3883) +#define CONFIG_I2S_TXRX 1 +#define CONFIG_I2S_IN_MCLK 1 +//#define CONFIG_I2S_WS_EDGE 1 +#define CONFIG_I2S_FRAC_DIV 1 +#define CONFIG_I2S_IN_CLK 1 +#define CONFIG_I2S_MS_MODE 1 +#endif + +#if defined(CONFIG_RALINK_RT3352)||defined(CONFIG_RALINK_RT5350) || defined (CONFIG_RALINK_RT6855) \ + || defined(CONFIG_RALINK_RT6855A) || defined(CONFIG_RALINK_MT7620) || defined(CONFIG_RALINK_MT7621) \ + || defined (CONFIG_RALINK_MT7628) || defined(CONFIG_ARCH_MT7623) +#define CONFIG_I2S_TXRX 1 +//#define CONFIG_I2S_WS_EDGE 1 +#define CONFIG_I2S_FRAC_DIV 1 +#define CONFIG_I2S_IN_CLK 1 +#endif + +#if defined(CONFIG_RALINK_RT3350) +#define CONFIG_I2S_IN_MCLK 1 +#endif + +#if defined(CONFIG_RALINK_RT3052) +#define CONFIG_I2S_MS_MODE 1 +#endif + +/* This is decided in menuconfig */ +#define CONFIG_I2S_MMAP 1 + +/* For MT7623 ASIC PLL Setting */ +#if defined(CONFIG_ARCH_MT7623) +#define AUD1PLL_CON0 (0xF0209270) +#define AUD1PLL_CON1 (0xF0209274) +#define AUD1PLL_CON2 (0xF0209278) +#define AUD1PLL_PWR_CON0 (0xF020927C) +#define AUD2PLL_CON0 (0xF02092C0) +#define AUD2PLL_CON1 (0xF02092C4) +#define AUD2PLL_CON2 (0xF02092C8) +#define AUD2PLL_PWR_CON0 (0xF02092CC) +#endif + +/* Register Map, Ref to RT3052 Data Sheet */ + +/* Register Map Detail */ +#if defined(CONFIG_ARCH_MT7623) +#define I2S_I2SCFG (ETHDMASYS_I2S_BASE+0x0000) +#define I2S_INT_STATUS (ETHDMASYS_I2S_BASE+0x0004) +#define I2S_INT_EN (ETHDMASYS_I2S_BASE+0x0008) +#define I2S_FF_STATUS (ETHDMASYS_I2S_BASE+0x000c) +#define I2S_FIFO_WREG (ETHDMASYS_I2S_BASE+0x0010) +#define I2S_TX_FIFO_WREG I2S_FIFO_WREG +#define I2S_RX_FIFO_RREG (ETHDMASYS_I2S_BASE+0x0014) +#define I2S_I2SCFG1 (ETHDMASYS_I2S_BASE+0x0018) +#define I2S_DIVINT_CFG (ETHDMASYS_I2S_BASE+0x0024) +#define I2S_DIVCOMP_CFG (ETHDMASYS_I2S_BASE+0x0020) +#else +#define I2S_I2SCFG (RALINK_I2S_BASE+0x0000) +#define I2S_INT_STATUS (RALINK_I2S_BASE+0x0004) +#define I2S_INT_EN (RALINK_I2S_BASE+0x0008) +#define I2S_FF_STATUS (RALINK_I2S_BASE+0x000c) +#define I2S_FIFO_WREG (RALINK_I2S_BASE+0x0010) +#define I2S_TX_FIFO_WREG I2S_FIFO_WREG +#define I2S_RX_FIFO_RREG (RALINK_I2S_BASE+0x0014) +#define I2S_I2SCFG1 (RALINK_I2S_BASE+0x0018) +#define I2S_DIVINT_CFG (RALINK_I2S_BASE+0x0024) +#define I2S_DIVCOMP_CFG (RALINK_I2S_BASE+0x0020) +#endif + + +/* I2SCFG bit field */ +#define I2S_EN 31 +#define I2S_DMA_EN 30 +#if defined(CONFIG_RALINK_MT7628) || defined(CONFIG_ARCH_MT7623) +#define I2S_LITTLE_ENDIAN 29 +#define I2S_SYS_ENDIAN 28 +#elif defined(CONFIG_RALINK_RT6855A) +#define I2S_BYTE_SWAP 28 +#endif +#define I2S_TX_EN 24 +#define I2S_RX_EN 20 +#if defined(CONFIG_RALINK_MT7628) || defined(CONFIG_ARCH_MT7623) +#define I2S_NORM_24BIT 18 +#define I2S_DATA_24BIT 17 +#endif +#define I2S_SLAVE_MODE 16 +#define I2S_RX_FF_THRES 12 +#define I2S_RX_CH_SWAP 11 +#define I2S_RX_CH1_OFF 10 +#define I2S_RX_CH0_OFF 9 +#if defined(CONFIG_RALINK_RT3052) +#define I2S_CLK_OUT_DIS 8 +#endif +#define I2S_TX_FF_THRES 4 +#define I2S_TX_CH_SWAP 3 +#define I2S_TX_CH1_OFF 2 +#define I2S_TX_CH0_OFF 1 +#if defined(CONFIG_RALINK_RT3052) +#define I2S_SLAVE_EN 0 +#else +#define I2S_WS_INV 0 +#endif +/* INT_EN bit field */ +#define I2S_RX_INT3_EN 7 +#define I2S_RX_INT2_EN 6 +#define I2S_RX_INT1_EN 5 +#define I2S_RX_INT0_EN 4 +#define I2S_TX_INT3_EN 3 +#define I2S_TX_INT2_EN 2 +#define I2S_TX_INT1_EN 1 +#define I2S_TX_INT0_EN 0 + +/* INT_STATUS bit field */ +#define I2S_RX_DMA_FAULT 7 +#define I2S_RX_OVRUN 6 +#define I2S_RX_UNRUN 5 +#define I2S_RX_THRES 4 +#define I2S_TX_DMA_FAULT 3 +#define I2S_TX_OVRUN 2 +#define I2S_TX_UNRUN 1 +#define I2S_TX_THRES 0 + +/* FF_STATUS bit field */ +#define I2S_RX_EPCNT 4 +#define I2S_TX_EPCNT 0 +/* I2S_DIVCOMP_CFG bit field */ +#define I2S_CLKDIV_EN 31 + +/* I2S_CFG1 bit field */ +#define I2S_LBK_EN 31 +#define I2S_EXT_LBK_EN 30 +#if defined(CONFIG_RALINK_MT7628) || defined(CONFIG_ARCH_MT7623) +#define I2S_DATA_FMT 0 +#endif + +/* FIFO_WREG bit field */ +#define I2S_FIFO_WDATA 0 + +/* Constant definition */ +#define NFF_THRES 4 +#define I2S_PAGE_SIZE 3072//(3*4096)//(1152*2*2*2) +#define I2S_MIN_PAGE_SIZE 4096 +#define MAX_I2S_PAGE 8 +#define I2S_TOTAL_PAGE_SIZE (I2S_PAGE_SIZE*MAX_I2S_PAGE) + +#if defined(CONFIG_I2S_WM8960) +#define MAX_SRATE_HZ 48000 +#define MIN_SRATE_HZ 8000 +#elif defined(CONFIG_I2S_WM8750) +#define MAX_SRATE_HZ 96000 +#define MIN_SRATE_HZ 8000 +#endif + +#define MAX_VOL_DB +0 +#define MIN_VOL_DB -127 + +#define ALSA_MMAP_IDX_SHIFT 2 +#if defined(CONFIG_SND_MT76XX_SOC) +#define STREAM_PLAYBACK SNDRV_PCM_STREAM_PLAYBACK +#define STREAM_CAPTURE SNDRV_PCM_STREAM_CAPTURE +#else +#define STREAM_PLAYBACK 0 +#define STREAM_CAPTURE 1 +#endif + +/* I2S I/O command */ +#define I2S_SRATE 0 +#define I2S_VOL 1 +#define I2S_ENABLE 2 +#define I2S_DISABLE 3 +#define I2S_TX_ENABLE 27 +#define I2S_TX_DISABLE 3 +#define I2S_GET_WBUF 4 +#define I2S_PUT_WBUF 5 +#define I2S_RX_ENABLE 6 +#define I2S_RX_DISABLE 7 +#define I2S_PUT_AUDIO 4 +#define I2S_GET_AUDIO 5 +#define I2S_TX_VOL 1 +#define I2S_RX_VOL 8 +#define I2S_WORD_LEN 9 +#define I2S_ENDIAN_FMT 10 +#define I2S_INTERNAL_LBK 11 +#define I2S_TX_STOP 12 +#define I2S_DEBUG_CODEC 13 +#define I2S_MS_MODE_CTRL 14 +#define I2S_TX_PAUSE 15 +#define I2S_TX_RESUME 16 +#define I2S_RESET 17 +#define I2S_RX_STOP 18 +#define I2S_EXTERNAL_LBK 19 +#define I2S_TXRX_COEXIST 20 +#define I2S_RX_PAUSE 21 +#define I2S_RX_RESUME 22 +#define I2S_CODEC_MIC_BOOST 23 +#define I2S_CODEC_MIC_IN 24 +#define I2S_CLOCK_ENABLE 25 +#define I2S_TEST_TEST 26 + +#define I2S_DEBUG 30 +#define I2S_DEBUG_CLKGEN 30 +#define I2S_DEBUG_INLBK 31 +#define I2S_DEBUG_EXLBK 32 +#define I2S_DEBUG_FMT 33 +#define I2S_DEBUG_RESET 34 +#define I2S_DEBUG_CODECBYPASS 35 +#if defined(CONFIG_I2S_WM8960) +#define I2S_DEBUG_CODEC_EXLBK 36 +#endif + +/* configuration */ +#define CONFIG_I2S_TFF_THRES NFF_THRES +#define CONFIG_I2S_CH_SWAP 0 +#if defined(CONFIG_I2S_MS_MODE) +#define CONFIG_I2S_SLAVE_EN 0 +#else +#define CONFIG_I2S_SLAVE_EN 1 +#endif + +/* driver status definition */ +#define I2S_OK 0 +#define I2S_OUTOFMEM 0x01 +#define I2S_GDMAFAILED 0x02 +#define I2S_REQUEST_IRQ_FAILED 0x04 +#define I2S_REG_SETUP_FAILED 0x08 + +#define I2S_STATISTIC +//#define I2S_HW_INTERRUPT_EN +//#define I2S_SW_IRQ_EN +#define I2S_MAJOR 234 + +/* parameter for ALSA */ +/*GDMA for I2S Status*/ +#define GDMA_I2S_DIS (0) +#define GDMA_I2S_EN (1) + + +typedef struct i2s_status_t +{ + u32 txdmafault; + u32 txovrun; + u32 txunrun; + u32 txthres; + int txbuffer_unrun; + int txbuffer_ovrun; + int txbuffer_len; + + u32 rxdmafault; + u32 rxovrun; + u32 rxunrun; + u32 rxthres; + int rxbuffer_unrun; + int rxbuffer_ovrun; + int rxbuffer_len; +}i2s_status_type; + + +typedef struct i2s_config_t +{ + + int srate; + int txvol; + int rxvol; + u32 pos; + u32 tx_isr_cnt; + u32 rx_isr_cnt; + int bSleep; + int bTxDMAEnable; + int bRxDMAEnable; + int enLable; + int micboost; + int micin; + + /* parameters fo ALSA */ + int bALSAEnable; + int bALSAMMAPEnable; + unsigned char bTrigger[2]; + unsigned char bPreTrigger[2]; + unsigned char dmaStat[2]; + unsigned char i2sStat[2]; + unsigned int hw_base_frame[2]; + struct snd_pcm_substream *pss[2]; + +#ifdef __KERNEL__ + spinlock_t lock; + wait_queue_head_t i2s_tx_qh, i2s_rx_qh; +#endif + u32 dmach; + u32 tx_unmask_ch; + u32 rx_unmask_ch; + u32 dma_unmask_status; + u32 dma_done_status; + u32 tx_ff_thres; + u32 tx_ch_swap; + u32 rx_ff_thres; + u32 rx_ch_swap; + u32 slave_en; + + u32 dis_match; + int start_cnt; +#if defined (CONFIG_RALINK_MT7628) || defined(CONFIG_ARCH_MT7623) + int little_edn; /* test file's fmt: little endian->1; big endian->0 */ + int sys_endian; /* kernal' system fmt: little endian->0; big endian->1 */ +#endif + int wordlen_24b; + int codec_pll_en; + int codec_num; + int tx_pause_en; + int rx_pause_en; + int end_cnt; + int txrx_coexist; + int tx_stop_cnt; + int rx_stop_cnt; + /* for I2S_CFG1 */ + u32 lbk; + u32 extlbk; + u32 fmt; + + int w_idx; + int r_idx; + + int tx_w_idx; + int tx_r_idx; + int rx_w_idx; + int rx_r_idx; + int mmap_index; + int next_p0_idx; + int next_p1_idx; + + u8* buf8ptr; + char* pMMAPBufPtr[MAX_I2S_PAGE*2]; + char* pMMAPTxBufPtr[MAX_I2S_PAGE]; + char* pMMAPRxBufPtr[MAX_I2S_PAGE]; + + union { + u16* pPage0TxBuf16Ptr; + u8* pPage0TxBuf8ptr; + }; + union { + u16* pPage1TxBuf16Ptr; + u8* pPage1TxBuf8ptr; + }; + + union { + u16* pPage0RxBuf16Ptr; + u8* pPage0RxBuf8ptr; + }; + union { + u16* pPage1RxBuf16Ptr; + u8* pPage1RxBuf8ptr; + }; + +}i2s_config_type; + + +void i2s_gen_test_pattern(void); +int i2s_mem_unmap(i2s_config_type* ptri2s_config); +int i2s_param_init(i2s_config_type* ptri2s_config); +int i2s_txbuf_alloc(i2s_config_type* ptri2s_config); +int i2s_rxbuf_alloc(i2s_config_type* ptri2s_config); +int i2s_txPagebuf_alloc(i2s_config_type* ptri2s_config); +int i2s_rxPagebuf_alloc(i2s_config_type* ptri2s_config); +int i2s_txbuf_free(i2s_config_type* ptri2s_config); +int i2s_rxbuf_free(i2s_config_type* ptri2s_config); +int i2s_txPagebuf_free(i2s_config_type* ptri2s_config); +int i2s_rxPagebuf_free(i2s_config_type* ptri2s_config); +int i2s_reset_tx_param(i2s_config_type* ptri2s_config); +int i2s_reset_rx_param(i2s_config_type* ptri2s_config); +int i2s_tx_config(i2s_config_type* ptri2s_config); +int i2s_rx_config(i2s_config_type* ptri2s_config); +int i2s_tx_enable(i2s_config_type* ptri2s_config); +int i2s_tx_disable(i2s_config_type* ptri2s_config); +int i2s_rx_enable(i2s_config_type* ptri2s_config); +int i2s_rx_disable(i2s_config_type* ptri2s_config); +int i2s_codec_enable(i2s_config_type* ptri2s_config); +int i2s_codec_disable(i2s_config_type* ptri2s_config); +int i2s_clock_enable(i2s_config_type* ptri2s_config); +int i2s_clock_disable(i2s_config_type* ptri2s_config); +int i2s_reset_config(i2s_config_type* ptri2s_config); +int i2s_refclk_disable(void); +int i2s_refclk_gpio_out_config(void); +int i2s_refclk_gpio_in_config(void); +int i2s_share_pin_config(i2s_config_type* ptri2s_config); +int i2s_share_pin_mt7623(i2s_config_type* ptri2s_config); +int i2s_master_clock_gpio_out_mt7623(void); +int i2s_slave_clock_gpio_in_mt7623(void); +int i2s_ws_config(i2s_config_type* ptri2s_config, unsigned long index); +int i2s_mode_config(u32 slave_en); +int i2s_codec_frequency_config(i2s_config_type* ptri2s_config, unsigned long index); +void i2s_tx_end_sleep_on(i2s_config_type* ptri2s_config); +void i2s_rx_end_sleep_on(i2s_config_type* ptri2s_config); + +#if defined(CONFIG_I2S_MCLK_12MHZ) +int i2s_refclk_12m_enable(void); +#endif +#if defined(CONFIG_I2S_MCLK_12P288MHZ) +int i2s_refclk_12p288m_enable(void); +#endif + +#if defined(MT7621_ASIC_BOARD) +int i2s_pll_config_mt7621(unsigned long index); +int i2s_pll_refclk_set(void); +#endif +#if defined(MT7623_ASIC_BOARD) +int i2s_pll_config_mt7623(unsigned long index); +#endif +#if defined(MT7628_ASIC_BOARD) || defined(CONFIG_ARCH_MT7623) +int i2s_driving_strength_adjust(void); +#endif +#if defined(I2S_STATISTIC) +void i2s_int_status(u32 dma_ch); +#endif +void i2s_dma_tx_handler(u32 dma_ch); +void i2s_dma_rx_handler(u32 dma_ch); +void i2s_dma_unmask_handler(u32 dma_ch); +void i2s_dma_mask_handler(u32 dma_ch); +void i2s_dma_tx_init(i2s_config_type* ptri2s_config); +void i2s_dma_rx_init(i2s_config_type* ptri2s_config); +void i2s_tx_task(unsigned long pData); +void i2s_rx_task(unsigned long pData); +void i2s_dma_tx_unmask_handler(u32 dma_ch); +void i2s_dma_rx_unmask_handler(u32 dma_ch); +int i2s_dma_tx_transf_data(i2s_config_type* ptri2s_config, u32 dma_ch); +int i2s_dma_tx_transf_zero(i2s_config_type* ptri2s_config, u32 dma_ch); +int i2s_dma_rx_transf_data(i2s_config_type* ptri2s_config, u32 dma_ch); +int i2s_dma_rx_transf_zero(i2s_config_type* ptri2s_config, u32 dma_ch); +void i2s_dma_tx_end_handle(i2s_config_type* ptri2s_config); +int i2s_dma_tx_soft_stop(i2s_config_type* ptri2s_config, u32 dma_ch); +int i2s_dma_rx_soft_stop(i2s_config_type* ptri2s_config, u32 dma_ch); + +int i2s_page_prepare(i2s_config_type* ptri2s_config,int dir); +int i2s_page_release(i2s_config_type* ptri2s_config,int dir); +int gdma_En_Switch(i2s_config_type* ptri2s_config,int dir,int enabled); +int i2s_startup(void); +int i2s_audio_exchange(i2s_config_type* ptri2s_config,int dir,unsigned long arg); +void gdma_unmask_handler(u32 dma_ch); +char* i2s_memPool_Alloc(i2s_config_type* ptri2s_config,int dir); +void i2s_memPool_free(i2s_config_type* ptri2s_config,int dir); +u32 i2s_mmap_phys_addr(i2s_config_type* ptri2s_config); + +#if !defined(CONFIG_I2S_TXRX) +#define GdmaI2sRx //GdmaI2sRx +#endif + +#define RALINK_I2S_VERSION "1.0" +#define I2SDRV_DEVNAME "i2s0" + +#endif /* __RALINK_I2S_H_ */ + diff --git a/sound/soc/mtk/i2s_debug.c b/sound/soc/mtk/i2s_debug.c new file mode 100644 index 0000000..9f61b14 --- /dev/null +++ b/sound/soc/mtk/i2s_debug.c @@ -0,0 +1,698 @@ +#include +#include +#include +#include /* printk() */ +#include "i2s_ctrl.h" +#include +#include +#include +#include +#include /* copy_from/to_user */ + +#if defined(CONFIG_SND_RALINK_SOC) +#include +#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>8)&0xFF) > 0) + #else + if(((ff_status>>4)&0x0F) > 0) + #endif + { + //data = *(volatile unsigned long*)(RALINK_I2S_BASE+0x14); + data = *(volatile unsigned long*)(I2S_RX_FIFO_RREG); + } + else + { + printk("*NO RX FREE FIFO ST=[0x%08X]\n", (u32)ff_status); + continue; + } + + if(data!= txbuffer[temp+j]) + { + MSG("[%d][0x%08X] vs [0x%08X]\n", (temp+j), (u32)data, (u32)txbuffer[temp+j]); + } + else + { + //MSG("&&[%d][0x%08X] vs [0x%08X]\n" ,(temp+j), (u32)data , (u32)txbuffer[temp+j]); + count++; + data=0; + } + if ((temp+j)==128) + { + //ff_status = *(volatile unsigned long*)(RALINK_I2S_BASE+0x0C); + ff_status = *(volatile unsigned long*)(I2S_FF_STATUS); + //printk("[%d]FIFO ST=[0x%08X]\n", (temp+j), (u32)ff_status); + } + } +#endif + +#if defined (INTERNAL_LOOPBACK_DEBUG) + for( i = 0 ; i < param[0] ; i ++ ) + { + //ff_status = *(volatile unsigned long*)(RALINK_I2S_BASE+0x0C); + ff_status = *(volatile unsigned long*)(I2S_FF_STATUS); + #if defined(CONFIG_RALINK_MT7628)|| defined(CONFIG_ARCH_MT7623) + if((ff_status&0xFF) > 0) + #else + if((ff_status&0x0F) > 0) + #endif + { + //*(volatile unsigned long*)(RALINK_I2S_BASE+0x10) = txbuffer[i]; + *(volatile unsigned long*)(I2S_TX_FIFO_WREG) = txbuffer[i]; + mdelay(1); + } + else + { + mdelay(1); + printk("[%d]NO TX FREE FIFO ST=[0x%08X]\n", i, (u32)ff_status); + continue; + } + + //if(i >= 16) + { + + //ff_status = *(volatile unsigned long*)(RALINK_I2S_BASE+0x0C); + ff_status = *(volatile unsigned long*)(I2S_FF_STATUS); + #if defined(CONFIG_RALINK_MT7628)|| defined(CONFIG_ARCH_MT7623) + if(((ff_status>>8)&0xFF) > 0) + #else + if(((ff_status>>4)&0x0F) > 0) + #endif + { + //data = *(volatile unsigned long*)(RALINK_I2S_BASE+0x14); + data = *(volatile unsigned long*)(I2S_RX_FIFO_RREG); + } + else + { + printk("*[%d]NO RX FREE FIFO ST=[0x%08X]\n", i, (u32)ff_status); + continue; + } + + { + if(data!= txbuffer[i]) + { + MSG("[%d][0x%08X] vs [0x%08X]\n", (i), (u32)data, (u32)txbuffer[i]); + } + else + { + MSG("**[%d][0x%08X] vs [0x%08X]\n" ,(i), (u32)data , (u32)txbuffer[i]); + count2++; + data=0; + } + } + + } + } + printk("Pattern match done count2=%d.\n", count2); +#endif + printk("Pattern match done count=%d.\n", count); + + } +#if defined(CONFIG_ARCH_MT7623) + *(volatile unsigned long*)(0xFB000034) |= 0x00020000; + *(volatile unsigned long*)(0xFB000034) &= 0xFFFDFFFF; + *(volatile unsigned long*)(ETHDMASYS_I2S_BASE+0x0) &= 0x7FFFFFFF; //Rest I2S to default vaule +#endif + +#if !defined(CONFIG_RALINK_RT3052) + break; +#endif + case I2S_DEBUG_EXLBK: + MSG("I2S_DEBUG_EXLBK\n"); +#if !defined(CONFIG_ARCH_MT7623) + switch(arg) + { + case 8000: + index = 0; + break; + case 11025: + index = 1; + break; + case 12000: + index = 2; + break; + case 16000: + index = 3; + break; + case 22050: + index = 4; + break; + case 24000: + index = 5; + break; + case 32000: + index = 6; + break; + case 44100: + index = 7; + break; + case 48000: + index = 8; + break; + case 88200: + index = 9; + break; + case 96000: + index = 10; + break; + default: + index = 7; + } +#if defined(CONFIG_RALINK_RT3052) + break; +#endif +#if defined(CONFIG_RALINK_RT6855A) + *(volatile unsigned long*)(RALINK_SYSCTL_BASE+0x860) = 0x00008080; + //*(volatile unsigned long*)(RALINK_SYSCTL_BASE+0x82C) = 0x00000300; +#else + *(volatile unsigned long*)(RALINK_SYSCTL_BASE+0x60) = 0x00000018; +#if defined(CONFIG_RALINK_RT3883) + *(volatile unsigned long*)(RALINK_SYSCTL_BASE+0x2C) = 0x00003000; +#else + *(volatile unsigned long*)(RALINK_SYSCTL_BASE+0x2C) = 0x00000300; +#endif +#endif + + *(volatile unsigned long*)(RALINK_I2S_BASE+0x18) = 0x40000000; + *(volatile unsigned long*)(RALINK_I2S_BASE+0x00) = 0x81104040; +#if defined(CONFIG_RALINK_MT7628) + pTable = i2s_inclk_int_16bit; +#else + pTable = i2s_inclk_int; +#endif + data = (volatile unsigned long)(pTable[index]); + i2s_outw(I2S_DIVINT_CFG, data); +#if defined(CONFIG_RALINK_MT7628) + pTable = i2s_inclk_comp_16bit; +#else + pTable = i2s_inclk_comp; +#endif + data = (volatile unsigned long)(pTable[index]); + data |= REGBIT(1, I2S_CLKDIV_EN); + i2s_outw(I2S_DIVCOMP_CFG, data); + + #if defined(CONFIG_I2S_MCLK_12MHZ) + pTable = i2s_codec_12Mhz; + #if defined(CONFIG_I2S_WM8960) + data = pTable[index]; + #else + data = pTable[index]|0x01; + #endif + #else + pTable = i2s_codec_12p288Mhz; + data = pTable[index]; + #endif + + #if defined(CONFIG_I2S_WM8960) || defined(CONFIG_I2S_WM8750) || defined(CONFIG_I2S_WM8751) + audiohw_preinit(); + #endif + + + #if defined (CONFIG_I2S_WM8960) + audiohw_postinit(1, 1, 1, 1, 0); // for codec apll enable, 16 bit word length + #elif defined(CONFIG_I2S_WM8750) || defined(CONFIG_I2S_WM8751) + audiohw_postinit(1, 1, 1, 0); // for 16 bit word length + #endif + + + #if defined (CONFIG_I2S_WM8960) + audiohw_set_frequency(data, 1); // for codec apll enable + #elif defined(CONFIG_I2S_WM8750) || defined(CONFIG_I2S_WM8751) + audiohw_set_frequency(data|0x1); + #endif + + + #if defined(CONFIG_I2S_WM8960) || defined(CONFIG_I2S_WM8750) || defined(CONFIG_I2S_WM8751) + audiohw_set_lineout_vol(1, 100, 100); + audiohw_set_linein_vol(100, 100); + #endif + + + #if defined(CONFIG_I2S_TXRX) + //audiohw_loopback(data); + #endif + #if !defined(CONFIG_RALINK_RT3052) + break; + #endif +#endif + case I2S_DEBUG_CODECBYPASS: + #if defined(CONFIG_I2S_TXRX) + #if defined(CONFIG_RALINK_MT7628) + data = i2s_inw(RALINK_SYSCTL_BASE+0x60); + //data &= ~(0x3<<4); + data &= ~(0x3<<6); + data &= ~(0x3<<16); + data &= ~(0x1<<14); + i2s_outw(RALINK_SYSCTL_BASE+0x60, data); + + data = i2s_inw(RALINK_SYSCTL_BASE+0x2c); + data &= ~(0x07<<9); + i2s_outw(RALINK_SYSCTL_BASE+0x2c, data); + #endif + + #if defined(CONFIG_I2S_WM8960) || defined(CONFIG_I2S_WM8750) || defined(CONFIG_I2S_WM8751) + audiohw_bypass(); /* did not work */ + #endif + #endif + break; + case I2S_DEBUG_FMT: + break; + case I2S_DEBUG_RESET: + break; +#if defined(CONFIG_I2S_WM8960) + case I2S_DEBUG_CODEC_EXLBK: + audiohw_codec_exlbk(); + break; +#endif + default: + MSG("Not support this debug cmd [%d]\n", cmd); + break; + } + + return 0; +} diff --git a/sound/soc/mtk/mt76xx_i2s.c b/sound/soc/mtk/mt76xx_i2s.c new file mode 100644 index 0000000..7615b51 --- /dev/null +++ b/sound/soc/mtk/mt76xx_i2s.c @@ -0,0 +1,304 @@ +/* + * mtk_audio_drv.c + * + * Created on: 2013/8/20 + * Author: MTK04880 + */ +#include +#include +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,35) +#include +#endif +#include +#include /* printk() */ +#include /* kmalloc() */ +#include /* everything... */ +#include /* error codes */ +#include /* size_t */ +#include +#include /* O_ACCMODE */ +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,36) +#include /* cli(), *_flags */ +#endif +#include /* copy_from/to_user */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "ralink_gdma.h" +#include "mt76xx_i2s.h" + +/****************************/ +/*GLOBAL VARIABLE DEFINITION*/ +/****************************/ +extern i2s_config_type* pi2s_config; + +/****************************/ +/*FUNCTION DECLRATION */ +/****************************/ +static int mt76xx_i2s_set_fmt(struct snd_soc_dai *cpu_dai,\ + unsigned int fmt); + +//static int mt76xx_i2s_shutdown(struct snd_pcm_substream *substream, +// struct snd_soc_dai *dai); +static int mt76xx_i2s_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai); +static int mt76xx_i2s_hw_params(struct snd_pcm_substream *substream,\ + struct snd_pcm_hw_params *params,\ + struct snd_soc_dai *dai); +static int mt76xx_i2s_play_prepare(struct snd_pcm_substream *substream,struct snd_soc_dai *dai); +static int mt76xx_i2s_rec_prepare(struct snd_pcm_substream *substream,struct snd_soc_dai *dai); +static int mt76xx_i2s_hw_free(struct snd_pcm_substream *substream,struct snd_soc_dai *dai); +static int mt76xx_i2s_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai); + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,20) +static int mt76xx_i2s_drv_probe(struct platform_device *pdev); +static int mt76xx_i2s_drv_remove(struct platform_device *pdev); +#endif +/****************************/ +/*STRUCTURE DEFINITION */ +/****************************/ + + +static struct snd_soc_dai_ops mt76xx_i2s_dai_ops = { + .startup = mt76xx_i2s_startup, + .hw_params = mt76xx_i2s_hw_params, + .hw_free = mt76xx_i2s_hw_free, + //.shutdown = mt76xx_i2s_shutdown, + .prepare = mt76xx_i2s_prepare, + .set_fmt = mt76xx_i2s_set_fmt, + //.set_sysclk = mt76xx_i2s_set_sysclk, +}; + +const struct snd_soc_component_driver mt76xx_i2s_component = { + .name = "mt76xx-i2s", +}; + +struct snd_soc_dai_driver mt76xx_i2s_dai = { + .playback = { + .channels_min = 1, + .channels_max = 2, + .rates = (SNDRV_PCM_RATE_8000|SNDRV_PCM_RATE_11025|\ + SNDRV_PCM_RATE_16000|SNDRV_PCM_RATE_22050|SNDRV_PCM_RATE_32000|\ + SNDRV_PCM_RATE_44100|SNDRV_PCM_RATE_48000), + + .formats = (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ + SNDRV_PCM_FMTBIT_S24_LE), + }, + .capture = { + .channels_min = 1, + .channels_max = 2, + .rates = (SNDRV_PCM_RATE_8000|SNDRV_PCM_RATE_11025|\ + SNDRV_PCM_RATE_16000|SNDRV_PCM_RATE_22050|SNDRV_PCM_RATE_32000|\ + SNDRV_PCM_RATE_44100|SNDRV_PCM_RATE_48000), + .formats = (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ + SNDRV_PCM_FMTBIT_S24_LE), + }, + .ops = &mt76xx_i2s_dai_ops, + .symmetric_rates = 1, +}; + +/****************************/ +/*FUNCTION BODY */ +/****************************/ + +static int mt76xx_i2s_set_fmt(struct snd_soc_dai *cpu_dai, + unsigned int fmt) +{//TODO + + //printk("******* %s *******\n", __func__); + return 0; +} + +static int mt76xx_i2s_play_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) +{ + //printk("******* %s *******\n", __func__); + i2s_config_type* rtd = (i2s_config_type*)substream->runtime->private_data; + rtd->pss[SNDRV_PCM_STREAM_PLAYBACK] = substream; + if(! rtd->i2sStat[SNDRV_PCM_STREAM_PLAYBACK]){ + i2s_reset_tx_param( rtd); + i2s_tx_config( rtd); + gdma_En_Switch(rtd, STREAM_PLAYBACK, GDMA_I2S_EN); + + if( rtd->bRxDMAEnable==0) + i2s_clock_enable( rtd); + + i2s_tx_enable( rtd); + rtd->i2sStat[SNDRV_PCM_STREAM_PLAYBACK] = 1; + MSG("I2S_TXENABLE done\n"); + } + + return 0; +} + +static int mt76xx_i2s_rec_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) +{ + + //printk("******* %s *******\n", __func__); + i2s_config_type* rtd = (i2s_config_type*)substream->runtime->private_data; + rtd->pss[SNDRV_PCM_STREAM_CAPTURE] = substream; + if(! rtd->i2sStat[SNDRV_PCM_STREAM_CAPTURE]) { + i2s_reset_rx_param(rtd); + i2s_rx_config(rtd); + gdma_En_Switch(rtd, STREAM_CAPTURE, GDMA_I2S_EN); + + if(rtd->bTxDMAEnable==0) + i2s_clock_enable(rtd); + + i2s_rx_enable(rtd); + rtd->i2sStat[SNDRV_PCM_STREAM_CAPTURE] = 1; + } + return 0; +} + +/*static int mt76xx_i2s_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + //i2s_config_type* rtd = (i2s_config_type*)substream->runtime->private_data; + //printk("******* %s *******\n", __func__); + return 0; +} +*/ +static int mt76xx_i2s_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + + //printk("******* %s *******\n", __func__); + if((!pi2s_config->i2sStat[SNDRV_PCM_STREAM_PLAYBACK]) && (!pi2s_config->i2sStat[SNDRV_PCM_STREAM_CAPTURE])){ + i2s_startup(); + if(!pi2s_config) + return -1; + i2s_reset_config(pi2s_config); + } + substream->runtime->private_data = pi2s_config; + return 0; +} + +static int mt76xx_i2s_hw_params(struct snd_pcm_substream *substream,\ + struct snd_pcm_hw_params *params,\ + struct snd_soc_dai *dai){ + unsigned int srate = 0; + //unsigned long data; + struct snd_pcm_runtime *runtime = substream->runtime; + i2s_config_type* rtd = runtime->private_data; + + //printk("******* %s *******\n", __func__); + switch(params_rate(params)){ + case 8000: + srate = 8000; + break; + case 16000: + srate = 16000; + break; + case 32000: + srate = 32000; + break; + case 44100: + srate = 44100; + break; + case 48000: + srate = 48000; + break; + default: + srate = 44100; + //MSG("audio sampling rate %u should be %d ~ %d Hz\n", (u32)params_rate(params), MIN_SRATE_HZ, MAX_SRATE_HZ); + break; + } + if(srate){ + if((rtd->bRxDMAEnable != GDMA_I2S_EN) && (rtd->bTxDMAEnable != GDMA_I2S_EN)){ + rtd->srate = srate; + MSG("set audio sampling rate to %d Hz\n", rtd->srate); + } + } + + return 0; +} +static int mt76xx_i2s_hw_free(struct snd_pcm_substream *substream,struct snd_soc_dai *dai){ + + //printk("******* %s *******\n", __func__); + i2s_config_type* rtd = (i2s_config_type*)substream->runtime->private_data; + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK){ + if(rtd->i2sStat[SNDRV_PCM_STREAM_PLAYBACK]){ + MSG("I2S_TXDISABLE\n"); + i2s_reset_tx_param(rtd); + + if((rtd->bRxDMAEnable==0)&&(rtd->bTxDMAEnable==0)){ + i2s_clock_disable(rtd); + } + rtd->i2sStat[SNDRV_PCM_STREAM_PLAYBACK] = 0; + } + } + else{ + if(rtd->i2sStat[SNDRV_PCM_STREAM_CAPTURE]){ + MSG("I2S_RXDISABLE\n"); + i2s_reset_rx_param(rtd); + + if((rtd->bRxDMAEnable==0)&&(rtd->bTxDMAEnable==0)){ + i2s_clock_disable(rtd); + } + rtd->i2sStat[SNDRV_PCM_STREAM_CAPTURE] = 0; + } + } + return 0; +} +static int mt76xx_i2s_prepare(struct snd_pcm_substream *substream,struct snd_soc_dai *dai) +{ + + //printk("******* %s *******\n", __func__); + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + return mt76xx_i2s_play_prepare(substream, dai); + else + return mt76xx_i2s_rec_prepare(substream, dai); + + return 0; +} + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,20) +static int mt76xx_i2s_drv_probe(struct platform_device *pdev) +{ + //printk("****** %s ******\n", __func__); + return snd_soc_register_component(&pdev->dev, &mt76xx_i2s_component, + &mt76xx_i2s_dai, 1); +} + +static int mt76xx_i2s_drv_remove(struct platform_device *pdev) +{ + snd_soc_unregister_component(&pdev->dev); + return 0; +} + +static struct platform_driver mt76xx_i2s_driver = { + .probe = mt76xx_i2s_drv_probe, + .remove = mt76xx_i2s_drv_remove, + .driver = { + .name = "mt76xx-i2s", + .owner = THIS_MODULE, + }, +}; + +static int __init mt76xx_i2s_init(void) +{ + + //printk("****** %s ******\n", __func__); + return platform_driver_register(&mt76xx_i2s_driver); +} + +static void __exit mt76xx_i2s_exit(void) +{ + //printk("****** %s ******\n", __func__); + platform_driver_unregister(&mt76xx_i2s_driver); +} + +module_init(mt76xx_i2s_init); +module_exit(mt76xx_i2s_exit); + +MODULE_AUTHOR("Dora Chen"); +MODULE_DESCRIPTION("Stretch MT76xx I2S Interface"); +MODULE_LICENSE("GPL"); +#endif diff --git a/sound/soc/mtk/mt76xx_i2s.h b/sound/soc/mtk/mt76xx_i2s.h new file mode 100644 index 0000000..9ae0e50 --- /dev/null +++ b/sound/soc/mtk/mt76xx_i2s.h @@ -0,0 +1,18 @@ +/* + * mtk_i2s.h + * + * Created on: 2013/8/20 + * Author: MTK04880 + */ + +#ifndef MTK_I2S_H_ +#define MTK_I2S_H_ + + +#ifdef __KERNEL__ +//#include +#include +#endif + +#include "i2s_ctrl.h" +#endif /* MTK_I2S_H_ */ diff --git a/sound/soc/mtk/mt76xx_machine.c b/sound/soc/mtk/mt76xx_machine.c new file mode 100644 index 0000000..00d2145 --- /dev/null +++ b/sound/soc/mtk/mt76xx_machine.c @@ -0,0 +1,317 @@ +/* + * mt76xx_machine.c + * + */ +#include +#include +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,35) +#include +#endif +#include +#include /* printk() */ +#include /* kmalloc() */ +#include /* everything... */ +#include /* error codes */ +#include /* size_t */ +#include +#include /* O_ACCMODE */ +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,36) +#include /* cli(), *_flags */ +#endif +#include /* copy_from/to_user */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "ralink_gdma.h" +#include "mt76xx_i2s.h" +#include "mt76xx_machine.h" +#if defined(CONFIG_SND_SOC_WM8960) +#include "../codecs/wm8960.h" +#endif + +#define I2C_AUDIO_DEV_ID (0) +/****************************/ +/*FUNCTION DECLRATION */ +/****************************/ +extern unsigned long i2s_codec_12p288Mhz[11]; +extern unsigned long i2s_codec_12Mhz[11]; + + +static int mt76xx_codec_clock_hwparams(struct snd_pcm_substream *substream,\ + struct snd_pcm_hw_params *params); +static int mt76xx_codec_startup(struct snd_pcm_substream *substream); +static int mt76xx_codec_init(struct snd_soc_pcm_runtime *rtd); +extern struct snd_soc_dai_driver mt76xx_i2s_dai; +extern struct snd_soc_platform_driver mt76xx_soc_platform; +struct platform_device *mt76xx_audio_device; + +#if defined(CONFIG_SND_SOC_WM8960) +extern struct snd_soc_dai wm8960_dai; +extern struct snd_soc_codec_device soc_codec_dev_wm8960; +#endif + +static struct snd_soc_ops mtk_audio_ops = { + .hw_params = mt76xx_codec_clock_hwparams, + .startup = mt76xx_codec_startup, +}; + +static struct snd_soc_dai_link mtk_audio_dai = { + .name = "mtk_dai", + .stream_name = "WMserious PCM", + .cpu_dai_name = "mt76xx-i2s", + .codec_dai_name = "wm8960-hifi", + .codec_name = "wm8960.0-001a", + .platform_name = "mt76xx-pcm", + .ignore_pmdown_time = true, + .init = mt76xx_codec_init, + .ops = &mtk_audio_ops, +}; + +static struct snd_soc_card mtk_audio_card = { + .name = "MTK APSoC I2S", + .owner = THIS_MODULE, + .dai_link = &mtk_audio_dai,//I2S/Codec + .num_links = 1, +}; + +static int mt76xx_codec_clock_hwparams(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *p = substream->private_data; + struct snd_soc_dai *codec_dai = p->codec_dai; + struct snd_pcm_runtime *runtime = substream->runtime; + i2s_config_type* rtd = runtime->private_data; + unsigned long data,index = 0; + unsigned long* pTable; + int mclk,ret,targetClk = 0; + + /*For duplex mode, avoid setting twice.*/ + if((rtd->bRxDMAEnable == GDMA_I2S_EN) || (rtd->bTxDMAEnable == GDMA_I2S_EN)) + return 0; +#if defined(CONFIG_I2S_MCLK_12MHZ) + mclk = 12000000; +#elif defined(CONFIG_I2S_MCLK_12P288MHZ) + mclk = 12288000; +#else + mclk = 12000000; +#endif + //snd_soc_dai_set_sysclk(codec_dai,0,mclk, SND_SOC_CLOCK_IN); + + switch(params_rate(params)){ + case 8000: + index = 0; + targetClk = 12288000; + break; + case 12000: + index = 2; + targetClk = 12288000; + break; + case 16000: + index = 3; + targetClk = 12288000; + break; + case 24000: + index = 5; + targetClk = 12288000; + break; + case 32000: + index = 6; + targetClk = 12288000; + break; + case 48000: + index = 8; + targetClk = 12288000; + break; + case 11025: + index = 1; + targetClk = 11289600; + break; + case 22050: + index = 4; + targetClk = 11289600; + break; + case 44100: + index = 7; + targetClk = 11289600; + break; + case 88200: + index = 9; + targetClk = 11289600; + break; + case 96000: + index = 10; + targetClk = 11289600; + break; + default: + index = 7; + targetClk = 12288000; + //MSG("audio sampling rate %u should be %d ~ %d Hz\n", (u32)params_rate(params), MIN_SRATE_HZ, MAX_SRATE_HZ); + break; + } +#if defined(CONFIG_SND_SOC_WM8960) + /* + * There is a fixed divide by 4 in the PLL and a selectable + * divide by N after the PLL which should be set to divide by 2 to meet this requirement. + * */ + ret = snd_soc_dai_set_pll(codec_dai, 0, 0,mclk, targetClk*2); + /* From app notes: allow Vref to stabilize to reduce clicks */ + if(rtd->slave_en){ + //printk("WM8960 is in master mode\n"); + ret = snd_soc_dai_set_clkdiv(codec_dai, WM8960_DCLKDIV, 0x1c4); + ret = snd_soc_dai_set_clkdiv(codec_dai, WM8960_SYSCLKDIV, 0x5); + } + +#endif + if(!rtd->slave_en) + snd_soc_dai_set_fmt(codec_dai,SND_SOC_DAIFMT_CBS_CFS|SND_SOC_DAIFMT_I2S|SND_SOC_DAIFMT_NB_NF); + else{ + snd_soc_dai_set_fmt(codec_dai,SND_SOC_DAIFMT_CBM_CFM|SND_SOC_DAIFMT_I2S|SND_SOC_DAIFMT_NB_NF); + } + mdelay(5); + +#if defined(CONFIG_SND_SOC_WM8960) +#if defined(CONFIG_I2S_MCLK_12MHZ) + pTable = i2s_codec_12Mhz; + data = pTable[index]; +#else + pTable = i2s_codec_12p288Mhz; + data = pTable[index]; +#endif + if(rtd->codec_pll_en) + ret = snd_soc_dai_set_clkdiv(codec_dai, WM8960_DACDIV, (data<<3)|0x5); + else + ret = snd_soc_dai_set_clkdiv(codec_dai, WM8960_DACDIV, (data<<3|0x4)); +#endif + + return 0; +} + +static int mt76xx_codec_startup(struct snd_pcm_substream *substream) +{ + //printk("******* %s *******\n", __func__); + return 0; +} +static int mt76xx_codec_init(struct snd_soc_pcm_runtime *rtd) +{ + + //printk("******* %s *******\n", __func__); + return 0; +} + +static struct i2c_board_info i2c_board_info[] = { + { +#if defined(CONFIG_SND_SOC_WM8750) + I2C_BOARD_INFO("wm8750", (0x36 >> 1)), +#elif defined(CONFIG_SND_SOC_WM8960) + I2C_BOARD_INFO("codec_wm8960", (0x34)), + }, { + I2C_BOARD_INFO("wm8960", (0x34 >> 1)), +#endif + } +}; + +static struct platform_device *soc_mtk_i2s_dev; +static struct platform_device *soc_mtk_pcm_dev; + +static int __init mt76xx_machine_init(void) +{ + //struct snd_soc_device *socdev = &mtk_audio_devdata; + //struct i2c_adapter *adapter = NULL; + //struct i2c_client *client = NULL; + int ret = 0; + struct i2c_adapter *adapter = NULL; + struct i2c_client *client = NULL; + + adapter = i2c_get_adapter(I2C_AUDIO_DEV_ID); + if (!adapter) + return -ENODEV; + client = i2c_new_device(adapter, &i2c_board_info[0]); + if (!client) + return -ENODEV; + i2c_get_clientdata(client); + + client = i2c_new_device(adapter, &i2c_board_info[1]); + if (!client) + return -ENODEV; + i2c_get_clientdata(client); + + i2c_put_adapter(adapter); + + soc_mtk_i2s_dev = + platform_device_register_simple("mt76xx-i2s", -1, NULL, 0); + if (IS_ERR(soc_mtk_i2s_dev)) + return PTR_ERR(soc_mtk_i2s_dev); + + soc_mtk_pcm_dev = + platform_device_register_simple("mt76xx-pcm", -1, NULL, 0); + if (IS_ERR(soc_mtk_pcm_dev)) + return PTR_ERR(soc_mtk_pcm_dev); + + mt76xx_audio_device = platform_device_alloc("soc-audio",-1); + if (mt76xx_audio_device == NULL) { + ret = -ENOMEM; + goto err_device_alloc; + } +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38) + platform_set_drvdata(mt76xx_audio_device, &mtk_audio_card); +#else + platform_set_drvdata(mt76xx_audio_device, &mtk_audio_devdata); + mtk_audio_devdata.dev = &mt76xx_audio_device->dev; +#endif + + /*Ralink I2S register process end*/ + ret = platform_device_add(mt76xx_audio_device); + if (ret) { + printk("mtk audio device : platform_device_add failed (%d)\n",ret); + goto err_device_add; + } + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38) +#else + snd_soc_register_dai(&mt76xx_i2s_dai); +#endif + + return 0; + +err_device_add: + if (mt76xx_audio_device!= NULL) { + platform_device_put(mt76xx_audio_device); + mt76xx_audio_device = NULL; + } +err_device_alloc: + return ret; +} + + +static void __exit mt76xx_machine_exit(void) +{ + + platform_device_unregister(mt76xx_audio_device); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,20) + /* Do nothing */ +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38) + snd_soc_unregister_platform(&mt76xx_audio_device->dev); +#else + snd_soc_unregister_platform(&mt76xx_soc_platform); +#endif + platform_device_unregister(soc_mtk_i2s_dev); + platform_device_unregister(soc_mtk_pcm_dev); + + mt76xx_audio_device = NULL; +} + +//module_init(mt76xx_machine_init); +late_initcall(mt76xx_machine_init); +module_exit(mt76xx_machine_exit); +//EXPORT_SYMBOL_GPL(mt76xx_soc_platform); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/mtk/mt76xx_machine.h b/sound/soc/mtk/mt76xx_machine.h new file mode 100644 index 0000000..79532b5 --- /dev/null +++ b/sound/soc/mtk/mt76xx_machine.h @@ -0,0 +1,21 @@ +/* + * mtk_audio_device.h + * + * Created on: 2013/10/23 + * Author: MTK04880 + */ + +#ifndef MT76XX_MACHINE_H_ +#define MT76XX_MACHINE_H_ +#include +#include +#include +#include + +#if 0 +#ifdef CONFIG_I2S_MMAP +#undef CONFIG_I2S_MMAP +#endif +#endif + +#endif /* MT76XX_MACHINE_H_ */ diff --git a/sound/soc/mtk/mt76xx_pcm.c b/sound/soc/mtk/mt76xx_pcm.c new file mode 100644 index 0000000..1100ee0 --- /dev/null +++ b/sound/soc/mtk/mt76xx_pcm.c @@ -0,0 +1,499 @@ +/* + * mt76xx_pcm.c + * + * Created on: 2013/9/6 + * Author: MTK04880 + */ + +#include +#include +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,35) +#include +#endif +#include +#include /* printk() */ +#include /* kmalloc() */ +#include /* everything... */ +#include /* error codes */ +#include /* size_t */ +#include +#include /* O_ACCMODE */ +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,36) +#include /* cli(), *_flags */ +#endif +#include /* copy_from/to_user */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "ralink_gdma.h" +#include "mt76xx_i2s.h" + +#define GDMA_PAGE_SIZE I2S_PAGE_SIZE +#define GDMA_PAGE_NUM MAX_I2S_PAGE +#define GDMA_TOTAL_PAGE_SIZE I2S_TOTAL_PAGE_SIZE + +dma_addr_t i2s_txdma_addr, i2s_rxdma_addr; +dma_addr_t i2s_mmap_addr[GDMA_PAGE_NUM*2]; + +extern struct tasklet_struct i2s_tx_tasklet; +extern struct tasklet_struct i2s_rx_tasklet; +extern int i2s_mmap_remap(struct vm_area_struct *vma, unsigned long size); +extern void i2s_tx_end_sleep_on(i2s_config_type* ptri2s_config); +extern void i2s_rx_end_sleep_on(i2s_config_type* ptri2s_config); + +static int mt76xx_pcm_open(struct snd_pcm_substream *substream); +static int mt76xx_pcm_new(struct snd_soc_pcm_runtime *rtd); +static void mt76xx_pcm_free(struct snd_pcm *pcm); +static int mt76xx_pcm_close(struct snd_pcm_substream *substream); +static snd_pcm_uframes_t mt76xx_pcm_pointer(struct snd_pcm_substream *substream); +static int mt76xx_pcm_trigger(struct snd_pcm_substream *substream, int cmd); +static int mt76xx_pcm_prepare(struct snd_pcm_substream *substream); +static int mt76xx_pcm_hw_params(struct snd_pcm_substream *substream,\ + struct snd_pcm_hw_params *hw_params); +static int mt76xx_pcm_copy(struct snd_pcm_substream *substream, int channel,\ + snd_pcm_uframes_t pos,void __user *buf, snd_pcm_uframes_t count); +static int mt76xx_pcm_mmap(struct snd_pcm_substream *substream, struct vm_area_struct *vma); +static int mt76xx_pcm_hw_free(struct snd_pcm_substream *substream); + +static int mt76xx_pcm_free_dma_buffer(struct snd_pcm_substream *substream,int stream); +static int mt76xx_pcm_allocate_dma_buffer(struct snd_pcm_substream *substream,int stream); + +#if LINUX_VERSION_CODE > KERNEL_VERSION(3,10,20) +static int mt76xx_platform_drv_probe(struct platform_device *pdev); +static int mt76xx_platform_drv_remove(struct platform_device *pdev); +#endif + +static const struct snd_pcm_hardware mt76xx_pcm_hwparam = { +#if defined(CONFIG_I2S_MMAP) + .info = (SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_PAUSE | + SNDRV_PCM_INFO_RESUME | + SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_MMAP_VALID), +#else + .info = (SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_PAUSE | + SNDRV_PCM_INFO_RESUME), +#endif + .formats = SNDRV_PCM_FMTBIT_S16_LE, + .period_bytes_min = GDMA_PAGE_SIZE, + .period_bytes_max = GDMA_PAGE_SIZE, + .periods_min = 1, + .periods_max = GDMA_PAGE_NUM, + .buffer_bytes_max = GDMA_TOTAL_PAGE_SIZE, +}; + +static struct snd_pcm_ops mt76xx_pcm_ops = { + + .open = mt76xx_pcm_open, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = mt76xx_pcm_hw_params, + .hw_free = mt76xx_pcm_hw_free, + .trigger = mt76xx_pcm_trigger, + .prepare = mt76xx_pcm_prepare, + .pointer = mt76xx_pcm_pointer, + .close = mt76xx_pcm_close, +#if defined(CONFIG_I2S_MMAP) + .mmap = mt76xx_pcm_mmap, +#endif + .copy = mt76xx_pcm_copy, +}; +#if LINUX_VERSION_CODE > KERNEL_VERSION(3,10,0) +struct snd_soc_platform_driver mt76xx_soc_platform = { + .ops = &mt76xx_pcm_ops, + .pcm_new = mt76xx_pcm_new, + .pcm_free = mt76xx_pcm_free, +}; +#else +struct snd_soc_platform mt76xx_soc_platform = { + .name = "mtk-dma", + .pcm_ops = &mt76xx_pcm_ops, + .pcm_new = mt76xx_pcm_new, + .pcm_free = mt76xx_pcm_free, +}; +#endif + +static int mt76xx_pcm_close(struct snd_pcm_substream *substream){ + + //printk("******* %s *********\n", __func__); + return 0; +} + +static snd_pcm_uframes_t mt76xx_pcm_pointer(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + i2s_config_type* rtd = runtime->private_data; + unsigned int offset = 0; + //int buff_frame_bond = bytes_to_frames(runtime, GDMA_PAGE_SIZE); + //printk("\n******* %s *********\n", __func__); + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK){ + offset = bytes_to_frames(runtime, GDMA_PAGE_SIZE*rtd->tx_r_idx); + //printk("r:%d w:%d (%d) \n",rtd->tx_r_idx,rtd->tx_w_idx,(runtime->control->appl_ptr/buff_frame_bond)%GDMA_PAGE_NUM); + } + else{ + offset = bytes_to_frames(runtime, GDMA_PAGE_SIZE*rtd->rx_w_idx); + //printk("w:%d r:%d appl_ptr:%x\n",rtd->rx_w_idx,rtd->rx_r_idx,(runtime->control->appl_ptr/buff_frame_bond)%GDMA_PAGE_NUM); + } + return offset; +} + + +static int mt76xx_pcm_trigger(struct snd_pcm_substream *substream, int cmd) +{ + int ret = 0; + i2s_config_type* rtd = (i2s_config_type*)substream->runtime->private_data; + //struct snd_pcm_runtime *runtime= substream->runtime; + + //printk("******* %s *********\n", __func__); +/* printk("trigger cmd:%s\n",(cmd==SNDRV_PCM_TRIGGER_START)?"START":\ + (cmd==SNDRV_PCM_TRIGGER_RESUME)?"RESUME":\ + (cmd==SNDRV_PCM_TRIGGER_PAUSE_RELEASE)?"PAUSE_RELEASE":\ + (cmd==SNDRV_PCM_TRIGGER_STOP)?"STOP":\ + (cmd==SNDRV_PCM_TRIGGER_SUSPEND)?"SUSPEND":\ + (cmd==SNDRV_PCM_TRIGGER_PAUSE_PUSH)?"PAUSE_PUSH":"default"); +*/ + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + rtd->bTrigger[SNDRV_PCM_STREAM_PLAYBACK] = 1; + } else { + rtd->bTrigger[SNDRV_PCM_STREAM_CAPTURE] = 1; + } + break; + case SNDRV_PCM_TRIGGER_STOP: + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + rtd->bTrigger[SNDRV_PCM_STREAM_PLAYBACK] = 0; + } else { + rtd->bTrigger[SNDRV_PCM_STREAM_CAPTURE] = 0; + } + break; + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK){ + rtd->tx_pause_en = 0; + } else { + rtd->rx_pause_en = 0; + } + break; + + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK){ + rtd->tx_pause_en = 1; + } else { + rtd->rx_pause_en = 1; + } + break; + default: + ret = -EINVAL; + break; + } + return ret; +} + +static int mt76xx_pcm_copy(struct snd_pcm_substream *substream, int channel,\ + snd_pcm_uframes_t pos,void __user *buf, snd_pcm_uframes_t count) +{ + struct snd_pcm_runtime *runtime= substream->runtime; + i2s_config_type* rtd = runtime->private_data; + int tx_w_idx = 0; + int rx_r_idx = 0; + char *hwbuf = NULL; + + //printk("******* %s *********\n", __func__); + hwbuf = runtime->dma_area + frames_to_bytes(runtime, pos); + //MSG("%s bur:%x\n",__func__,hwbuf); + //printk("hw_ptr:%d, buffer_size:%d, appl_prt:%d, boundary:%d\n", + // runtime->status->hw_ptr, runtime->buffer_size, runtime->control->appl_ptr, runtime->boundary); + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK){ + rtd->tx_w_idx = (rtd->tx_w_idx+1)%MAX_I2S_PAGE; + tx_w_idx = rtd->tx_w_idx; + //printk("put TB[%d - %x] for user write\n",rtd->tx_w_idx,pos); + copy_from_user(rtd->pMMAPTxBufPtr[tx_w_idx], (char*)buf, I2S_PAGE_SIZE); + } + else{ + rx_r_idx = rtd->rx_r_idx; + rtd->rx_r_idx = (rtd->rx_r_idx+1)%MAX_I2S_PAGE; + copy_to_user((char*)buf, rtd->pMMAPRxBufPtr[rx_r_idx], I2S_PAGE_SIZE); + } + return 0; +} + +static int mt76xx_pcm_mmap(struct snd_pcm_substream *substream, struct vm_area_struct *vma) +{ + int ret; + unsigned long size; + + size = vma->vm_end-vma->vm_start; + printk("******* %s: size :%lx end:%lx start:%lx *******\n", __func__,size,vma->vm_end,vma->vm_start); + ret = i2s_mmap_remap(vma, size); + + return ret; +} + + +static int mt76xx_pcm_prepare(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime= substream->runtime; + i2s_config_type *rtd = (i2s_config_type*)runtime->private_data; + //runtime->buffer_size = GDMA_PAGE_NUM*GDMA_PAGE_SIZE; + //runtime->boundary = (GDMA_PAGE_NUM*GDMA_PAGE_SIZE)/4; + + //printk("******* %s *******\n", __func__); + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK){ + //printk("===== %s:%s:%d =====\n", __FILE__, __func__, __LINE__); + mt76xx_pcm_allocate_dma_buffer(substream,SNDRV_PCM_STREAM_PLAYBACK); + + if(! rtd->dmaStat[SNDRV_PCM_STREAM_PLAYBACK]){ + i2s_page_prepare(rtd,STREAM_PLAYBACK); + tasklet_init(&i2s_tx_tasklet, i2s_tx_task, (u32)rtd); + rtd->dmaStat[SNDRV_PCM_STREAM_PLAYBACK] = 1; + gdma_unmask_handler(GDMA_I2S_TX0); + } + } else { + mt76xx_pcm_allocate_dma_buffer(substream,SNDRV_PCM_STREAM_CAPTURE); + + if(! rtd->dmaStat[SNDRV_PCM_STREAM_CAPTURE]){ + i2s_page_prepare(rtd,STREAM_CAPTURE); /* TX:enLabel=1; RX:enLabel=2 */ + tasklet_init(&i2s_rx_tasklet, i2s_rx_task, (u32)rtd); + rtd->dmaStat[SNDRV_PCM_STREAM_CAPTURE] = 1; + gdma_unmask_handler(GDMA_I2S_RX0); + } + } + + return 0; +} + + +static int mt76xx_pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *hw_params) +{ + /*struct snd_pcm_runtime *runtime = substream->runtime; + i2s_config_type *rtd = (i2s_config_type*)runtime->private_data; + */ + int ret,i; + ret = i = 0; + + //printk("******* %s *******\n", __func__); + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK){ + //i2s_page_prepare(rtd,STREAM_PLAYBACK); + } else { + //i2s_page_prepare(rtd,STREAM_CAPTURE); + } + + return ret; +} + +static int mt76xx_pcm_hw_free(struct snd_pcm_substream *substream) +{ + i2s_config_type* rtd = (i2s_config_type*)substream->runtime->private_data; + //struct snd_dma_buffer *buf = &substream->dma_buffer; + + //printk("******* %s *******\n", __func__); + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK){ + if(rtd->dmaStat[SNDRV_PCM_STREAM_PLAYBACK]){ + + gdma_En_Switch(rtd,STREAM_PLAYBACK,GDMA_I2S_DIS); + i2s_tx_end_sleep_on(rtd); + tasklet_kill(&i2s_tx_tasklet); + i2s_tx_disable(rtd); + //mt76xx_pcm_free_dma_buffer(substream,substream->stream); + i2s_page_release(rtd,STREAM_PLAYBACK); + rtd->dmaStat[SNDRV_PCM_STREAM_PLAYBACK] = 0; + } + mt76xx_pcm_free_dma_buffer(substream,substream->stream); + } + else{ + if(rtd->dmaStat[SNDRV_PCM_STREAM_CAPTURE]){ + + gdma_En_Switch(rtd,STREAM_CAPTURE,GDMA_I2S_DIS); + i2s_tx_end_sleep_on(rtd); + tasklet_kill(&i2s_rx_tasklet); + i2s_rx_disable(rtd); + //mt76xx_pcm_free_dma_buffer(substream,substream->stream); + i2s_page_release(rtd,STREAM_CAPTURE); + rtd->dmaStat[SNDRV_PCM_STREAM_CAPTURE] = 0; + } + mt76xx_pcm_free_dma_buffer(substream,substream->stream); + } + return 0; +} + +static int mt76xx_pcm_free_dma_buffer(struct snd_pcm_substream *substream, + int stream) +{ + + //struct snd_pcm_substream *substream = pcm->streams[stream].substream; + struct snd_dma_buffer *buf = &substream->dma_buffer; + i2s_config_type* rtd = (i2s_config_type*)substream->runtime->private_data; + + //printk("******* %s *******\n", __func__); + if (!buf->area) + return 0; + if(substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + i2s_memPool_free(rtd,STREAM_PLAYBACK); + else + i2s_memPool_free(rtd,STREAM_CAPTURE); + buf->area = NULL; + snd_pcm_set_runtime_buffer(substream, NULL); + return 0; +} + +static int mt76xx_pcm_allocate_dma_buffer(struct snd_pcm_substream *substream, + int stream) +{ + //struct snd_pcm_substream *substream = pcm->streams[stream].substream; + struct snd_dma_buffer *buf = &substream->dma_buffer; + i2s_config_type* rtd = (i2s_config_type*)substream->runtime->private_data; + + //printk("******* %s *******\n", __func__); + if(!buf->area){ +#if defined(CONFIG_I2S_MMAP) + printk("\n############## MMAP ##############\n"); + buf->dev.type = SNDRV_DMA_TYPE_DEV; +#else + buf->dev.type = SNDRV_DMA_TYPE_UNKNOWN; +#endif + buf->dev.dev = NULL; + buf->private_data = NULL; + if(stream == SNDRV_PCM_STREAM_PLAYBACK) + buf->area = i2s_memPool_Alloc(rtd,STREAM_PLAYBACK); + else + buf->area = i2s_memPool_Alloc(rtd,STREAM_CAPTURE); + + if (!buf->area) + return -ENOMEM; + buf->bytes = GDMA_TOTAL_PAGE_SIZE; +#if defined(CONFIG_I2S_MMAP) + buf->addr = i2s_mmap_phys_addr(rtd); +#endif + snd_pcm_set_runtime_buffer(substream, buf); + } else{ + //printk("Buffer have been allocated!\n"); + } + + return 0; +} + +static int mt76xx_pcm_open(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime= substream->runtime; + struct snd_dma_buffer *buf = &substream->dma_buffer; + int stream = substream->stream; + int ret = 0; + + //printk("******* %s *******\n", __func__); + snd_soc_set_runtime_hwparams(substream, &mt76xx_pcm_hwparam); + /* ensure that buffer size is a multiple of period size */ + ret = snd_pcm_hw_constraint_integer(runtime, + SNDRV_PCM_HW_PARAM_PERIODS); + if (ret < 0) + goto out; + +#if 1 + if(stream == SNDRV_PCM_STREAM_PLAYBACK){ + ret = mt76xx_pcm_allocate_dma_buffer(substream, + SNDRV_PCM_STREAM_PLAYBACK); + } + else{ + ret = mt76xx_pcm_allocate_dma_buffer(substream, + SNDRV_PCM_STREAM_CAPTURE); + } +#endif + + if (ret) + goto out; + + if(buf) + memset(buf->area,0,sizeof(I2S_PAGE_SIZE*MAX_I2S_PAGE)); + + out: + return ret; +} + + + +static int mt76xx_pcm_new(struct snd_soc_pcm_runtime *rtd) +{ +// int ret = 0; + + //printk("******* %s *******\n", __func__); + return 0; +} + +static void mt76xx_pcm_free(struct snd_pcm *pcm) +{ + /*struct snd_pcm_substream *substream; + struct snd_dma_buffer *buf; + i2s_config_type* rtd; + int stream; +*/ + //printk("******* %s *******\n", __func__); + //return 0; +} + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,20) +static int mt76xx_platform_drv_probe(struct platform_device *pdev) +{ + //printk("******* %s *******\n", __func__); + return snd_soc_register_platform(&pdev->dev, &mt76xx_soc_platform); +} + +static int mt76xx_platform_drv_remove(struct platform_device *pdev) +{ + //printk("******* %s *******\n", __func__); + snd_soc_unregister_platform(&pdev->dev); + return 0; +} + +static struct platform_driver mt76xx_pcm_driver = { + .driver = { + .name = "mt76xx-pcm", + .owner = THIS_MODULE, + }, + + .probe = mt76xx_platform_drv_probe, + .remove = mt76xx_platform_drv_remove, +}; + +static int __init mt76xx_pcm_init(void) +{ + + printk("******* %s *******\n", __func__); + return platform_driver_register(&mt76xx_pcm_driver); +} + +static void __exit mt76xx_pcm_exit(void) +{ + platform_driver_unregister(&mt76xx_pcm_driver); +} +#else +static int __init mt76xx_pcm_init(void) +{ + + printk("******* %s *******\n", __func__); + return snd_soc_register_platform(&mt76xx_soc_platform); +} + +static void __exit mt76xx_pcm_exit(void) +{ + printk("******* %s *******\n", __func__); + snd_soc_unregister_platform(&mt76xx_soc_platform); +} +#endif +module_init(mt76xx_pcm_init); +module_exit(mt76xx_pcm_exit); + +MODULE_AUTHOR("Dora Chen"); +MODULE_DESCRIPTION("MTK APSoC I2S DMA driver"); +MODULE_LICENSE("GPL"); + diff --git a/sound/soc/mtk/ralink_gdma.c b/sound/soc/mtk/ralink_gdma.c new file mode 100644 index 0000000..b385f05 --- /dev/null +++ b/sound/soc/mtk/ralink_gdma.c @@ -0,0 +1,918 @@ +/* + *************************************************************************** + * Ralink Tech Inc. + * 5F., No.36, Taiyuan St., Jhubei City, + * Hsinchu County 302, + * Taiwan, R.O.C. + * + * (c) Copyright, Ralink Technology, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + * + * + *************************************************************************** + * + Module Name: + ralink_gdma.c + + Abstract: + + Revision History: + Who When What + -------- ---------- ---------------------------------------------- + Name Date Modification logs + Steven Liu 2009-03-24 Support RT3883 + * + */ +#include +#include +#include +#include +#include +#include +#if defined (CONFIG_MIPS) + #include + #include +#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> 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<> ===\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<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<ChNum] = NewEntry->DoneIntCallback; + } + + if(NewEntry->SoftMode) { + Data |= (0x01<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<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<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 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 "); +MODULE_LICENSE("GPL"); +MODULE_VERSION(MOD_VERSION); diff --git a/sound/soc/mtk/ralink_gdma.h b/sound/soc/mtk/ralink_gdma.h new file mode 100644 index 0000000..95ce5f7 --- /dev/null +++ b/sound/soc/mtk/ralink_gdma.h @@ -0,0 +1,326 @@ +/* + *************************************************************************** + * Ralink Tech Inc. + * 5F., No.36, Taiyuan St., Jhubei City, + * Hsinchu County 302, + * Taiwan, R.O.C. + * + * (c) Copyright, Ralink Technology, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + * + * + *************************************************************************** + */ + +#ifndef __RALINK_DMA_CTRL_H__ +#define __RALINK_DMA_CTRL_H__ + +//#include + +/* + * 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 +#define GDMA_READ_REG(phys) (*(volatile unsigned int *)((phys))) +#define GDMA_WRITE_REG(phys, val) mt65xx_reg_sync_writel((val), (phys)) + +#else +#define GDMA_READ_REG(addr) (le32_to_cpu(*(volatile u32 *)(addr))) +#define GDMA_WRITE_REG(addr, val) *((volatile uint32_t *)(addr)) = cpu_to_le32(val) + + + +#endif + + +#define GET_GDMA_IP_VER (GDMA_READ_REG(RALINK_GDMA_GCT) & 0x6) >> 1 //GDMA_GCT[2:1] + +#define RALINK_IRQ_ADDR RALINK_INTCL_BASE +#if defined (CONFIG_RALINK_MT7621) || defined (CONFIG_ARCH_MT7628) +#define RALINK_REG_INTENA (RALINK_IRQ_ADDR + 0x80) +#define RALINK_REG_INTDIS (RALINK_IRQ_ADDR + 0x78) +#else +#define RALINK_REG_INTENA (RALINK_IRQ_ADDR + 0x34) +#define RALINK_REG_INTDIS (RALINK_IRQ_ADDR + 0x38) +#endif + +/* + * 12bytes=GDMA Channel n Source Address(4) + + * GDMA Channel n Destination Address(4) + + * GDMA Channel n Control Register(4) + * + */ +#define GDMA_SRC_REG(ch) (RALINK_GDMA_BASE + ch*16) +#define GDMA_DST_REG(ch) (GDMA_SRC_REG(ch) + 4) +#define GDMA_CTRL_REG(ch) (GDMA_DST_REG(ch) + 4) +#define GDMA_CTRL_REG1(ch) (GDMA_CTRL_REG(ch) + 4) + +//GDMA Interrupt Status Register +#if defined (CONFIG_RALINK_RT3052) +#define UNMASK_INT_STATUS(ch) (ch+16) +#elif defined (CONFIG_RALINK_RT3883) || defined (CONFIG_RALINK_RT3352) || defined (CONFIG_RALINK_RT5350) || defined (CONFIG_RALINK_RT6855) || defined (CONFIG_RALINK_RT6855A) || defined (CONFIG_RALINK_MT7620) || defined (CONFIG_RALINK_MT7621) || defined (CONFIG_RALINK_MT7628) || defined (CONFIG_ARCH_MT7623) +#define UNMASK_INT_STATUS(ch) (ch) +#endif +#define TXDONE_INT_STATUS(ch) (ch) + +//Control Reg0 +#define MODE_SEL_OFFSET 0 +#define CH_EBL_OFFSET 1 +#define CH_DONEINT_EBL_OFFSET 2 +#define BRST_SIZE_OFFSET 3 +#define DST_BRST_MODE_OFFSET 6 +#define SRC_BRST_MODE_OFFSET 7 +#define TRANS_CNT_OFFSET 16 + +//Control Reg1 +#if defined (CONFIG_RALINK_RT3052) +#define CH_UNMASKINT_EBL_OFFSET 4 +#define NEXT_UNMASK_CH_OFFSET 1 +#elif defined (CONFIG_RALINK_RT3883) || defined (CONFIG_RALINK_RT3352) || defined (CONFIG_RALINK_RT5350) || defined (CONFIG_RALINK_RT6855) || defined (CONFIG_RALINK_RT6855A) || defined (CONFIG_RALINK_MT7620) || defined (CONFIG_RALINK_MT7621) || defined (CONFIG_RALINK_MT7628) || defined (CONFIG_ARCH_MT7623) +#define CH_UNMASKINT_EBL_OFFSET 1 +#define NEXT_UNMASK_CH_OFFSET 3 +#endif +#define COHERENT_INT_EBL_OFFSET 2 +#define CH_MASK_OFFSET 0 + + +#if defined (CONFIG_RALINK_RT3052) +//Control Reg0 +#define DST_DMA_REQ_OFFSET 8 +#define SRC_DMA_REQ_OFFSET 12 +#elif defined (CONFIG_RALINK_RT3883) || defined (CONFIG_RALINK_RT3352) || defined (CONFIG_RALINK_RT5350) || defined (CONFIG_RALINK_RT6855) || defined (CONFIG_RALINK_RT6855A) || defined (CONFIG_RALINK_MT7620) || defined (CONFIG_RALINK_MT7621) || defined (CONFIG_RALINK_MT7628) || defined (CONFIG_ARCH_MT7623) +//Control Reg1 +#define DST_DMA_REQ_OFFSET 8 +#define SRC_DMA_REQ_OFFSET 16 +#endif + +#define GDMA_PCM0_RX0 0 +#define GDMA_PCM0_RX1 1 +#define GDMA_PCM0_TX0 2 +#define GDMA_PCM0_TX1 3 + +#define GDMA_PCM1_RX0 4 +#define GDMA_PCM1_RX1 5 +#define GDMA_PCM1_TX0 6 +#define GDMA_PCM1_TX1 7 + +#define GDMA_PCM_RX(i,j) (0+((i)<<2)+j) +#define GDMA_PCM_TX(i,j) (2+((i)<<2)+j) + +#define GDMA_I2S_TX0 4 +#define GDMA_I2S_TX1 5 +#define GDMA_I2S_RX0 6 +#define GDMA_I2S_RX1 7 + +#define GDMA_SPI_TX 13 +#define GDMA_SPI_RX 12 + + +//#define GDMA_DEBUG +#ifdef GDMA_DEBUG +#define GDMA_PRINT(fmt, args...) printk(KERN_INFO "GDMA: " fmt, ## args) +#else +#define GDMA_PRINT(fmt, args...) { } +#endif + +/* + * TYPEDEFS AND STRUCTURES + */ + +enum GdmaBusterMode { + INC_MODE=0, + FIX_MODE=1 +}; + +enum GdmaBusterSize { + BUSTER_SIZE_4B=0, /* 1 transfer */ + BUSTER_SIZE_8B=1, /* 2 transfer */ + BUSTER_SIZE_16B=2, /* 4 transfer */ + BUSTER_SIZE_32B=3, /* 8 transfer */ + BUSTER_SIZE_64B=4 /* 16 transfer */ +}; + +enum GdmaDmaReqNum { +#if defined (CONFIG_RALINK_RT3052) + DMA_REQ0=0, + DMA_NAND_REQ=1, + DMA_I2S_TX_REQ=2, + DMA_PCM_RX0_REQ=3, + DMA_PCM_RX1_REQ=4, + DMA_PCM_TX0_REQ=5, + DMA_PCM_TX1_REQ=6, + DMA_REG7=7, + DMA_MEM_REQ=8 +#elif defined (CONFIG_RALINK_RT3883) || defined (CONFIG_RALINK_RT3352) || defined (CONFIG_RALINK_RT5350) || defined (CONFIG_RALINK_RT6855) + DMA_REQ0=0, + DMA_NAND_REQ=1, + DMA_I2S_TX_REQ=2, + DMA_I2S_RX_REQ=3, + DMA_PCM_RX0_REQ=4, + DMA_PCM_RX1_REQ=5, + DMA_PCM_TX0_REQ=6, + DMA_PCM_TX1_REQ=7, + DMA_CODEC0_REQ8=8, + DMA_CODEC1_REQ9=9, + DMA_REQ10=10, + DMA_REQ11=11, + DMA_REQ12=12, + DMA_REQ13=13, + DMA_REQ14=14, + DMA_REQ15=15, + + #if defined (CONFIG_RALINK_RT3883) + DMA_MEM_REQ=16 + #elif defined (CONFIG_RALINK_RT3352) || defined (CONFIG_RALINK_RT5350) || defined (CONFIG_RALINK_RT6855) + DMA_MEM_REQ=32 + #endif + +#elif defined(CONFIG_RALINK_MT7620) || defined (CONFIG_RALINK_MT7621) || defined (CONFIG_RALINK_MT7628) || defined (CONFIG_ARCH_MT7623) + DMA_REQ0=0, + DMA_NAND_REQ=1, + DMA_I2S_TX_REQ=2, + DMA_I2S_RX_REQ=3, + DMA_PCM_RX0_REQ=4, + DMA_PCM_RX1_REQ=5, + DMA_PCM_TX0_REQ=6, + DMA_PCM_TX1_REQ=7, + DMA_PCM_RX2_REQ=8, + DMA_PCM_RX3_REQ=9, + DMA_PCM_TX2_REQ=10, + DMA_PCM_TX3_REQ=11, + DMA_SPI_RX_REQ=12, + DMA_SPI_TX_REQ=13, + DMA_MEM_REQ=32 + +#elif defined (CONFIG_RALINK_RT6855A) + DMA_NAND_REQ=0, + DMA_I2S_TX_REQ=1, + DMA_I2S_RX_REQ=2, + DMA_REQ0=3, + DMA_PCM_RX0_REQ=4, + DMA_PCM_RX1_REQ=5, + DMA_PCM_TX0_REQ=6, + DMA_PCM_TX1_REQ=7, + DMA_CODEC0_REQ8=8, + DMA_CODEC1_REQ9=9, + DMA_REQ10=10, + DMA_REQ11=11, + DMA_REQ12=12, + DMA_REQ13=13, + DMA_REQ14=14, + DMA_REQ15=15, + DMA_MEM_REQ=32 +#else +#error Please Choose System Type +#endif +}; + + + +typedef struct { + uint32_t Src; + uint32_t Dst; + uint16_t TransCount; + uint8_t SoftMode; + uint8_t NextUnMaskCh; + uint8_t ChMask; + uint8_t CoherentIntEbl; + uint32_t ChNum; + enum GdmaDmaReqNum SrcReqNum; + enum GdmaDmaReqNum DstReqNum; + enum GdmaBusterMode SrcBurstMode; + enum GdmaBusterMode DstBurstMode; + enum GdmaBusterSize BurstSize; + void (*DoneIntCallback)(uint32_t); + void (*UnMaskIntCallback)(uint32_t); +} GdmaReqEntry; + +/* + * EXPORT FUNCTION + */ +int GdmaI2sTx(uint32_t Src, uint32_t Dst, uint8_t TxNo, uint16_t TransCount, + void (*DoneIntCallback)(uint32_t data), + void (*UnMaskIntCallback)(uint32_t data)); + +int GdmaI2sRx(uint32_t Src, uint32_t Dst, uint8_t RxNo, uint16_t TransCount, + void (*DoneIntCallback)(uint32_t data), + void (*UnMaskIntCallback)(uint32_t data)); + +int GdmaPcmRx(uint32_t Src, uint32_t Dst, uint8_t PcmNo, uint8_t RxNo, uint16_t TransCount, + void (*DoneIntCallback)(uint32_t data), + void (*UnMaskIntCallback)(uint32_t data)); + +int GdmaPcmTx(uint32_t Src, uint32_t Dst, uint8_t PcmNo, uint8_t TxNo, uint16_t TransCount, + void (*DoneIntCallback)(uint32_t data), + void (*UnMaskIntCallback)(uint32_t data)); + +int GdmaSpiTx(uint32_t Src, uint32_t Dst, uint16_t TransCount, + void (*DoneIntCallback)(uint32_t data), + void (*UnMaskIntCallback)(uint32_t data)); + +int GdmaSpiRx(uint32_t Src, uint32_t Dst, uint16_t TransCount, + void (*DoneIntCallback)(uint32_t data), + void (*UnMaskIntCallback)(uint32_t data)); + + +int GdmaMem2Mem(uint32_t Src, uint32_t Dst, uint16_t TransCount, + void (*DoneIntCallback)(uint32_t data)); + +int GdmaMaskChannel(uint32_t ChNum); + +int GdmaUnMaskChannel(uint32_t ChNum); + +int GdmaReqQuickIns(uint32_t ChNum); + + +#endif diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 6173d15..d9c52a7 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1758,7 +1758,8 @@ static int soc_probe(struct platform_device *pdev) /* Bodge while we unpick instantiation */ card->dev = &pdev->dev; - return snd_soc_register_card(card); + snd_soc_register_card(card); + return 0; } static int soc_cleanup_card_resources(struct snd_soc_card *card) -- 1.7.10.4