add alc5621 and alc5631 codec support
author陈辉 <chenhui@rk29.(none)>
Tue, 19 Apr 2011 01:38:09 +0000 (09:38 +0800)
committer陈辉 <chenhui@rk29.(none)>
Tue, 19 Apr 2011 01:38:09 +0000 (09:38 +0800)
13 files changed:
arch/arm/configs/rk29_sdk_defconfig
arch/arm/mach-rk29/board-rk29sdk.c
sound/soc/codecs/Kconfig
sound/soc/codecs/Makefile
sound/soc/codecs/alc5621.c [new file with mode: 0644]
sound/soc/codecs/alc5621.h [new file with mode: 0644]
sound/soc/codecs/rt5631.c [new file with mode: 0644]
sound/soc/codecs/rt5631.h [new file with mode: 0644]
sound/soc/rk29/Kconfig [changed mode: 0755->0644]
sound/soc/rk29/Makefile [changed mode: 0755->0644]
sound/soc/rk29/rk29_alc5621.c [new file with mode: 0644]
sound/soc/rk29/rk29_i2s.c [changed mode: 0755->0644]
sound/soc/rk29/rk29_rt5631.c [new file with mode: 0644]

index cf905e66325265e68894c4cfd48c84d4d6830841..9919260e32b3c9894ea180cff3e9fbc68181aec0 100755 (executable)
@@ -1309,6 +1309,8 @@ CONFIG_SND_RK29_SOC_I2S=y
 CONFIG_SND_RK29_SOC_I2S_8CH=y
 # CONFIG_SND_RK29_SOC_WM8988 is not set
 CONFIG_SND_RK29_SOC_WM8900=y
+# CONFIG_SND_RK29_SOC_alc5621 is not set                                                                                       
+# CONFIG_SND_RK29_SOC_alc5631 is not set
 # CONFIG_SND_RK29_SOC_WM8994 is not set
 # CONFIG_SND_RK29_CODEC_SOC_MASTER is not set
 CONFIG_SND_RK29_CODEC_SOC_SLAVE=y
index c70363ffc42147088bbe94d9e97a434fd7e51e60..22442001d422769cb0950f202fbba529818a0ecf 100755 (executable)
@@ -512,6 +512,20 @@ static struct i2c_board_info __initdata board_i2c0_devices[] = {
                .flags                  = 0,
        },
 #endif
+#if defined (CONFIG_SND_SOC_alc5621)
+        {
+                .type                   = "ALC5621",
+                .addr                   = 0x1a,
+                .flags                  = 0,
+        },
+#endif
+#if defined (CONFIG_SND_SOC_alc5631)
+        {
+                .type                   = "rt5631",
+                .addr                   = 0x1a,
+                .flags                  = 0,
+        },
+#endif
 #if defined (CONFIG_SND_SOC_RK1000)
        {
                .type                   = "rk1000_i2c_codec",
index 1d0c6bf24363f191d541c7febd96ca7581e9ea98..4ba65a696c2df4204eb2e4aac7da6b087f34fe57 100644 (file)
@@ -42,6 +42,8 @@ config SND_SOC_ALL_CODECS
        select SND_SOC_WM8753 if SND_SOC_I2C_AND_SPI
        select SND_SOC_WM8776 if SND_SOC_I2C_AND_SPI
        select SND_SOC_WM8900 if I2C
+       select SND_SOC_alc5621 if I2C
+       select SND_SOC_alc5631 if I2C
        select SND_SOC_WM8903 if I2C
        select SND_SOC_WM8940 if I2C
        select SND_SOC_WM8960 if I2C
@@ -66,11 +68,13 @@ config SND_SOC_ALL_CODECS
          be selected separately.
 
           If unsure select "N".
-
+select SND_SOC_ALC5623_RT if I2C
+config SND_SOC_ALC5623
+        tristate
 config SND_SOC_WM_HUBS
        tristate
-       default y if SND_SOC_WM8993=y || SND_SOC_WM8994=y
-       default m if SND_SOC_WM8993=m || SND_SOC_WM8994=m
+       default y if SND_SOC_WM8993=y
+       default m if SND_SOC_WM8993=m
 
 config SND_SOC_AC97_CODEC
        tristate
@@ -179,6 +183,12 @@ config SND_SOC_WM8776
 config SND_SOC_WM8900
        tristate
 
+config SND_SOC_alc5621
+       tristate
+
+config SND_SOC_alc5631
+       tristate
+       
 config SND_SOC_WM8903
        tristate
 
index 36af1ce465dfc248d4876e9539f79ce4904e675d..49b4439c6a359acef739828633fc86563a0a62ff 100644 (file)
@@ -30,6 +30,8 @@ snd-soc-wm8750-objs := wm8750.o
 snd-soc-wm8753-objs := wm8753.o
 snd-soc-wm8776-objs := wm8776.o
 snd-soc-wm8900-objs := wm8900.o
+snd-soc-alc5621-objs := alc5621.o
+snd-soc-alc5631-objs := rt5631.o
 snd-soc-wm8903-objs := wm8903.o
 snd-soc-wm8940-objs := wm8940.o
 snd-soc-wm8960-objs := wm8960.o
@@ -49,6 +51,8 @@ snd-soc-rk1000-objs := rk1000_codec.o
 # Amp
 snd-soc-max9877-objs := max9877.o
 
+snd-soc-alc5623-objs := alc5623_tuning.o
+obj-$(CONFIG_SND_SOC_ALC5623)   += snd-soc-alc5623.o
 obj-$(CONFIG_SND_SOC_AC97_CODEC)       += snd-soc-ac97.o
 obj-$(CONFIG_SND_SOC_AD1836)   += snd-soc-ad1836.o
 obj-$(CONFIG_SND_SOC_AD1938)   += snd-soc-ad1938.o
@@ -81,6 +85,8 @@ obj-$(CONFIG_SND_SOC_WM8750)  += snd-soc-wm8750.o
 obj-$(CONFIG_SND_SOC_WM8753)   += snd-soc-wm8753.o
 obj-$(CONFIG_SND_SOC_WM8776)   += snd-soc-wm8776.o
 obj-$(CONFIG_SND_SOC_WM8900)   += snd-soc-wm8900.o
+obj-$(CONFIG_SND_SOC_alc5621)  += snd-soc-alc5621.o
+obj-$(CONFIG_SND_SOC_alc5631)  += snd-soc-alc5631.o
 obj-$(CONFIG_SND_SOC_WM8903)   += snd-soc-wm8903.o
 obj-$(CONFIG_SND_SOC_WM8971)   += snd-soc-wm8971.o
 obj-$(CONFIG_SND_SOC_WM8974)   += snd-soc-wm8974.o
diff --git a/sound/soc/codecs/alc5621.c b/sound/soc/codecs/alc5621.c
new file mode 100644 (file)
index 0000000..ab04ab7
--- /dev/null
@@ -0,0 +1,1932 @@
+#include <linux/module.h>\r
+#include <linux/moduleparam.h>\r
+#include <linux/version.h>\r
+#include <linux/kernel.h>\r
+#include <linux/init.h>\r
+#include <linux/delay.h>\r
+#include <linux/pm.h>\r
+#include <linux/i2c.h>\r
+#include <linux/platform_device.h>\r
+\r
+#include <sound/core.h>\r
+#include <sound/pcm.h>\r
+#include <sound/pcm_params.h>\r
+#include <sound/soc.h>\r
+#include <sound/soc-dapm.h>\r
+#include <sound/initval.h>\r
+#include <asm/div64.h>\r
+#include "alc5621.h"\r
+\r
+#if REALTEK_HWDEP\r
+\r
+#include <linux/ioctl.h>\r
+#include <linux/types.h>\r
+\r
+#endif\r
+\r
+#define AUDIO_NAME "rt5621"\r
+#define RT5621_VERSION "alsa 1.0.21 0.05"\r
+\r
+#ifdef RT5621_DEBUG\r
+#define dbg(format, arg...) \\r
+       printk(KERN_DEBUG AUDIO_NAME ": " format "\n" , ## arg)\r
+#else\r
+#define dbg(format, arg...) do {} while (0)\r
+#endif\r
+#define err(format, arg...) \\r
+       printk(KERN_ERR AUDIO_NAME ": " format "\n" , ## arg)\r
+#define info(format, arg...) \\r
+       printk(KERN_INFO AUDIO_NAME ": " format "\n" , ## arg)\r
+#define warn(format, arg...) \\r
+       printk(KERN_WARNING AUDIO_NAME ": " format "\n" , ## arg)\r
+       \r
+static int caps_charge = 500;\r
+module_param(caps_charge, int, 0);\r
+MODULE_PARM_DESC(caps_charge, "RT5621 cap charge time (msecs)");\r
+\r
+/* codec private data */\r
+struct rt5621_priv {\r
+       unsigned int sysclk;\r
+};\r
+\r
+static struct snd_soc_device *rt5621_socdev;\r
+\r
+struct rt5621_reg{\r
+\r
+       u8 reg_index;\r
+       u16 reg_value;\r
+};\r
+\r
+static struct rt5621_reg init_data[] = {\r
+       {RT5621_AUDIO_INTERFACE,        0x8000},    //set I2S codec to slave mode\r
+       {RT5621_STEREO_DAC_VOL,         0x0808},    //default stereo DAC volume to 0db\r
+       {RT5621_OUTPUT_MIXER_CTRL,      0x0740},    //default output mixer control      \r
+       {RT5621_ADC_REC_MIXER,          0x3f3f},    //set record source is Mic1 by default\r
+       {RT5621_MIC_CTRL,               0x0500},    //set Mic1,Mic2 boost 20db  \r
+       {RT5621_SPK_OUT_VOL,            0x8080},    //default speaker volume to 0db \r
+       {RT5621_HP_OUT_VOL,             0x8888},    //default HP volume to -12db        \r
+       {RT5621_ADD_CTRL_REG,           0x5f00},    //Class AB/D speaker ratio is 1VDD\r
+       {RT5621_STEREO_AD_DA_CLK_CTRL,  0x066d},    //set Dac filter to 256fs\r
+       {RT5621_HID_CTRL_INDEX,         0x46},      //Class D setting\r
+       {RT5621_HID_CTRL_DATA,          0xFFFF},    //power on Class D Internal register\r
+};\r
+\r
+#define RT5621_INIT_REG_NUM ARRAY_SIZE(init_data)\r
+\r
+/*\r
+ * rt5621 register cache\r
+ * We can't read the RT5621 register space when we\r
+ * are using 2 wire for device control, so we cache them instead.\r
+ */\r
+static const u16 rt5621_reg[0x80/2];\r
+\r
+\r
+/* virtual HP mixers regs */\r
+#define HPL_MIXER      0x80\r
+#define HPR_MIXER      0x82\r
+/*reg84*/\r
+/*bit0,1:for hp pga power control\r
+ *bit2,3:for aux pga power control\r
+ */\r
+#define MISC_FUNC_REG 0x84\r
+static u16 reg80=0,reg82=0, reg84 = 0;\r
+\r
+\r
+/*\r
+ * read rt5621 register cache\r
+ */\r
+static inline unsigned int rt5621_read_reg_cache(struct snd_soc_codec *codec,\r
+       unsigned int reg)\r
+{\r
+       u16 *cache = codec->reg_cache;\r
+       if (reg < 1 || reg > (ARRAY_SIZE(rt5621_reg) + 1))\r
+               return -1;\r
+       return cache[reg/2];\r
+}\r
+\r
+\r
+/*\r
+ * write rt5621 register cache\r
+ */\r
+\r
+static inline void rt5621_write_reg_cache(struct snd_soc_codec *codec,\r
+       unsigned int reg, unsigned int value)\r
+{\r
+       u16 *cache = codec->reg_cache;\r
+       if (reg < 0 || reg > 0x7e)\r
+               return;\r
+       cache[reg/2] = value;\r
+}\r
+\r
+\r
+\r
+static int rt5621_write(struct snd_soc_codec *codec, unsigned int reg,\r
+       unsigned int value)\r
+{\r
+       u8 data[3];\r
+\r
+       if(reg>0x7E)\r
+       {\r
+               if(reg==HPL_MIXER)\r
+                       reg80=value;\r
+               else if(reg==HPR_MIXER)\r
+                       reg82=value;\r
+               else if (reg == MISC_FUNC_REG)\r
+                       reg84 = value;\r
+               else\r
+                       return -EIO;\r
+       \r
+               return 0;       \r
+       }       \r
+\r
+\r
+       printk("rt5621 write reg=%x,value=%x\n",reg,value);\r
+       data[0] = reg;\r
+       data[1] = (0xFF00 & value) >> 8;\r
+       data[2] = 0x00FF & value;\r
+\r
+       if (codec->hw_write(codec->control_data, data, 3) == 3)\r
+       {\r
+               rt5621_write_reg_cache (codec, reg, value);             \r
+               printk(KERN_INFO "rt5621 write reg=%x,value=%x\n",reg,value);\r
+               return 0;\r
+       }\r
+       else\r
+       {\r
+               printk(KERN_ERR "rt5621 write faile\n");\r
+               return -EIO;\r
+       }\r
+}\r
+\r
+\r
+static unsigned int rt5621_read(struct snd_soc_codec *codec, unsigned int reg)\r
+{\r
+       u8 data[2]={0};\r
+       unsigned int value=0x0;\r
+\r
+       if(reg>0x7E)\r
+       {\r
+               if(reg==HPL_MIXER)\r
+                return reg80;\r
+               else if(reg==HPR_MIXER)\r
+                return reg82;\r
+               else if (reg == MISC_FUNC_REG)\r
+                       return reg84;\r
+               else\r
+                return -EIO;\r
+                \r
+                return -EIO;   \r
+       }\r
+\r
+\r
+       data[0] = reg;\r
+//flove031811_S\r
+#if 0\r
+      i2c_master_recv(codec->control_data, data, 2);\r
+      \r
+       value = (data[0]<<8) | data[1];         \r
+       printk("rt5621_read reg%x=%x\n",reg,value);\r
+#elif 1\r
+\r
+       i2c_master_reg8_recv(codec->control_data,reg,data, 2,100 * 1000);\r
+\r
+             value = (data[0]<<8) | data[1];         \r
+       printk("rt5621_read reg%x=%x\n",reg,value);\r
+          return value;\r
+\r
+#else  \r
+       if(codec->hw_write(codec->control_data, data, 1) ==1)\r
+       {\r
+               i2c_master_recv(codec->control_data, data, 2);\r
+\r
+               value = (data[0]<<8) | data[1];         \r
+               printk(KERN_DEBUG "rt5621 read reg%x=%x\n",reg,value);\r
+               \r
+               return value;\r
+       }\r
+       else\r
+       {\r
+               printk(KERN_ERR "rt5621 read faile\n");\r
+               return -EIO;                    \r
+       }               \r
+#endif\r
+//flove031811_E        \r
+}\r
+\r
+#define rt5621_write_mask(c, reg, value, mask) snd_soc_update_bits(c, reg, mask, value)\r
+\r
+\r
+#define rt5621_reset(c) rt5621_write(c, 0x0, 0)\r
+\r
+static unsigned int rt5621_read_index(struct snd_soc_codec *codec, unsigned int index)\r
+{\r
+       unsigned int value;\r
+\r
+       rt5621_write(codec, 0x6a, index);\r
+       mdelay(1);\r
+       value = rt5621_read(codec, 0x6c);\r
+       return value;\r
+}\r
+\r
+static int rt5621_init_reg(struct snd_soc_codec *codec)\r
+{\r
+       int i;\r
+\r
+       for (i = 0; i < RT5621_INIT_REG_NUM; i++)\r
+       {\r
+               rt5621_write(codec, init_data[i].reg_index, init_data[i].reg_value);\r
+       }\r
+\r
+       return 0;\r
+}\r
+\r
+\r
+#if !USE_DAPM_CONTROL\r
+//*****************************************************************************\r
+//\r
+//function:Change audio codec power status\r
+//\r
+//*****************************************************************************\r
+static int rt5621_ChangeCodecPowerStatus(struct snd_soc_codec *codec,int power_state)\r
+{\r
+       unsigned short int PowerDownState=0;\r
+\r
+       switch(power_state)\r
+       {\r
+               case POWER_STATE_D0:                    //FULL ON-----power on all power\r
+                       \r
+                       rt5621_write(codec,RT5621_PWR_MANAG_ADD1,~PowerDownState);\r
+                       rt5621_write(codec,RT5621_PWR_MANAG_ADD2,~PowerDownState);\r
+                       rt5621_write(codec,RT5621_PWR_MANAG_ADD3,~PowerDownState);\r
+\r
+               break;  \r
+\r
+               case POWER_STATE_D1:            //LOW ON-----\r
+\r
+\r
+                       rt5621_write_mask(codec,RT5621_PWR_MANAG_ADD2 ,PWR_VREF |PWR_DAC_REF_CIR |PWR_L_DAC_CLK |PWR_R_DAC_CLK |PWR_L_HP_MIXER |PWR_R_HP_MIXER|\r
+                                                                                                        PWR_L_ADC_CLK_GAIN |PWR_R_ADC_CLK_GAIN |PWR_L_ADC_REC_MIXER |PWR_R_ADC_REC_MIXER|PWR_CLASS_AB\r
+                                                                                                       ,PWR_VREF |PWR_DAC_REF_CIR |PWR_L_DAC_CLK |PWR_R_DAC_CLK |PWR_L_HP_MIXER |PWR_R_HP_MIXER|\r
+                                                                                                        PWR_L_ADC_CLK_GAIN |PWR_R_ADC_CLK_GAIN |PWR_L_ADC_REC_MIXER |PWR_R_ADC_REC_MIXER|PWR_CLASS_AB);\r
+\r
+                       rt5621_write_mask(codec,RT5621_PWR_MANAG_ADD3 ,PWR_MAIN_BIAS|PWR_HP_R_OUT_VOL|PWR_HP_L_OUT_VOL|PWR_SPK_OUT|\r
+                                                                                                        PWR_MIC1_FUN_CTRL|PWR_MIC1_BOOST_MIXER\r
+                                                                                                       ,PWR_MAIN_BIAS|PWR_HP_R_OUT_VOL|PWR_HP_L_OUT_VOL|PWR_SPK_OUT|\r
+                                                                                                        PWR_MIC1_FUN_CTRL|PWR_MIC1_BOOST_MIXER);                       \r
+\r
+\r
+                       rt5621_write_mask(codec,RT5621_PWR_MANAG_ADD1 ,PWR_MAIN_I2S_EN|PWR_HP_OUT_ENH_AMP|PWR_HP_OUT_AMP|PWR_MIC1_BIAS_EN\r
+                                                                                                       ,PWR_MAIN_I2S_EN|PWR_HP_OUT_ENH_AMP|PWR_HP_OUT_AMP|PWR_MIC1_BIAS_EN);\r
+                                               \r
+               break;\r
+\r
+               case POWER_STATE_D1_PLAYBACK:   //Low on of Playback\r
+\r
+\r
+                       rt5621_write_mask(codec,RT5621_PWR_MANAG_ADD2,PWR_VREF|PWR_DAC_REF_CIR|PWR_L_DAC_CLK|PWR_R_DAC_CLK|PWR_L_HP_MIXER|PWR_R_HP_MIXER|PWR_CLASS_AB|PWR_CLASS_D\r
+                                                                                                                ,PWR_VREF|PWR_DAC_REF_CIR|PWR_L_DAC_CLK|PWR_R_DAC_CLK|PWR_L_HP_MIXER|PWR_R_HP_MIXER|PWR_CLASS_AB|PWR_CLASS_D);\r
+\r
+                       rt5621_write_mask(codec,RT5621_PWR_MANAG_ADD3,PWR_MAIN_BIAS|PWR_HP_R_OUT_VOL|PWR_HP_L_OUT_VOL|PWR_SPK_OUT \r
+                                                                                                                ,PWR_MAIN_BIAS|PWR_HP_R_OUT_VOL|PWR_HP_L_OUT_VOL|PWR_SPK_OUT);         \r
+\r
+                       rt5621_write_mask(codec,RT5621_PWR_MANAG_ADD1,PWR_MAIN_I2S_EN|PWR_HP_OUT_ENH_AMP|PWR_HP_OUT_AMP\r
+                                                                                                                ,PWR_MAIN_I2S_EN|PWR_HP_OUT_ENH_AMP|PWR_HP_OUT_AMP);\r
+                                                                       \r
+\r
+               break;\r
+\r
+               case POWER_STATE_D1_RECORD:     //Low on of Record\r
+\r
+                       rt5621_write_mask(codec,RT5621_PWR_MANAG_ADD1 ,PWR_MAIN_I2S_EN|PWR_MIC1_BIAS_EN\r
+                                                                                                                 ,PWR_MAIN_I2S_EN|PWR_MIC1_BIAS_EN);                                                                                      \r
+                                                                                       \r
+                       rt5621_write_mask(codec,RT5621_PWR_MANAG_ADD2 ,PWR_VREF|PWR_L_ADC_CLK_GAIN|PWR_R_ADC_CLK_GAIN|PWR_L_ADC_REC_MIXER|PWR_R_ADC_REC_MIXER\r
+                                                                                                             ,PWR_VREF|PWR_L_ADC_CLK_GAIN|PWR_R_ADC_CLK_GAIN|PWR_L_ADC_REC_MIXER|PWR_R_ADC_REC_MIXER);\r
+\r
+                       rt5621_write_mask(codec,RT5621_PWR_MANAG_ADD3 ,PWR_MAIN_BIAS|PWR_MIC2_BOOST_MIXER|PWR_MIC1_BOOST_MIXER\r
+                                                                                                             ,PWR_MAIN_BIAS|PWR_MIC2_BOOST_MIXER|PWR_MIC1_BOOST_MIXER);                \r
+       \r
+               break;\r
+\r
+               case POWER_STATE_D2:            //STANDBY----\r
+\r
+                       rt5621_write_mask(codec,RT5621_PWR_MANAG_ADD1 ,0,PWR_MAIN_I2S_EN|PWR_HP_OUT_ENH_AMP|PWR_HP_OUT_AMP|PWR_MIC1_BIAS_EN);                                                                                      \r
+\r
+\r
+                       rt5621_write_mask(codec,RT5621_PWR_MANAG_ADD3 ,0,PWR_HP_R_OUT_VOL|PWR_HP_L_OUT_VOL|PWR_SPK_OUT|PWR_MIC1_FUN_CTRL|PWR_MIC1_BOOST_MIXER);\r
+\r
+                                                                                                               \r
+                       rt5621_write_mask(codec,RT5621_PWR_MANAG_ADD2 ,0,PWR_DAC_REF_CIR |PWR_L_DAC_CLK |PWR_R_DAC_CLK |PWR_L_HP_MIXER |PWR_R_HP_MIXER|\r
+                                                                                                                        PWR_L_ADC_CLK_GAIN |PWR_R_ADC_CLK_GAIN |PWR_L_ADC_REC_MIXER |PWR_R_ADC_REC_MIXER|PWR_CLASS_AB|PWR_CLASS_D);\r
+\r
+               \r
+               break;\r
+\r
+               case POWER_STATE_D2_PLAYBACK:   //STANDBY of playback\r
+\r
+                       rt5621_write_mask(codec,RT5621_PWR_MANAG_ADD3 ,0,/*PWR_HP_R_OUT_VOL|PWR_HP_L_OUT_VOL|*/PWR_SPK_OUT);\r
+\r
+                       rt5621_write_mask(codec,RT5621_PWR_MANAG_ADD1 ,0,PWR_HP_OUT_ENH_AMP|PWR_HP_OUT_AMP);                                                                                       \r
+                                                                       \r
+                       rt5621_write_mask(codec,RT5621_PWR_MANAG_ADD2 ,0,PWR_DAC_REF_CIR|PWR_L_DAC_CLK|PWR_R_DAC_CLK|PWR_L_HP_MIXER|PWR_R_HP_MIXER|PWR_CLASS_AB|PWR_CLASS_D);\r
+\r
+               break;\r
+\r
+               case POWER_STATE_D2_RECORD:             //STANDBY of record\r
+\r
+                       rt5621_write_mask(codec,RT5621_PWR_MANAG_ADD1 ,0,PWR_MIC1_BIAS_EN);                                                                                        \r
+                                                                                       \r
+                       rt5621_write_mask(codec,RT5621_PWR_MANAG_ADD2 ,0,PWR_L_ADC_CLK_GAIN|PWR_R_ADC_CLK_GAIN|PWR_L_ADC_REC_MIXER|PWR_R_ADC_REC_MIXER);\r
+\r
+                       rt5621_write_mask(codec,RT5621_PWR_MANAG_ADD3 ,0,PWR_MIC2_BOOST_MIXER|PWR_MIC1_BOOST_MIXER);            \r
+\r
+               break;          \r
+\r
+               case POWER_STATE_D3:            //SLEEP\r
+               case POWER_STATE_D4:            //OFF----power off all power\r
+                       rt5621_write_mask(codec,RT5621_PWR_MANAG_ADD1 ,0,PWR_HP_OUT_ENH_AMP|PWR_HP_OUT_AMP);            \r
+                       rt5621_write(codec,RT5621_PWR_MANAG_ADD3,0);\r
+                       rt5621_write(codec,RT5621_PWR_MANAG_ADD1,0);\r
+                       rt5621_write(codec,RT5621_PWR_MANAG_ADD2,0);\r
+                                               \r
+               break;  \r
+\r
+               default:\r
+\r
+               break;\r
+       }\r
+\r
+       return 0;\r
+}\r
+\r
+\r
+//*****************************************************************************\r
+//\r
+//function AudioOutEnable:Mute/Unmute audio out channel\r
+//                                                     WavOutPath:output channel\r
+//                                                     Mute :Mute/Unmute output channel                                                                                        \r
+//\r
+//*****************************************************************************\r
+static int rt5621_AudioOutEnable(struct snd_soc_codec *codec,unsigned short int WavOutPath,int Mute)\r
+{\r
+       int RetVal=0;   \r
+\r
+       if(Mute)\r
+       {\r
+               switch(WavOutPath)\r
+               {\r
+                       case RT_WAVOUT_ALL_ON:\r
+\r
+                               RetVal=rt5621_write_mask(codec,RT5621_SPK_OUT_VOL,RT_L_MUTE|RT_R_MUTE,RT_L_MUTE|RT_R_MUTE);     //Mute Speaker right/left channel\r
+                               RetVal=rt5621_write_mask(codec,RT5621_HP_OUT_VOL,RT_L_MUTE|RT_R_MUTE,RT_L_MUTE|RT_R_MUTE);      //Mute headphone right/left channel\r
+                               RetVal=rt5621_write_mask(codec,RT5621_MONO_AUX_OUT_VOL,RT_L_MUTE|RT_R_MUTE,RT_L_MUTE|RT_R_MUTE);        //Mute Aux/Mono right/left channel\r
+                               RetVal=rt5621_write_mask(codec,RT5621_STEREO_DAC_VOL,RT_M_HP_MIXER|RT_M_SPK_MIXER|RT_M_MONO_MIXER\r
+                                                                                                                         ,RT_M_HP_MIXER|RT_M_SPK_MIXER|RT_M_MONO_MIXER);       //Mute DAC to HP,Speaker,Mono Mixer\r
+               \r
+                       break;\r
+               \r
+                       case RT_WAVOUT_HP:\r
+\r
+                               RetVal=rt5621_write_mask(codec,RT5621_HP_OUT_VOL,RT_L_MUTE|RT_R_MUTE,RT_L_MUTE|RT_R_MUTE);      //Mute headphone right/left channel\r
+                       \r
+                       break;\r
+\r
+                       case RT_WAVOUT_SPK:\r
+                               \r
+                               RetVal=rt5621_write_mask(codec,RT5621_SPK_OUT_VOL,RT_L_MUTE|RT_R_MUTE,RT_L_MUTE|RT_R_MUTE);     //Mute Speaker right/left channel                       \r
+\r
+                       break;\r
+                       \r
+                       case RT_WAVOUT_AUXOUT:\r
+\r
+                               RetVal=rt5621_write_mask(codec,RT5621_MONO_AUX_OUT_VOL,RT_L_MUTE|RT_R_MUTE,RT_L_MUTE|RT_R_MUTE);        //Mute AuxOut right/left channel\r
+\r
+                       break;\r
+\r
+                       case RT_WAVOUT_MONO:\r
+\r
+                               RetVal=rt5621_write_mask(codec,RT5621_MONO_AUX_OUT_VOL,RT_L_MUTE,RT_L_MUTE);    //Mute MonoOut channel          \r
+\r
+                       break;\r
+\r
+                       case RT_WAVOUT_DAC:\r
+\r
+                               RetVal=rt5621_write_mask(codec,RT5621_STEREO_DAC_VOL,RT_M_HP_MIXER|RT_M_SPK_MIXER|RT_M_MONO_MIXER\r
+                                                                                                                         ,RT_M_HP_MIXER|RT_M_SPK_MIXER|RT_M_MONO_MIXER);       //Mute DAC to HP,Speaker,Mono Mixer                             \r
+                       break;\r
+\r
+                       default:\r
+\r
+                               return 0;\r
+\r
+               }\r
+       }\r
+       else\r
+       {\r
+               switch(WavOutPath)\r
+               {\r
+\r
+                       case RT_WAVOUT_ALL_ON:\r
+\r
+                               RetVal=rt5621_write_mask(codec,RT5621_SPK_OUT_VOL               ,0,RT_L_MUTE|RT_R_MUTE);        //Mute Speaker right/left channel\r
+                               RetVal=rt5621_write_mask(codec,RT5621_HP_OUT_VOL                ,0,RT_L_MUTE|RT_R_MUTE);        //Mute headphone right/left channel\r
+                               RetVal=rt5621_write_mask(codec,RT5621_MONO_AUX_OUT_VOL  ,0,RT_L_MUTE|RT_R_MUTE);        //Mute Aux/Mono right/left channel\r
+                               RetVal=rt5621_write_mask(codec,RT5621_STEREO_DAC_VOL    ,0,RT_M_HP_MIXER|RT_M_SPK_MIXER|RT_M_MONO_MIXER);       //Mute DAC to HP,Speaker,Mono Mixer\r
+               \r
+                       break;\r
+               \r
+                       case RT_WAVOUT_HP:\r
+\r
+                               RetVal=rt5621_write_mask(codec,RT5621_HP_OUT_VOL,0,RT_L_MUTE|RT_R_MUTE);        //UnMute headphone right/left channel   \r
+                                       \r
+                       break;\r
+\r
+                       case RT_WAVOUT_SPK:\r
+                               \r
+                               RetVal=rt5621_write_mask(codec,RT5621_SPK_OUT_VOL,0,RT_L_MUTE|RT_R_MUTE);       //unMute Speaker right/left channel                     \r
+\r
+                       break;\r
+                       \r
+                       case RT_WAVOUT_AUXOUT:\r
+\r
+                               RetVal=rt5621_write_mask(codec,RT5621_MONO_AUX_OUT_VOL,0,RT_L_MUTE|RT_R_MUTE);//unMute AuxOut right/left channel\r
+\r
+                       break;\r
+\r
+                       case RT_WAVOUT_MONO:\r
+\r
+                               RetVal=rt5621_write_mask(codec,RT5621_MONO_AUX_OUT_VOL,0,RT_L_MUTE);    //unMute MonoOut channel                \r
+\r
+                       break;\r
+\r
+                       case RT_WAVOUT_DAC:\r
+\r
+                               RetVal=rt5621_write_mask(codec,RT5621_STEREO_DAC_VOL,0,RT_M_HP_MIXER|RT_M_SPK_MIXER|RT_M_MONO_MIXER);   //unMute DAC to HP,Speaker,Mono Mixer\r
+\r
+                       default:\r
+                               return 0;\r
+               }\r
+\r
+       }\r
+       \r
+       return RetVal;\r
+}\r
+\r
+\r
+//*****************************************************************************\r
+//\r
+//function:Enable/Disable ADC input source control\r
+//\r
+//*****************************************************************************\r
+static int Enable_ADC_Input_Source(struct snd_soc_codec *codec,unsigned short int ADC_Input_Sour,int Enable)\r
+{\r
+       int bRetVal=0;\r
+       \r
+       if(Enable)\r
+       {\r
+               //Enable ADC source \r
+               bRetVal=rt5621_write_mask(codec,RT5621_ADC_REC_MIXER,0,ADC_Input_Sour);\r
+       }\r
+       else\r
+       {\r
+               //Disable ADC source            \r
+               bRetVal=rt5621_write_mask(codec,RT5621_ADC_REC_MIXER,ADC_Input_Sour,ADC_Input_Sour);\r
+       }\r
+\r
+       return bRetVal;\r
+}\r
+#endif\r
+\r
+\r
+//static const char *rt5621_spkl_pga[] = {"Vmid","HPL mixer","SPK mixer","Mono Mixer"};\r
+static const char *rt5621_spkn_source_sel[] = {"RN", "RP", "LN"};\r
+static const char *rt5621_spk_pga[] = {"Vmid","HP mixer","SPK mixer","Mono Mixer"};\r
+static const char *rt5621_hpl_pga[]  = {"Vmid","HPL mixer"};\r
+static const char *rt5621_hpr_pga[]  = {"Vmid","HPR mixer"};\r
+static const char *rt5621_mono_pga[] = {"Vmid","HP mixer","SPK mixer","Mono Mixer"};\r
+static const char *rt5621_amp_type_sel[] = {"Class AB","Class D"};\r
+static const char *rt5621_mic_boost_sel[] = {"Bypass","20db","30db","40db"};\r
+\r
+static const struct soc_enum rt5621_enum[] = {\r
+SOC_ENUM_SINGLE(RT5621_OUTPUT_MIXER_CTRL, 14, 3, rt5621_spkn_source_sel), /* spkn source from hp mixer */      \r
+SOC_ENUM_SINGLE(RT5621_OUTPUT_MIXER_CTRL, 10, 4, rt5621_spk_pga), /* spk input sel 1 */        \r
+SOC_ENUM_SINGLE(RT5621_OUTPUT_MIXER_CTRL, 9, 2, rt5621_hpl_pga), /* hp left input sel 2 */     \r
+SOC_ENUM_SINGLE(RT5621_OUTPUT_MIXER_CTRL, 8, 2, rt5621_hpr_pga), /* hp right input sel 3 */    \r
+SOC_ENUM_SINGLE(RT5621_OUTPUT_MIXER_CTRL, 6, 4, rt5621_mono_pga), /* mono input sel 4 */\r
+SOC_ENUM_SINGLE(RT5621_MIC_CTRL                        , 10,4, rt5621_mic_boost_sel), /*Mic1 boost sel 5 */\r
+SOC_ENUM_SINGLE(RT5621_MIC_CTRL                        , 8,4,rt5621_mic_boost_sel), /*Mic2 boost sel 6 */\r
+SOC_ENUM_SINGLE(RT5621_OUTPUT_MIXER_CTRL,13,2,rt5621_amp_type_sel), /*Speaker AMP sel 7 */\r
+};\r
+\r
+static int rt5621_amp_sel_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)\r
+{\r
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);\r
+       struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;\r
+       unsigned short val;\r
+       unsigned short mask, bitmask;\r
+\r
+       for (bitmask = 1; bitmask < e->max; bitmask <<= 1)\r
+               ;\r
+       if (ucontrol->value.enumerated.item[0] > e->max - 1)\r
+               return -EINVAL;\r
+       val = ucontrol->value.enumerated.item[0] << e->shift_l;\r
+       mask = (bitmask - 1) << e->shift_l;\r
+       if (e->shift_l != e->shift_r) {\r
+               if (ucontrol->value.enumerated.item[1] > e->max - 1)\r
+                       return -EINVAL;\r
+               val |= ucontrol->value.enumerated.item[1] << e->shift_r;\r
+               mask |= (bitmask - 1) << e->shift_r;\r
+       }\r
+\r
+        snd_soc_update_bits(codec, e->reg, mask, val);\r
+        val &= (0x1 << 13);\r
+        if (val == 0)\r
+        {\r
+                snd_soc_update_bits(codec, 0x3c, 0x0000, 0x4000);       /*power off classd*/\r
+                snd_soc_update_bits(codec, 0x3c, 0x8000, 0x8000);       /*power on classab*/\r
+        }\r
+        else\r
+       {\r
+                snd_soc_update_bits(codec, 0x3c, 0x0000, 0x8000);       /*power off classab*/\r
+                snd_soc_update_bits(codec, 0x3c, 0x4000, 0x4000);       /*power on classd*/\r
+        }\r
+       return 0;\r
+}\r
+\r
+\r
+\r
+static const struct snd_kcontrol_new rt5621_snd_controls[] = {\r
+SOC_DOUBLE("Speaker Playback Volume",  RT5621_SPK_OUT_VOL, 8, 0, 31, 1),       \r
+SOC_DOUBLE("Speaker Playback Switch",  RT5621_SPK_OUT_VOL, 15, 7, 1, 1),\r
+SOC_DOUBLE("Headphone Playback Volume", RT5621_HP_OUT_VOL, 8, 0, 31, 1),\r
+SOC_DOUBLE("Headphone Playback Switch", RT5621_HP_OUT_VOL,15, 7, 1, 1),\r
+SOC_DOUBLE("AUX Playback Volume",              RT5621_MONO_AUX_OUT_VOL, 8, 0, 31, 1),\r
+SOC_DOUBLE("AUX Playback Switch",              RT5621_MONO_AUX_OUT_VOL, 15, 7, 1, 1),\r
+SOC_DOUBLE("PCM Playback Volume",              RT5621_STEREO_DAC_VOL, 8, 0, 31, 1),\r
+SOC_DOUBLE("Line In Volume",                   RT5621_LINE_IN_VOL, 8, 0, 31, 1),\r
+SOC_SINGLE("Mic 1 Volume",                             RT5621_MIC_VOL, 8, 31, 1),\r
+SOC_SINGLE("Mic 2 Volume",                             RT5621_MIC_VOL, 0, 31, 1),\r
+SOC_ENUM("Mic 1 Boost",                                rt5621_enum[5]),\r
+SOC_ENUM("Mic 2 Boost",                                rt5621_enum[6]),\r
+SOC_ENUM_EXT("Speaker Amp Type",                       rt5621_enum[7], snd_soc_get_enum_double, rt5621_amp_sel_put),\r
+SOC_DOUBLE("AUX In Volume",                    RT5621_AUXIN_VOL, 8, 0, 31, 1),\r
+SOC_DOUBLE("Capture Volume",                   RT5621_ADC_REC_GAIN, 7, 0, 31, 0),\r
+};\r
+\r
+\r
+\r
+/* add non dapm controls */\r
+static int rt5621_add_controls(struct snd_soc_codec *codec)\r
+{\r
+       int err, i;\r
+\r
+       for (i = 0; i < ARRAY_SIZE(rt5621_snd_controls); i++) {\r
+               err = snd_ctl_add(codec->card,\r
+                               snd_soc_cnew(&rt5621_snd_controls[i],codec, NULL));\r
+               if (err < 0)\r
+                       return err;\r
+       }\r
+       return 0;\r
+}\r
+\r
+void hp_depop_mode2(struct snd_soc_codec *codec)\r
+{\r
+       rt5621_write_mask(codec, 0x3e, 0x8000, 0x8000);\r
+       rt5621_write_mask(codec, 0x04, 0x8080, 0x8080);\r
+       rt5621_write_mask(codec, 0x3a, 0x0100, 0x0100);\r
+       rt5621_write_mask(codec, 0x3c, 0x2000, 0x2000);\r
+       rt5621_write_mask(codec, 0x3e, 0x0600, 0x0600);\r
+       rt5621_write_mask(codec, 0x5e, 0x0200, 0x0200);\r
+       schedule_timeout_uninterruptible(msecs_to_jiffies(300));\r
+}\r
+\r
+void aux_depop_mode2(struct snd_soc_codec *codec)\r
+{\r
+       rt5621_write_mask(codec, 0x3e, 0x8000, 0x8000);\r
+       rt5621_write_mask(codec, 0x06, 0x8080, 0x8080);\r
+       rt5621_write_mask(codec, 0x3a, 0x0100, 0x0100);\r
+       rt5621_write_mask(codec, 0x3c, 0x2000, 0x2000);\r
+       rt5621_write_mask(codec, 0x3e, 0x6000, 0x6000);\r
+       rt5621_write_mask(codec, 0x5e, 0x0020, 0x0200);\r
+       schedule_timeout_uninterruptible(msecs_to_jiffies(300));\r
+       rt5621_write_mask(codec, 0x3a, 0x0002, 0x0002);\r
+       rt5621_write_mask(codec, 0x3a, 0x0001, 0x0001); \r
+}\r
+#if USE_DAPM_CONTROL\r
+\r
+/*\r
+ * _DAPM_ Controls\r
+ */\r
+\r
+/* We have to create a fake left and right HP mixers because\r
+ * the codec only has a single control that is shared by both channels.\r
+ * This makes it impossible to determine the audio path using the current\r
+ * register map, thus we add a new (virtual) register to help determine the\r
+ * audio route within the device.\r
+ */\r
+ static int mixer_event (struct snd_soc_dapm_widget *w, \r
+       struct snd_kcontrol *kcontrol, int event)\r
+{\r
+\r
+       u16 l, r, lineIn,mic1,mic2, aux, pcm;\r
+\r
+       l = rt5621_read(w->codec, HPL_MIXER);\r
+       r = rt5621_read(w->codec, HPR_MIXER);\r
+       lineIn = rt5621_read(w->codec, RT5621_LINE_IN_VOL);\r
+       mic2 = rt5621_read(w->codec, RT5621_MIC_ROUTING_CTRL);\r
+       aux = rt5621_read(w->codec,RT5621_AUXIN_VOL);\r
+       pcm = rt5621_read(w->codec, RT5621_STEREO_DAC_VOL);\r
+\r
+\r
+       if (event & SND_SOC_DAPM_PRE_REG)\r
+               return 0;\r
+\r
+       if (l & 0x1 || r & 0x1)\r
+               rt5621_write(w->codec, RT5621_STEREO_DAC_VOL, pcm & 0x7fff);\r
+       else\r
+               rt5621_write(w->codec, RT5621_STEREO_DAC_VOL, pcm | 0x8000);\r
+\r
+       if (l & 0x2 || r & 0x2)\r
+               rt5621_write(w->codec, RT5621_MIC_ROUTING_CTRL, mic2 & 0xff7f);\r
+       else\r
+               rt5621_write(w->codec, RT5621_MIC_ROUTING_CTRL, mic2 | 0x0080);\r
+\r
+       mic1 = rt5621_read(w->codec, RT5621_MIC_ROUTING_CTRL);\r
+       if (l & 0x4 || r & 0x4)\r
+               rt5621_write(w->codec, RT5621_MIC_ROUTING_CTRL, mic1 & 0x7fff);\r
+       else\r
+               rt5621_write(w->codec, RT5621_MIC_ROUTING_CTRL, mic1 | 0x8000);\r
+\r
+       if (l & 0x8 || r & 0x8)\r
+               rt5621_write(w->codec, RT5621_AUXIN_VOL, aux & 0x7fff);\r
+       else\r
+               rt5621_write(w->codec, RT5621_AUXIN_VOL, aux | 0x8000);\r
+\r
+       if (l & 0x10 || r & 0x10)\r
+               rt5621_write(w->codec, RT5621_LINE_IN_VOL, lineIn & 0x7fff);\r
+       else\r
+               rt5621_write(w->codec, RT5621_LINE_IN_VOL, lineIn | 0x8000);\r
+\r
+       return 0;\r
+}\r
+\r
+\r
+static int hp_event(struct snd_soc_dapm_widget *w, \r
+       struct snd_kcontrol *kcontrol, int event)\r
+{\r
+       struct snd_soc_codec *codec = w->codec;\r
+       unsigned int reg = rt5621_read(codec, MISC_FUNC_REG);\r
+       \r
+       if (((reg & 0x03) != 0x00) && ((reg & 0x03) != 0x03))\r
+               return 0;\r
+       \r
+       switch (event)\r
+       {\r
+               case SND_SOC_DAPM_POST_PMU:\r
+                       hp_depop_mode2(codec);\r
+                       rt5621_write_mask(codec, 0x04, 0x0000, 0x8080);\r
+                       rt5621_write_mask(codec, 0x3a, 0x0020, 0x0020);\r
+                       break;\r
+               case SND_SOC_DAPM_POST_PMD:\r
+                       rt5621_write_mask(codec, 0x04, 0x8080, 0x8080);\r
+                       rt5621_write_mask(codec, 0x3a, 0x0000, 0x0010);\r
+                       rt5621_write_mask(codec, 0x3a, 0x0000, 0x0020);\r
+                       rt5621_write_mask(codec, 0x3e, 0x0000, 0x0600);\r
+                       break;  \r
+       }\r
+       return 0;\r
+}\r
+\r
+static int aux_event(struct snd_soc_dapm_widget *w, \r
+       struct snd_kcontrol *kcontrol, int event)\r
+{\r
+       struct snd_soc_codec *codec = w->codec;\r
+       unsigned int reg = rt5621_read(codec, MISC_FUNC_REG);\r
+       \r
+       if (((reg & 0x0c) != 0x00) && ((reg & 0x0c) != 0x0c))\r
+               return 0;\r
+       \r
+       switch (event)\r
+       {\r
+               case SND_SOC_DAPM_POST_PMU:\r
+                       aux_depop_mode2(codec);\r
+                       rt5621_write_mask(codec, 0x06, 0x0000, 0x8080);\r
+                       break;\r
+               case SND_SOC_DAPM_POST_PMD:\r
+                       rt5621_write_mask(codec, 0x06, 0x8080, 0x8080);\r
+                       rt5621_write_mask(codec, 0x3a, 0x0000, 0x0001);\r
+                       rt5621_write_mask(codec, 0x3a, 0x0000, 0x0002);\r
+                       rt5621_write_mask(codec, 0x3e, 0x0000, 0x6000);         \r
+                       break;\r
+       }\r
+       return 0;\r
+}\r
+\r
+/* Left Headphone Mixers */\r
+static const struct snd_kcontrol_new rt5621_hpl_mixer_controls[] = {\r
+SOC_DAPM_SINGLE("LineIn Playback Switch", HPL_MIXER, 4, 1, 0),\r
+SOC_DAPM_SINGLE("AUXIN Playback Switch", HPL_MIXER, 3, 1, 0),\r
+SOC_DAPM_SINGLE("Mic1 Playback Switch", HPL_MIXER, 2, 1, 0),\r
+SOC_DAPM_SINGLE("Mic2 Playback Switch", HPL_MIXER, 1, 1, 0),\r
+SOC_DAPM_SINGLE("PCM Playback Switch", HPL_MIXER, 0, 1, 0),\r
+SOC_DAPM_SINGLE("RecordL Playback Switch", RT5621_ADC_REC_GAIN, 15, 1,1),\r
+};\r
+\r
+/* Right Headphone Mixers */\r
+static const struct snd_kcontrol_new rt5621_hpr_mixer_controls[] = {\r
+SOC_DAPM_SINGLE("LineIn Playback Switch", HPR_MIXER, 4, 1, 0),\r
+SOC_DAPM_SINGLE("AUXIN Playback Switch", HPR_MIXER, 3, 1, 0),\r
+SOC_DAPM_SINGLE("Mic1 Playback Switch", HPR_MIXER, 2, 1, 0),\r
+SOC_DAPM_SINGLE("Mic2 Playback Switch", HPR_MIXER, 1, 1, 0),\r
+SOC_DAPM_SINGLE("PCM Playback Switch", HPR_MIXER, 0, 1, 0),\r
+SOC_DAPM_SINGLE("RecordR Playback Switch", RT5621_ADC_REC_GAIN, 14, 1,1),\r
+};\r
+\r
+//Left Record Mixer\r
+static const struct snd_kcontrol_new rt5621_captureL_mixer_controls[] = {\r
+SOC_DAPM_SINGLE("Mic1 Capture Switch", RT5621_ADC_REC_MIXER, 14, 1, 1),\r
+SOC_DAPM_SINGLE("Mic2 Capture Switch", RT5621_ADC_REC_MIXER, 13, 1, 1),\r
+SOC_DAPM_SINGLE("LineInL Capture Switch",RT5621_ADC_REC_MIXER,12, 1, 1),\r
+SOC_DAPM_SINGLE("AUXIN Capture Switch", RT5621_ADC_REC_MIXER, 11, 1, 1),\r
+SOC_DAPM_SINGLE("HPMixerL Capture Switch", RT5621_ADC_REC_MIXER,10, 1, 1),\r
+SOC_DAPM_SINGLE("SPKMixer Capture Switch",RT5621_ADC_REC_MIXER,9, 1, 1),\r
+SOC_DAPM_SINGLE("MonoMixer Capture Switch",RT5621_ADC_REC_MIXER,8, 1, 1),\r
+};\r
+\r
+\r
+//Right Record Mixer\r
+static const struct snd_kcontrol_new rt5621_captureR_mixer_controls[] = {\r
+SOC_DAPM_SINGLE("Mic1 Capture Switch", RT5621_ADC_REC_MIXER, 6, 1, 1),\r
+SOC_DAPM_SINGLE("Mic2 Capture Switch", RT5621_ADC_REC_MIXER, 5, 1, 1),\r
+SOC_DAPM_SINGLE("LineInR Capture Switch",RT5621_ADC_REC_MIXER,4, 1, 1),\r
+SOC_DAPM_SINGLE("AUXIN Capture Switch", RT5621_ADC_REC_MIXER, 3, 1, 1),\r
+SOC_DAPM_SINGLE("HPMixerR Capture Switch", RT5621_ADC_REC_MIXER,2, 1, 1),\r
+SOC_DAPM_SINGLE("SPKMixer Capture Switch",RT5621_ADC_REC_MIXER,1, 1, 1),\r
+SOC_DAPM_SINGLE("MonoMixer Capture Switch",RT5621_ADC_REC_MIXER,0, 1, 1),\r
+};\r
+\r
+/* Speaker Mixer */\r
+static const struct snd_kcontrol_new rt5621_speaker_mixer_controls[] = {\r
+SOC_DAPM_SINGLE("LineIn Playback Switch", RT5621_LINE_IN_VOL, 14, 1, 1),\r
+SOC_DAPM_SINGLE("AUXIN Playback Switch", RT5621_AUXIN_VOL, 14, 1, 1),\r
+SOC_DAPM_SINGLE("Mic1 Playback Switch", RT5621_MIC_ROUTING_CTRL, 14, 1, 1),\r
+SOC_DAPM_SINGLE("Mic2 Playback Switch", RT5621_MIC_ROUTING_CTRL, 6, 1, 1),\r
+SOC_DAPM_SINGLE("PCM Playback Switch", RT5621_STEREO_DAC_VOL, 14, 1, 1),\r
+};\r
+\r
+\r
+/* Mono Mixer */\r
+static const struct snd_kcontrol_new rt5621_mono_mixer_controls[] = {\r
+SOC_DAPM_SINGLE("LineIn Playback Switch", RT5621_LINE_IN_VOL, 13, 1, 1),\r
+SOC_DAPM_SINGLE("Mic1 Playback Switch", RT5621_MIC_ROUTING_CTRL, 13, 1, 1),\r
+SOC_DAPM_SINGLE("Mic2 Playback Switch", RT5621_MIC_ROUTING_CTRL, 5, 1, 1),\r
+SOC_DAPM_SINGLE("AUXIN Playback Switch", RT5621_AUXIN_VOL, 13, 1, 1),\r
+SOC_DAPM_SINGLE("PCM Playback Switch", RT5621_STEREO_DAC_VOL, 13, 1, 1),\r
+SOC_DAPM_SINGLE("RecordL Playback Switch", RT5621_ADC_REC_GAIN, 13, 1,1),\r
+SOC_DAPM_SINGLE("RecordR Playback Switch", RT5621_ADC_REC_GAIN, 12, 1,1),\r
+};\r
+\r
+/* mono output mux */\r
+static const struct snd_kcontrol_new rt5621_mono_mux_controls =\r
+SOC_DAPM_ENUM("Route", rt5621_enum[4]);\r
+\r
+/* speaker left output mux */\r
+static const struct snd_kcontrol_new rt5621_hp_spk_mux_controls =\r
+SOC_DAPM_ENUM("Route", rt5621_enum[1]);\r
+\r
+\r
+/* headphone left output mux */\r
+static const struct snd_kcontrol_new rt5621_hpl_out_mux_controls =\r
+SOC_DAPM_ENUM("Route", rt5621_enum[2]);\r
+\r
+/* headphone right output mux */\r
+static const struct snd_kcontrol_new rt5621_hpr_out_mux_controls =\r
+SOC_DAPM_ENUM("Route", rt5621_enum[3]);\r
+\r
+static const struct snd_soc_dapm_widget rt5621_dapm_widgets[] = {\r
+SND_SOC_DAPM_MUX("Mono Out Mux", SND_SOC_NOPM, 0, 0,\r
+       &rt5621_mono_mux_controls),\r
+SND_SOC_DAPM_MUX("Speaker Out Mux", SND_SOC_NOPM, 0, 0,\r
+       &rt5621_hp_spk_mux_controls),\r
+SND_SOC_DAPM_MUX("Left Headphone Out Mux", SND_SOC_NOPM, 0, 0,\r
+       &rt5621_hpl_out_mux_controls),\r
+SND_SOC_DAPM_MUX("Right Headphone Out Mux", SND_SOC_NOPM, 0, 0,\r
+       &rt5621_hpr_out_mux_controls),\r
+       \r
+SND_SOC_DAPM_MIXER_E("Left HP Mixer",RT5621_PWR_MANAG_ADD2, 5, 0,\r
+       &rt5621_hpl_mixer_controls[0], ARRAY_SIZE(rt5621_hpl_mixer_controls),\r
+       mixer_event, SND_SOC_DAPM_POST_REG),    \r
+SND_SOC_DAPM_MIXER_E("Right HP Mixer",RT5621_PWR_MANAG_ADD2, 4, 0,\r
+       &rt5621_hpr_mixer_controls[0], ARRAY_SIZE(rt5621_hpr_mixer_controls),\r
+       mixer_event, SND_SOC_DAPM_POST_REG),    \r
+SND_SOC_DAPM_MIXER("Mono Mixer", RT5621_PWR_MANAG_ADD2, 2, 0,\r
+       &rt5621_mono_mixer_controls[0], ARRAY_SIZE(rt5621_mono_mixer_controls)),\r
+       \r
+SND_SOC_DAPM_MIXER("Speaker Mixer", RT5621_PWR_MANAG_ADD2,3,0,\r
+       &rt5621_speaker_mixer_controls[0], ARRAY_SIZE(rt5621_speaker_mixer_controls)),  \r
+       \r
+SND_SOC_DAPM_MIXER("Left Record Mixer", RT5621_PWR_MANAG_ADD2,1,0,\r
+       &rt5621_captureL_mixer_controls[0],     ARRAY_SIZE(rt5621_captureL_mixer_controls)),    \r
+SND_SOC_DAPM_MIXER("Right Record Mixer", RT5621_PWR_MANAG_ADD2,0,0,\r
+       &rt5621_captureR_mixer_controls[0],     ARRAY_SIZE(rt5621_captureR_mixer_controls)),    \r
+       \r
+SND_SOC_DAPM_DAC("Left DAC", "Left HiFi Playback", RT5621_PWR_MANAG_ADD2,9, 0),\r
+SND_SOC_DAPM_DAC("Right DAC", "Right HiFi Playback", RT5621_PWR_MANAG_ADD2, 8, 0),\r
+\r
+SND_SOC_DAPM_MIXER("IIS Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),\r
+SND_SOC_DAPM_MIXER("HP Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),\r
+\r
+SND_SOC_DAPM_MIXER("Line Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),\r
+SND_SOC_DAPM_MIXER("AUXIN Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),\r
+\r
+SND_SOC_DAPM_ADC("Left ADC", "Left HiFi Capture", RT5621_PWR_MANAG_ADD2, 7, 0),\r
+SND_SOC_DAPM_ADC("Right ADC", "Right HiFi Capture", RT5621_PWR_MANAG_ADD2, 6, 0),\r
+\r
+SND_SOC_DAPM_PGA_E("Left Headphone", MISC_FUNC_REG, 0, 0, NULL, 0, \r
+       hp_event, SND_SOC_DAPM_POST_PMD | SND_SOC_DAPM_POST_PMU),\r
+SND_SOC_DAPM_PGA_E("Right Headphone", MISC_FUNC_REG, 1, 0, NULL, 0, \r
+       hp_event, SND_SOC_DAPM_POST_PMD | SND_SOC_DAPM_POST_PMU),\r
+\r
+SND_SOC_DAPM_PGA("Speaker PGA", RT5621_PWR_MANAG_ADD3, 12, 0, NULL, 0),\r
+\r
+SND_SOC_DAPM_PGA_E("AUXL Out", MISC_FUNC_REG, 2, 0, NULL, 0,\r
+       aux_event, SND_SOC_DAPM_POST_PMD | SND_SOC_DAPM_POST_PMU),\r
+SND_SOC_DAPM_PGA_E("AUXR Out", MISC_FUNC_REG, 3, 0, NULL, 0,\r
+       aux_event, SND_SOC_DAPM_POST_PMD | SND_SOC_DAPM_POST_PMU),\r
+\r
+SND_SOC_DAPM_PGA("Left Line In", RT5621_PWR_MANAG_ADD3, 7, 0, NULL, 0),\r
+SND_SOC_DAPM_PGA("Right Line In", RT5621_PWR_MANAG_ADD3, 6, 0, NULL, 0),\r
+SND_SOC_DAPM_PGA("Left AUX In", RT5621_PWR_MANAG_ADD3, 5, 0, NULL, 0),\r
+SND_SOC_DAPM_PGA("Right AUX In", RT5621_PWR_MANAG_ADD3, 4, 0, NULL, 0),\r
+\r
+SND_SOC_DAPM_PGA("Mic 1 PGA", RT5621_PWR_MANAG_ADD3, 3, 0, NULL, 0),\r
+SND_SOC_DAPM_PGA("Mic 2 PGA", RT5621_PWR_MANAG_ADD3, 2, 0, NULL, 0),\r
+SND_SOC_DAPM_PGA("Mic 1 Pre Amp", RT5621_PWR_MANAG_ADD3, 1, 0, NULL, 0),\r
+SND_SOC_DAPM_PGA("Mic 2 Pre Amp", RT5621_PWR_MANAG_ADD3, 0, 0, NULL, 0),\r
+\r
+SND_SOC_DAPM_MICBIAS("Mic Bias1", RT5621_PWR_MANAG_ADD1, 11, 0),\r
+\r
+SND_SOC_DAPM_OUTPUT("AUXL"),\r
+SND_SOC_DAPM_OUTPUT("AUXR"),\r
+SND_SOC_DAPM_OUTPUT("HPL"),\r
+SND_SOC_DAPM_OUTPUT("HPR"),\r
+SND_SOC_DAPM_OUTPUT("SPK"),\r
+\r
+SND_SOC_DAPM_INPUT("LINEL"),\r
+SND_SOC_DAPM_INPUT("LINER"),\r
+SND_SOC_DAPM_INPUT("AUXINL"),\r
+SND_SOC_DAPM_INPUT("AUXINR"),\r
+SND_SOC_DAPM_INPUT("MIC1"),\r
+SND_SOC_DAPM_INPUT("MIC2"),\r
+SND_SOC_DAPM_VMID("VMID"),\r
+};\r
+\r
+static const struct snd_soc_dapm_route audio_map[] = {\r
+       /* left HP mixer */\r
+       {"Left HP Mixer"        ,       "LineIn Playback Switch"                ,       "Left Line In"},\r
+       {"Left HP Mixer"        ,       "AUXIN Playback Switch"         ,       "Left AUX In"},\r
+       {"Left HP Mixer"        ,       "Mic1 Playback Switch"                  ,       "Mic 1 PGA"},\r
+       {"Left HP Mixer"        ,       "Mic2 Playback Switch"                  ,       "Mic 2 PGA"},\r
+       {"Left HP Mixer"        ,       "PCM Playback Switch"                   ,       "Left DAC"},\r
+       {"Left HP Mixer"        ,       "RecordL Playback Switch"               ,       "Left Record Mixer"},\r
+       \r
+       /* right HP mixer */\r
+       {"Right HP Mixer"       ,       "LineIn Playback Switch"                ,       "Right Line In"},\r
+       {"Right HP Mixer"       ,       "AUXIN Playback Switch"         ,       "Right AUX In"},\r
+       {"Right HP Mixer"       ,       "Mic1 Playback Switch"                  ,       "Mic 1 PGA"},\r
+       {"Right HP Mixer"       ,       "Mic2 Playback Switch"                  ,       "Mic 2 PGA"},\r
+       {"Right HP Mixer"       ,       "PCM Playback Switch"                   ,       "Right DAC"},\r
+       {"Right HP Mixer"       ,       "RecordR Playback Switch"               ,       "Right Record Mixer"},\r
+       \r
+       /* virtual mixer - mixes left & right channels for spk and mono */\r
+       {"IIS Mixer"            ,       NULL                                            ,       "Left DAC"},\r
+       {"IIS Mixer"            ,       NULL                                            ,       "Right DAC"},\r
+       {"Line Mixer"           ,       NULL                                            ,       "Right Line In"},\r
+       {"Line Mixer"           ,       NULL                                            ,       "Left Line In"},\r
+       {"AUXIN Mixer"  ,       NULL                                            ,       "Left AUX In"},\r
+       {"AUXIN Mixer"  ,       NULL                                            ,       "Right AUX In"},\r
+       {"HP Mixer"             ,       NULL                                            ,       "Left HP Mixer"},\r
+       {"HP Mixer"             ,       NULL                                            ,       "Right HP Mixer"},\r
+       \r
+       /* speaker mixer */\r
+       {"Speaker Mixer"        ,       "LineIn Playback Switch"                ,       "Line Mixer"},\r
+       {"Speaker Mixer"        ,       "AUXIN Playback Switch"         ,       "AUXIN Mixer"},\r
+       {"Speaker Mixer"        ,       "Mic1 Playback Switch"                  ,       "Mic 1 PGA"},\r
+       {"Speaker Mixer"        ,       "Mic2 Playback Switch"                  ,       "Mic 2 PGA"},\r
+       {"Speaker Mixer"        ,       "PCM Playback Switch"                   ,       "IIS Mixer"},\r
+\r
+\r
+       /* mono mixer */\r
+       {"Mono Mixer"           ,       "LineIn Playback Switch"                ,       "Line Mixer"},\r
+       {"Mono Mixer"           ,       "Mic1 Playback Switch"                  ,       "Mic 1 PGA"},\r
+       {"Mono Mixer"           ,       "Mic2 Playback Switch"                  ,       "Mic 2 PGA"},\r
+       {"Mono Mixer"           ,       "PCM Playback Switch"                   ,       "IIS Mixer"},\r
+       {"Mono Mixer"           ,       "AUXIN Playback Switch"         ,       "AUXIN Mixer"},\r
+       {"Mono Mixer"           ,       "RecordL Playback Switch"               ,       "Left Record Mixer"},\r
+       {"Mono Mixer"           ,       "RecordR Playback Switch"               ,       "Right Record Mixer"},\r
+       \r
+       /*Left record mixer */\r
+       {"Left Record Mixer"    ,       "Mic1 Capture Switch"           ,       "Mic 1 Pre Amp"},\r
+       {"Left Record Mixer"    ,       "Mic2 Capture Switch"           ,       "Mic 2 Pre Amp"},\r
+       {"Left Record Mixer"    ,       "LineInL Capture Switch"        ,       "LINEL"},\r
+       {"Left Record Mixer"    ,       "AUXIN Capture Switch"          ,       "AUXINL"},\r
+       {"Left Record Mixer"    ,       "HPMixerL Capture Switch"       ,       "Left HP Mixer"},\r
+       {"Left Record Mixer"    ,       "SPKMixer Capture Switch"       ,       "Speaker Mixer"},\r
+       {"Left Record Mixer"    ,       "MonoMixer Capture Switch"      ,       "Mono Mixer"},\r
+       \r
+       /*Right record mixer */\r
+       {"Right Record Mixer"   ,       "Mic1 Capture Switch"           ,       "Mic 1 Pre Amp"},\r
+       {"Right Record Mixer"   ,        "Mic2 Capture Switch"          ,       "Mic 2 Pre Amp"},\r
+       {"Right Record Mixer"   ,       "LineInR Capture Switch"        ,       "LINER"},\r
+       {"Right Record Mixer"   ,       "AUXIN Capture Switch"          ,       "AUXINR"},\r
+       {"Right Record Mixer"   ,       "HPMixerR Capture Switch"       ,       "Right HP Mixer"},\r
+       {"Right Record Mixer"   ,       "SPKMixer Capture Switch"       ,       "Speaker Mixer"},\r
+       {"Right Record Mixer"   ,        "MonoMixer Capture Switch"     ,       "Mono Mixer"},  \r
+\r
+       /* headphone left mux */\r
+       {"Left Headphone Out Mux"       ,        "HPL mixer"                    ,        "Left HP Mixer"},\r
+\r
+       /* headphone right mux */\r
+       {"Right Headphone Out Mux", "HPR mixer", "Right HP Mixer"},\r
+\r
+       /* speaker mux */\r
+       {"Speaker Out Mux", "HP mixer", "HP Mixer"},\r
+       {"Speaker Out Mux", "SPK mixer", "Speaker Mixer"},\r
+       {"Speaker Out Mux", "Mono Mixer", "Mono Mixer"},\r
+\r
+       /* mono mux */\r
+       {"Mono Out Mux", "HP mixer", "HP Mixer"},\r
+       {"Mono Out Mux", "SPK mixer", "Speaker Mixer"},\r
+       {"Mono Out Mux", "Mono Mixer", "Mono Mixer"},\r
+       \r
+       /* output pga */\r
+       {"HPL", NULL, "Left Headphone"},\r
+       {"Left Headphone", NULL, "Left Headphone Out Mux"},\r
+\r
+       {"HPR", NULL, "Right Headphone"},\r
+       {"Right Headphone", NULL, "Right Headphone Out Mux"},\r
+\r
+       {"SPK", NULL, "Speaker PGA"},\r
+       {"Speaker PGA", NULL, "Speaker Out Mux"},\r
+\r
+       {"AUXL", NULL, "AUXL Out"},\r
+       {"AUXL Out", NULL, "Mono Out Mux"},\r
+\r
+       {"AUXR", NULL, "AUXR Out"},\r
+       {"AUXR Out", NULL, "Mono Out Mux"},\r
+\r
+       /* input pga */\r
+       {"Left Line In", NULL, "LINEL"},\r
+       {"Right Line In", NULL, "LINER"},\r
+       \r
+       {"Left AUX In", NULL, "AUXINL"},\r
+       {"Right AUX In", NULL, "AUXINR"},\r
+       \r
+       {"Mic 1 Pre Amp", NULL, "MIC1"},\r
+       {"Mic 2 Pre Amp", NULL, "MIC2"},        \r
+       {"Mic 1 PGA", NULL, "Mic 1 Pre Amp"},\r
+       {"Mic 2 PGA", NULL, "Mic 2 Pre Amp"},\r
+\r
+       /* left ADC */\r
+       {"Left ADC", NULL, "Left Record Mixer"},\r
+\r
+       /* right ADC */\r
+       {"Right ADC", NULL, "Right Record Mixer"},\r
+       \r
+};\r
+\r
+static int rt5621_add_widgets(struct snd_soc_codec *codec)\r
+{\r
+       snd_soc_dapm_new_controls(codec, rt5621_dapm_widgets,\r
+                               ARRAY_SIZE(rt5621_dapm_widgets));\r
+       snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));\r
+       snd_soc_dapm_new_widgets(codec);\r
+\r
+       return 0;\r
+}\r
+\r
+#else\r
+\r
+static int rt5621_pcm_hw_prepare(struct snd_pcm_substream *substream,\r
+               struct snd_soc_dai *codec_dai)\r
+{\r
+\r
+       struct snd_soc_codec *codec = codec_dai->codec;\r
+       int stream = substream->stream;\r
+\r
+       switch (stream)\r
+       {\r
+               case SNDRV_PCM_STREAM_PLAYBACK:\r
+\r
+                       rt5621_ChangeCodecPowerStatus(codec,POWER_STATE_D1_PLAYBACK);   //power on dac to hp and speaker out\r
+                                               \r
+                       rt5621_AudioOutEnable(codec,RT_WAVOUT_SPK,0);   //unmute speaker out\r
+                       \r
+                       rt5621_AudioOutEnable(codec,RT_WAVOUT_HP,0);    //unmute hp out\r
+\r
+                       break;\r
+               case SNDRV_PCM_STREAM_CAPTURE:\r
+\r
+                       rt5621_ChangeCodecPowerStatus(codec,POWER_STATE_D1_RECORD);     //power on input to adc\r
+\r
+                       Enable_ADC_Input_Source(codec,RT_WAVIN_L_MIC1|RT_WAVIN_R_MIC1,1);       //enable record source from mic1\r
+\r
+                       break;                  \r
+       }\r
+       \r
+       return 0;\r
+}\r
+\r
+#endif\r
+/* PLL divisors */\r
+struct _pll_div {\r
+       u32 pll_in;\r
+       u32 pll_out;\r
+       u16 regvalue;\r
+};\r
+\r
+static const struct _pll_div codec_pll_div[] = {\r
+       \r
+       {  2048000,  8192000,   0x0ea0},                \r
+       {  3686400,  8192000,   0x4e27},        \r
+       { 12000000,  8192000,   0x456b},   \r
+       { 13000000,  8192000,   0x495f},\r
+       { 13100000,      8192000,       0x0320},        \r
+       {  2048000,  11289600,  0xf637},\r
+       {  3686400,  11289600,  0x2f22},        \r
+       { 12000000,  11289600,  0x3e2f},   \r
+       { 13000000,  11289600,  0x4d5b},\r
+       { 13100000,      11289600,      0x363b},        \r
+       {  2048000,  16384000,  0x1ea0},\r
+       {  3686400,  16384000,  0x9e27},        \r
+       { 12000000,  16384000,  0x452b},   \r
+       { 13000000,  16384000,  0x542f},\r
+       { 13100000,      16384000,      0x03a0},        \r
+       {  2048000,  16934400,  0xe625},\r
+       {  3686400,  16934400,  0x9126},        \r
+       { 12000000,  16934400,  0x4d2c},   \r
+       { 13000000,  16934400,  0x742f},\r
+       { 13100000,      16934400,      0x3c27},                        \r
+       {  2048000,  22579200,  0x2aa0},\r
+       {  3686400,  22579200,  0x2f20},        \r
+       { 12000000,  22579200,  0x7e2f},   \r
+       { 13000000,  22579200,  0x742f},\r
+       { 13100000,      22579200,      0x3c27},                \r
+       {  2048000,  24576000,  0x2ea0},\r
+       {  3686400,  24576000,  0xee27},        \r
+       { 12000000,  24576000,  0x2915},   \r
+       { 13000000,  24576000,  0x772e},\r
+       { 13100000,      24576000,      0x0d20},        \r
+};\r
+\r
+static const struct _pll_div codec_bclk_pll_div[] = {\r
+\r
+       {  1536000,      24576000,      0x3ea0},        \r
+       {  3072000,      24576000,      0x1ea0},\r
+       {  512000,       24576000,  0x8e90},\r
+       {  256000,   24576000,  0xbe80},\r
+               {  2822400,      11289600,      0x1ee0},        //flove040711\r
+       {  3072000,      12288000,      0x1ee0},        //flove040711   \r
+};\r
+\r
+\r
+static int rt5621_set_dai_pll(struct snd_soc_dai *codec_dai,\r
+               int pll_id, unsigned int freq_in, unsigned int freq_out)\r
+{\r
+       int i;\r
+       int ret = -EINVAL;\r
+       struct snd_soc_codec *codec = codec_dai->codec;\r
+\r
+       if (pll_id < RT5621_PLL_FR_MCLK || pll_id > RT5621_PLL_FR_BCLK)\r
+               return -EINVAL;\r
+\r
+       //rt5621_write_mask(codec,RT5621_PWR_MANAG_ADD2, 0x0000,0x1000);        //disable PLL power     \r
+       \r
+       if (!freq_in || !freq_out) {\r
+\r
+               return 0;\r
+       }               \r
+\r
+       if (RT5621_PLL_FR_MCLK == pll_id) {\r
+       for (i = 0; i < ARRAY_SIZE(codec_pll_div); i++) {\r
+                       \r
+               if (codec_pll_div[i].pll_in == freq_in && codec_pll_div[i].pll_out == freq_out)\r
+                       {\r
+                               rt5621_write_mask(codec, RT5621_GLOBAL_CLK_CTRL_REG, 0x0000, 0x4000);                           \r
+                               rt5621_write(codec,RT5621_PLL_CTRL,codec_pll_div[i].regvalue);//set PLL parameter       \r
+                               rt5621_write_mask(codec,RT5621_PWR_MANAG_ADD2, 0x1000,0x1000);  //enable PLL power      \r
+                               ret = 0;\r
+                       }\r
+       }\r
+       }\r
+       else if (RT5621_PLL_FR_BCLK == pll_id)\r
+       {\r
+               for (i = 0; i < ARRAY_SIZE(codec_bclk_pll_div); i++)\r
+               {\r
+                       if ((freq_in == codec_bclk_pll_div[i].pll_in) && (freq_out == codec_bclk_pll_div[i].pll_out))\r
+                       {\r
+                               rt5621_write_mask(codec, RT5621_GLOBAL_CLK_CTRL_REG, 0x4000, 0x4000);\r
+                               rt5621_write(codec,RT5621_PLL_CTRL,codec_bclk_pll_div[i].regvalue);//set PLL parameter \r
+                               rt5621_write_mask(codec,RT5621_PWR_MANAG_ADD2, 0x1000,0x1000);  //enable PLL power      \r
+                               ret = 0;\r
+                       }\r
+               }\r
+       }\r
+\r
+       rt5621_write_mask(codec,RT5621_GLOBAL_CLK_CTRL_REG,0x8000,0x8000);//Codec sys-clock from PLL    \r
+       return ret;\r
+}\r
+\r
+\r
+struct _coeff_div {\r
+       u32 mclk;\r
+       u32 rate;\r
+       u16 fs;\r
+       u16 regvalue;\r
+};\r
+\r
+/* codec hifi mclk (after PLL) clock divider coefficients */\r
+static const struct _coeff_div coeff_div[] = {\r
+       /* 8k */\r
+       { 8192000,  8000, 256*4, 0x2a2d},\r
+       {12288000,  8000, 384*4, 0x2c2f},\r
+\r
+       /* 11.025k */\r
+       {11289600, 11025, 256*4, 0x2a2d},\r
+       {16934400, 11025, 384*4, 0x2c2f},\r
+\r
+       /* 16k */\r
+       {12288000, 16000, 384*2, 0x1c2f},\r
+       {16384000, 16000, 256*4, 0x2a2d},\r
+       {24576000, 16000, 384*4, 0x2c2f},\r
+\r
+       /* 22.05k */    \r
+       {11289600, 22050, 256*2, 0x1a2d},\r
+       {16934400, 22050, 384*2, 0x1c2f},\r
+\r
+       /* 32k */\r
+       {12288000, 32000, 384  , 0x0c2f},\r
+       {16384000, 32000, 256*2, 0x1a2d},\r
+       {24576000, 32000, 384*2, 0x1c2f},\r
+\r
+       /* 44.1k */\r
+       {11289600, 44100, 256*1, 0x0a2d},\r
+       {22579200, 44100, 256*2, 0x1a2d},\r
+       {45158400, 44100, 256*4, 0x2a2d},       \r
+\r
+       /* 48k */\r
+       {12288000, 48000, 256*1, 0x0a2d},\r
+       {24576000, 48000, 256*2, 0x1a2d},\r
+       {49152000, 48000, 256*4, 0x2a2d},\r
+\r
+};\r
+\r
+\r
+\r
+static int get_coeff(int mclk, int rate)\r
+{\r
+       int i;\r
+       \r
+       printk("get_coeff mclk=%d,rate=%d\n",mclk,rate);\r
+\r
+       for (i = 0; i < ARRAY_SIZE(coeff_div); i++) {\r
+               if (coeff_div[i].rate == rate && coeff_div[i].mclk == mclk)\r
+                       return i;\r
+       }\r
+       return -EINVAL;\r
+}\r
+\r
+\r
+\r
+\r
+/*\r
+ * Clock after PLL and dividers\r
+ */\r
+ /*in this driver, you have to set sysclk to be 24576000,\r
+ * but you don't need to give a clk to be 24576000, our \r
+ * internal pll will generate this clock! so it won't make\r
+ * you any difficult.\r
+ */\r
+static int rt5621_set_dai_sysclk(struct snd_soc_dai *codec_dai,\r
+               int clk_id, unsigned int freq, int dir)\r
+{\r
+       struct snd_soc_codec *codec = codec_dai->codec;\r
+       struct rt5621_priv *rt5621 = codec->private_data;\r
+\r
+       switch (freq) {\r
+       case 24576000:\r
+               rt5621->sysclk = freq;\r
+               return 0;\r
+       }\r
+       return 0;\r
+}\r
+\r
+\r
+static int rt5621_set_dai_fmt(struct snd_soc_dai *codec_dai,\r
+               unsigned int fmt)\r
+{\r
+       struct snd_soc_codec *codec = codec_dai->codec;\r
+       u16 iface = 0;\r
+\r
+       /* set master/slave audio interface */\r
+       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {\r
+       case SND_SOC_DAIFMT_CBM_CFM:\r
+               iface = 0x0000;\r
+               break;\r
+       case SND_SOC_DAIFMT_CBS_CFS:\r
+               iface = 0x8000;\r
+               break;\r
+       default:\r
+               return -EINVAL;\r
+       }\r
+\r
+       /* interface format */\r
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {\r
+       case SND_SOC_DAIFMT_I2S:\r
+               iface |= 0x0000;\r
+               break;\r
+       case SND_SOC_DAIFMT_RIGHT_J:\r
+               iface |= 0x0001;\r
+               break;\r
+       case SND_SOC_DAIFMT_LEFT_J:\r
+               iface |= 0x0002;\r
+               break;\r
+       case SND_SOC_DAIFMT_DSP_A:\r
+               iface |= 0x0003;\r
+               break;\r
+       case SND_SOC_DAIFMT_DSP_B:\r
+               iface |= 0x4003;\r
+               break;\r
+       default:\r
+               return -EINVAL;\r
+       }\r
+\r
+       /* clock inversion */\r
+       switch (fmt & SND_SOC_DAIFMT_INV_MASK) {\r
+       case SND_SOC_DAIFMT_NB_NF:\r
+               iface |= 0x0000;\r
+               break;\r
+       case SND_SOC_DAIFMT_IB_NF:\r
+               iface |= 0x0100;\r
+               break;\r
+       default:\r
+               return -EINVAL;\r
+       }\r
+\r
+       rt5621_write(codec,RT5621_AUDIO_INTERFACE,iface);\r
+       return 0;\r
+}\r
+\r
+\r
+static int rt5621_pcm_hw_params(struct snd_pcm_substream *substream,\r
+       struct snd_pcm_hw_params *params,\r
+       struct snd_soc_dai *codec_dai)\r
+{\r
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;\r
+       struct snd_soc_device *socdev = rtd->socdev;\r
+       struct snd_soc_codec *codec = socdev ->card->codec;\r
+       struct rt5621_priv *rt5621 = codec->private_data;\r
+       u16 iface=rt5621_read(codec,RT5621_AUDIO_INTERFACE)&0xfff3;\r
+       int coeff = get_coeff(rt5621->sysclk, params_rate(params));\r
+\r
+       printk("rt5621_pcm_hw_params\n");\r
+       if (coeff < 0)\r
+               coeff = get_coeff(24576000, params_rate(params));         /*if not set sysclk, default to be 24.576MHz*/\r
+\r
+       /* bit size */\r
+       switch (params_format(params)) {\r
+       case SNDRV_PCM_FORMAT_S16_LE:\r
+               iface |= 0x0000;\r
+               break;\r
+       case SNDRV_PCM_FORMAT_S20_3LE:\r
+               iface |= 0x0004;\r
+               break;\r
+       case SNDRV_PCM_FORMAT_S24_LE:\r
+               iface |= 0x0008;\r
+               break;\r
+       case SNDRV_PCM_FORMAT_S32_LE:\r
+               iface |= 0x000c;\r
+               break;\r
+       }\r
+\r
+       /* set iface & srate */\r
+       rt5621_write(codec, RT5621_AUDIO_INTERFACE, iface);\r
+\r
+       if (coeff >= 0)\r
+               rt5621_write(codec, RT5621_STEREO_AD_DA_CLK_CTRL, coeff_div[coeff].regvalue);\r
+//     else\r
+//     {\r
+//             printk(KERN_ERR "cant find matched sysclk and rate config\n");\r
+//             return -EINVAL;\r
+               \r
+//     }\r
+       return 0;\r
+}\r
+\r
+#if !USE_DAPM_CONTROL\r
+static int rt5621_set_bias_level(struct snd_soc_codec *codec, \r
+                       enum snd_soc_bias_level level)\r
+{\r
+       switch (level) {\r
+               case SND_SOC_BIAS_ON:\r
+                       break;\r
+               case SND_SOC_BIAS_PREPARE:\r
+                       break;\r
+               case SND_SOC_BIAS_STANDBY:\r
+                       break;\r
+               case SND_SOC_BIAS_OFF:\r
+\r
+                       rt5621_write_mask(codec, 0x02, 0x8080, 0x8080);\r
+                       rt5621_write_mask(codec, 0x04, 0x8080, 0x8080);\r
+                       rt5621_write(codec, 0x3e, 0x0000);\r
+                       rt5621_write(codec, 0x3c, 0x0000);\r
+                       rt5621_write(codec, 0x3a, 0x0000);\r
+                       break;          \r
+       }\r
+       codec->bias_level = level;\r
+       return 0;\r
+}\r
+#else\r
+static int rt5621_set_bias_level(struct snd_soc_codec *codec, \r
+                       enum snd_soc_bias_level level)\r
+{\r
+       switch (level) {\r
+               case SND_SOC_BIAS_ON:\r
+                       break;\r
+               case SND_SOC_BIAS_PREPARE:\r
+                       break;\r
+               case SND_SOC_BIAS_STANDBY:\r
+\r
+                       break;\r
+               case SND_SOC_BIAS_OFF:\r
+\r
+                       rt5621_write_mask(codec, 0x02, 0x8080, 0x8080);\r
+                       rt5621_write_mask(codec, 0x04, 0x8080, 0x8080);\r
+                       rt5621_write(codec, 0x3e, 0x0000);\r
+                       rt5621_write(codec, 0x3c, 0x0000);\r
+                       rt5621_write(codec, 0x3a, 0x0000);\r
+                       break;          \r
+       }\r
+       codec->bias_level = level;\r
+       return 0;\r
+}\r
+#endif\r
+\r
+\r
+\r
+\r
+\r
+#if !USE_DAPM_CONTROL\r
+\r
+static void rt5621_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *codec_dai)\r
+{\r
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;\r
+       struct snd_soc_device *socdev = rtd->socdev;\r
+       struct snd_soc_codec *codec = socdev->card->codec;\r
+       int stream = substream->stream;\r
+       \r
+       switch (stream)\r
+       {\r
+               case SNDRV_PCM_STREAM_PLAYBACK:\r
+\r
+                       rt5621_AudioOutEnable(codec,RT_WAVOUT_SPK,1);   //mute speaker out\r
+                       \r
+                       rt5621_AudioOutEnable(codec,RT_WAVOUT_HP,1);    //mute hp out\r
+\r
+                       rt5621_ChangeCodecPowerStatus(codec,POWER_STATE_D2_PLAYBACK);   //power off dac to hp and speaker out\r
+                                               \r
+\r
+\r
+                       break;\r
+               case SNDRV_PCM_STREAM_CAPTURE:\r
+\r
+                       Enable_ADC_Input_Source(codec,RT_WAVIN_L_MIC1|RT_WAVIN_R_MIC1,0);       //disable record        source from mic1\r
+\r
+                       rt5621_ChangeCodecPowerStatus(codec,POWER_STATE_D2_RECORD);\r
+                       \r
+\r
+                       break;                  \r
+       }       \r
+}\r
+\r
+#endif\r
+\r
+\r
+#define RT5621_HIFI_RATES SNDRV_PCM_RATE_8000_48000\r
+\r
+#define RT5621_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\\r
+       SNDRV_PCM_FMTBIT_S24_LE)\r
+\r
+struct snd_soc_dai_ops rt5621_hifi_ops = {\r
+       .hw_params = rt5621_pcm_hw_params,      \r
+       .set_fmt = rt5621_set_dai_fmt,\r
+       .set_sysclk = rt5621_set_dai_sysclk,\r
+       .set_pll = rt5621_set_dai_pll,\r
+#if !USE_DAPM_CONTROL\r
+       .prepare = rt5621_pcm_hw_prepare,\r
+       .shutdown = rt5621_shutdown,\r
+#endif\r
+       \r
+};\r
+\r
+struct snd_soc_dai rt5621_dai = { \r
+       \r
+               .name = "RT5621",\r
+               .playback = {\r
+                       .stream_name = "HiFi Playback",\r
+                       .channels_min = 1,\r
+                       .channels_max = 2,\r
+                       .rates = RT5621_HIFI_RATES,\r
+                       .formats = RT5621_FORMATS,},\r
+               .capture = {\r
+                       .stream_name = "HiFi Capture",\r
+                       .channels_min = 1,\r
+                       .channels_max = 2,\r
+                       .rates = RT5621_HIFI_RATES,\r
+                       .formats = RT5621_FORMATS,},\r
+\r
+               .ops = &rt5621_hifi_ops,\r
+};\r
+\r
+\r
+EXPORT_SYMBOL_GPL(rt5621_dai);\r
+\r
+static ssize_t rt5621_index_reg_show(struct device *dev, \r
+       struct device_attribute *attr, char *buf)\r
+{\r
+       struct snd_soc_device *socdev = dev_get_drvdata(dev);\r
+       struct snd_soc_codec *codec = socdev ->card->codec;\r
+       int count = 0;\r
+       int value;\r
+       int i; \r
+       \r
+       count += sprintf(buf, "%s index register\n", codec->name);\r
+\r
+       for (i = 0; i < 0x60; i++) {\r
+               count += sprintf(buf + count, "index-%2x    ", i);\r
+               if (count >= PAGE_SIZE - 1)\r
+                       break;\r
+               value = rt5621_read_index(codec, i);\r
+               count += snprintf(buf + count, PAGE_SIZE - count, "0x%4x", value);\r
+\r
+               if (count >= PAGE_SIZE - 1)\r
+                       break;\r
+\r
+               count += snprintf(buf + count, PAGE_SIZE - count, "\n");\r
+               if (count >= PAGE_SIZE - 1)\r
+                       break;\r
+       }\r
+\r
+       if (count >= PAGE_SIZE)\r
+                       count = PAGE_SIZE - 1;\r
+               \r
+       return count;\r
+       \r
+}\r
+\r
+static DEVICE_ATTR(index_reg, 0444, rt5621_index_reg_show, NULL);\r
+\r
+#if defined(CONFIG_SND_HWDEP)\r
+#if REALTEK_HWDEP\r
+\r
+#define RT_CE_CODEC_HWDEP_NAME "rt56xx hwdep "\r
+\r
+static int rt56xx_hwdep_open(struct snd_hwdep *hw, struct file *file)\r
+{\r
+       printk("enter %s\n", __func__);\r
+       return 0;\r
+}\r
+\r
+static int rt56xx_hwdep_release(struct snd_hwdep *hw, struct file *file)\r
+{\r
+       printk("enter %s\n", __func__);\r
+       return 0;\r
+}\r
+\r
+\r
+static int rt56xx_hwdep_ioctl_common(struct snd_hwdep *hw, struct file *file, unsigned int cmd, unsigned long arg)\r
+{\r
+       struct rt56xx_cmd rt56xx;\r
+       struct rt56xx_cmd __user *_rt56xx = arg;\r
+       struct rt56xx_reg_state *buf;\r
+       struct rt56xx_reg_state *p;\r
+       struct snd_soc_codec *codec = hw->private_data;\r
+\r
+       if (copy_from_user(&rt56xx, _rt56xx, sizeof(rt56xx)))\r
+               return -EFAULT;\r
+       buf = kmalloc(sizeof(*buf) * rt56xx.number, GFP_KERNEL);\r
+       if (buf == NULL)\r
+               return -ENOMEM;\r
+       if (copy_from_user(buf, rt56xx.buf, sizeof(*buf) * rt56xx.number)) {\r
+               goto err;\r
+       }\r
+       switch (cmd) {\r
+               case RT_READ_CODEC_REG_IOCTL:\r
+                       for (p = buf; p < buf + rt56xx.number; p++)\r
+                       {\r
+                               p->reg_value = codec->read(codec, p->reg_index);\r
+                       }\r
+                       if (copy_to_user(rt56xx.buf, buf, sizeof(*buf) * rt56xx.number))\r
+                               goto err;\r
+                               \r
+                       break;\r
+               case RT_WRITE_CODEC_REG_IOCTL:\r
+                       for (p = buf; p < buf + rt56xx.number; p++)\r
+                               codec->write(codec, p->reg_index, p->reg_value);\r
+                       break;\r
+       }\r
+\r
+       kfree(buf);\r
+       return 0;\r
+\r
+err:\r
+       kfree(buf);\r
+       return -EFAULT;\r
+       \r
+}\r
+\r
+static int rt56xx_codec_dump_reg(struct snd_hwdep *hw, struct file *file, unsigned long arg)\r
+{\r
+       struct rt56xx_cmd rt56xx;\r
+       struct rt56xx_cmd __user *_rt56xx = arg;\r
+       struct rt56xx_reg_state *buf;\r
+       struct snd_soc_codec *codec = hw->private_data;\r
+       int number = codec->reg_cache_size;\r
+       int i;\r
+\r
+       printk(KERN_DEBUG "enter %s, number = %d\n", __func__, number); \r
+       if (copy_from_user(&rt56xx, _rt56xx, sizeof(rt56xx)))\r
+               return -EFAULT;\r
+       \r
+       buf = kmalloc(sizeof(*buf) * number, GFP_KERNEL);\r
+       if (buf == NULL)\r
+               return -ENOMEM;\r
+\r
+       for (i = 0; i < number; i++)\r
+       {\r
+               buf[i].reg_index = i << 1;\r
+               buf[i].reg_value = codec->read(codec, buf[i].reg_index);\r
+       }\r
+       if (copy_to_user(rt56xx.buf, buf, sizeof(*buf) * i))\r
+               goto err;\r
+       rt56xx.number = number;\r
+       if (copy_to_user(_rt56xx, &rt56xx, sizeof(rt56xx)))\r
+               goto err;\r
+       kfree(buf);\r
+       return 0;\r
+err:\r
+       kfree(buf);\r
+       return -EFAULT;\r
+       \r
+}\r
+\r
+static int rt56xx_hwdep_ioctl(struct snd_hwdep *hw, struct file *file, unsigned int cmd, unsigned long arg)\r
+{\r
+       if (cmd == RT_READ_ALL_CODEC_REG_IOCTL)\r
+       {\r
+               return rt56xx_codec_dump_reg(hw, file, arg);\r
+       }\r
+       else\r
+       {\r
+               return rt56xx_hwdep_ioctl_common(hw, file, cmd, arg);\r
+       }\r
+}\r
+\r
+static int realtek_ce_init_hwdep(struct snd_soc_codec *codec)\r
+{\r
+       struct snd_hwdep *hw;\r
+       struct snd_card *card = codec->card;\r
+       int err;\r
+\r
+       if ((err = snd_hwdep_new(card, RT_CE_CODEC_HWDEP_NAME, 0, &hw)) < 0)\r
+               return err;\r
+       \r
+       strcpy(hw->name, RT_CE_CODEC_HWDEP_NAME);\r
+       hw->private_data = codec;\r
+       hw->ops.open = rt56xx_hwdep_open;\r
+       hw->ops.release = rt56xx_hwdep_release;\r
+       hw->ops.ioctl = rt56xx_hwdep_ioctl;\r
+       return 0;\r
+}\r
+\r
+#endif\r
+#endif\r
+\r
+static void rt5621_work(struct work_struct *work)\r
+{\r
+       struct snd_soc_codec *codec =\r
+               container_of(work, struct snd_soc_codec, delayed_work.work);\r
+       \r
+       rt5621_set_bias_level(codec, codec->bias_level);\r
+}\r
+\r
+\r
+static int rt5621_suspend(struct platform_device *pdev, pm_message_t state)\r
+{\r
+       struct snd_soc_device *socdev = platform_get_drvdata(pdev);\r
+       struct snd_soc_codec *codec = socdev ->card->codec;\r
+\r
+       /* we only need to suspend if we are a valid card */\r
+       if(!codec->card)\r
+               return 0;\r
+               \r
+       rt5621_set_bias_level(codec, SND_SOC_BIAS_STANDBY);\r
+       return 0;\r
+}\r
+\r
+static int rt5621_resume(struct platform_device *pdev)\r
+{\r
+       struct snd_soc_device *socdev = platform_get_drvdata(pdev);\r
+       struct snd_soc_codec *codec = socdev ->card->codec;\r
+       int i;\r
+       u8 data[3];\r
+       u16 *cache = codec->reg_cache;\r
+\r
+       /* we only need to resume if we are a valid card */\r
+       if(!codec->card)\r
+               return 0;\r
+\r
+       /* Sync reg_cache with the hardware */  \r
+\r
+       for (i = 0; i < ARRAY_SIZE(rt5621_reg); i++) {\r
+               if (i == RT5621_RESET)\r
+                       continue;\r
+               data[0] =i << 1;        \r
+               data[1] = (0xFF00 & cache[i]) >> 8;\r
+               data[2] = 0x00FF & cache[i];    \r
+               codec->hw_write(codec->control_data, data, 3);\r
+       }       \r
+\r
+       rt5621_set_bias_level(codec, SND_SOC_BIAS_STANDBY);\r
+       \r
+       /* charge rt5621 caps */\r
+       \r
+       if (codec->suspend_bias_level == SND_SOC_BIAS_ON) {\r
+               rt5621_set_bias_level(codec, SND_SOC_BIAS_PREPARE);\r
+               codec->bias_level = SND_SOC_BIAS_ON;\r
+               schedule_delayed_work(&codec->delayed_work,\r
+                                       msecs_to_jiffies(caps_charge));\r
+       }\r
+       return 0;\r
+}\r
+\r
+\r
+/*\r
+ * initialise the RT5621 driver\r
+ * register the mixer and dsp interfaces with the kernel\r
+ */\r
+static int rt5621_init(struct snd_soc_device *socdev)\r
+{\r
+       struct snd_soc_codec *codec = socdev ->card->codec;\r
+       int  ret = 0;\r
+\r
+       printk(KERN_INFO "alsa version is 1.0.21, codec driver version is 0.04\n");\r
+       codec->name = "RT5621";\r
+       codec->owner = THIS_MODULE;\r
+       codec->read = rt5621_read;\r
+       codec->write = rt5621_write;\r
+       codec->set_bias_level = rt5621_set_bias_level;\r
+       codec->dai = &rt5621_dai;\r
+       codec->num_dai = 1;\r
+       codec->reg_cache_step = 2;\r
+       codec->reg_cache_size = ARRAY_SIZE(rt5621_reg) * 2;\r
+       codec->reg_cache = kmemdup(rt5621_reg, sizeof(rt5621_reg), GFP_KERNEL);\r
+\r
+       if (codec->reg_cache == NULL)\r
+               return -ENOMEM;\r
+               \r
+       /* register pcms */\r
+       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);\r
+       if (ret < 0) {\r
+               printk(KERN_ERR "rt5621: failed to create pcms\n");\r
+               goto pcm_err;\r
+       }\r
+\r
+\r
+       rt5621_reset(codec);\r
+       rt5621_write(codec, RT5621_PWR_MANAG_ADD3, 0x8000);//enable Main bias\r
+       rt5621_write(codec, RT5621_PWR_MANAG_ADD2, 0x2000);//enable Vref\r
+\r
+       hp_depop_mode2(codec);\r
+\r
+       rt5621_init_reg(codec);\r
+       rt5621_set_bias_level(codec, SND_SOC_BIAS_PREPARE);\r
+       codec->bias_level = SND_SOC_BIAS_STANDBY;\r
+       schedule_delayed_work(&codec->delayed_work,\r
+               msecs_to_jiffies(caps_charge));\r
+       \r
+       rt5621_add_controls(codec);\r
+\r
+       #if USE_DAPM_CONTROL\r
+\r
+               rt5621_add_widgets(codec);      \r
+\r
+       #endif\r
+\r
+       #if defined(CONFIG_SND_HWDEP)\r
+       #if REALTEK_HWDEP\r
+\r
+               realtek_ce_init_hwdep(codec);\r
+\r
+       #endif\r
+       #endif\r
+\r
+       ret = snd_soc_init_card(socdev);\r
+\r
+       if (ret < 0) {\r
+               printk(KERN_ERR "rt5621: failed to register card\n");\r
+                       goto card_err;\r
+       }\r
+       return ret;\r
+\r
+card_err:\r
+       snd_soc_free_pcms(socdev);\r
+       snd_soc_dapm_free(socdev);\r
+pcm_err:\r
+       kfree(codec->reg_cache);\r
+       return ret;\r
+}\r
+\r
+static int rt5621_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id)\r
+{\r
+       struct snd_soc_device *socdev = rt5621_socdev;\r
+       struct snd_soc_codec *codec = socdev ->card->codec;\r
+       int ret;\r
+\r
+       i2c_set_clientdata(i2c, codec);\r
+       codec->control_data = i2c;\r
+\r
+       ret = rt5621_init(socdev);\r
+       if (ret < 0)\r
+               pr_err("failed to initialise rt5621\n");\r
+\r
+       return ret;\r
+}\r
+\r
+\r
+static int rt5621_i2c_remove(struct i2c_client *client)\r
+{\r
+       struct snd_soc_codec *codec = i2c_get_clientdata(client);\r
+       kfree(codec->reg_cache);\r
+       return 0;\r
+}\r
+\r
+static const struct i2c_device_id rt5621_i2c_id[] = {\r
+               {"ALC5621", 0},\r
+               {}\r
+};\r
+MODULE_DEVICE_TABLE(i2c, rt5621_i2c_id);\r
+static struct i2c_driver rt5621_i2c_driver = {\r
+       .driver = {\r
+               .name = "RT5621 I2C Codec",\r
+               .owner = THIS_MODULE,\r
+       },\r
+       .probe =    rt5621_i2c_probe,\r
+       .remove =   rt5621_i2c_remove,\r
+       .id_table = rt5621_i2c_id,\r
+};\r
+\r
+static int rt5621_add_i2c_device(struct platform_device *pdev,\r
+                                const struct rt5621_setup_data *setup)\r
+{\r
+#if 0\r
+       struct i2c_board_info info;\r
+       struct i2c_adapter *adapter;\r
+       struct i2c_client *client;\r
+#endif\r
+       int ret;\r
+       ret = i2c_add_driver(&rt5621_i2c_driver);\r
+       if (ret != 0) {\r
+               dev_err(&pdev->dev, "can't add i2c driver\n");\r
+               return ret;\r
+       }\r
+#if 0\r
+       memset(&info, 0, sizeof(struct i2c_board_info));\r
+       info.addr = setup->i2c_address;\r
+       strlcpy(info.type, "rt5621", I2C_NAME_SIZE);\r
+\r
+       adapter = i2c_get_adapter(setup->i2c_bus);\r
+       if (!adapter) {\r
+               dev_err(&pdev->dev, "can't get i2c adapter %d\n",\r
+                       setup->i2c_bus);\r
+               goto err_driver;\r
+       }\r
+\r
+       client = i2c_new_device(adapter, &info);\r
+       i2c_put_adapter(adapter);\r
+       if (!client) {\r
+               dev_err(&pdev->dev, "can't add i2c device at 0x%x\n",\r
+                       (unsigned int)info.addr);\r
+               goto err_driver;\r
+       }\r
+#endif\r
+       return 0;\r
+\r
+#if 0\r
+err_driver:\r
+       i2c_del_driver(&rt5621_i2c_driver);\r
+       return -ENODEV;\r
+#endif\r
+}\r
+\r
+\r
+static int rt5621_probe(struct platform_device *pdev)\r
+{\r
+       struct snd_soc_device *socdev = platform_get_drvdata(pdev);\r
+       struct rt5621_setup_data *setup = socdev->codec_data;\r
+       struct snd_soc_codec *codec;\r
+       struct rt5621_priv *rt5621;\r
+       int ret;\r
+\r
+       pr_info("RT5621 Audio Codec %s\n", RT5621_VERSION);\r
+\r
+       codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);\r
+       if (codec == NULL)\r
+               return -ENOMEM;\r
+\r
+       rt5621 = kzalloc(sizeof(struct rt5621_priv), GFP_KERNEL);\r
+       if (rt5621 == NULL) {\r
+               kfree(codec);\r
+               return -ENOMEM;\r
+       }\r
+       codec->private_data = rt5621;\r
+       socdev ->card->codec = codec;\r
+       mutex_init(&codec->mutex);\r
+       INIT_LIST_HEAD(&codec->dapm_widgets);\r
+       INIT_LIST_HEAD(&codec->dapm_paths);\r
+       rt5621_socdev = socdev;\r
+       INIT_DELAYED_WORK(&codec->delayed_work, rt5621_work);\r
+       ret = device_create_file(&pdev->dev, &dev_attr_index_reg);\r
+       if (ret < 0)\r
+               printk(KERN_WARNING "asoc: failed to add index_reg sysfs files\n");\r
+\r
+       ret = -ENODEV;\r
+//     if (setup->i2c_address) {\r
+               codec->hw_write = (hw_write_t)i2c_master_send;\r
+               ret = rt5621_add_i2c_device(pdev, setup);\r
+//     }\r
+       if (ret != 0) {\r
+               kfree(codec->private_data);\r
+               kfree(codec);\r
+       }\r
+       return ret;\r
+}\r
+\r
+static int run_delayed_work(struct delayed_work *dwork)\r
+{\r
+       int ret;\r
+\r
+       /* cancel any work waiting to be queued. */\r
+       ret = cancel_delayed_work(dwork);\r
+\r
+       /* if there was any work waiting then we run it now and\r
+        * wait for it's completion */\r
+       if (ret) {\r
+               schedule_delayed_work(dwork, 0);\r
+               flush_scheduled_work();\r
+       }\r
+       return ret;\r
+}\r
+\r
+static int rt5621_remove(struct platform_device *pdev)\r
+{\r
+       struct snd_soc_device *socdev = platform_get_drvdata(pdev);\r
+       struct snd_soc_codec *codec = socdev ->card->codec;\r
+\r
+       if (codec->control_data)\r
+               rt5621_set_bias_level(codec, SND_SOC_BIAS_OFF);\r
+       run_delayed_work(&codec->delayed_work);\r
+       snd_soc_free_pcms(socdev);\r
+       snd_soc_dapm_free(socdev);\r
+       device_remove_file(&pdev->dev, &dev_attr_index_reg);\r
+       i2c_unregister_device(codec->control_data);\r
+       i2c_del_driver(&rt5621_i2c_driver);\r
+       kfree(codec->private_data);\r
+       kfree(codec);\r
+\r
+       return 0;\r
+}\r
+\r
+struct snd_soc_codec_device soc_codec_dev_rt5621 = {\r
+       .probe =        rt5621_probe,\r
+       .remove =       rt5621_remove,\r
+       .suspend =      rt5621_suspend,\r
+       .resume =       rt5621_resume,\r
+};\r
+\r
+EXPORT_SYMBOL_GPL(soc_codec_dev_rt5621);\r
+\r
+static int __init rt5621_modinit(void)\r
+{\r
+       return snd_soc_register_dai(&rt5621_dai);\r
+}\r
+\r
+static void __exit rt5621_exit(void)\r
+{\r
+       snd_soc_unregister_dai(&rt5621_dai);\r
+}\r
+\r
+module_init(rt5621_modinit);\r
+module_exit(rt5621_exit);\r
+MODULE_LICENSE("GPL");\r
+\r
diff --git a/sound/soc/codecs/alc5621.h b/sound/soc/codecs/alc5621.h
new file mode 100644 (file)
index 0000000..bdcebbd
--- /dev/null
@@ -0,0 +1,516 @@
+#ifndef _RT5621_H\r
+#define _RT5621_H\r
+\r
+\r
+#define RT5621_RESET                                           0X00                    //RESET CODEC TO DEFAULT\r
+#define RT5621_SPK_OUT_VOL                                     0X02                    //SPEAKER OUT VOLUME\r
+#define RT5621_HP_OUT_VOL                                      0X04                    //HEADPHONE OUTPUT VOLUME\r
+#define RT5621_MONO_AUX_OUT_VOL                                0X06                    //MONO OUTPUT/AUXOUT VOLUME\r
+#define RT5621_AUXIN_VOL                                       0X08                    //AUXIN VOLUME\r
+#define RT5621_LINE_IN_VOL                                     0X0A                    //LINE IN VOLUME\r
+#define RT5621_STEREO_DAC_VOL                          0X0C                    //STEREO DAC VOLUME\r
+#define RT5621_MIC_VOL                                         0X0E                    //MICROPHONE VOLUME\r
+#define RT5621_MIC_ROUTING_CTRL                                0X10                    //MIC ROUTING CONTROL\r
+#define RT5621_ADC_REC_GAIN                                    0X12                    //ADC RECORD GAIN\r
+#define RT5621_ADC_REC_MIXER                           0X14                    //ADC RECORD MIXER CONTROL\r
+#define RT5621_SOFT_VOL_CTRL_TIME                      0X16                    //SOFT VOLUME CONTROL TIME\r
+#define RT5621_OUTPUT_MIXER_CTRL                       0X1C                    //OUTPUT MIXER CONTROL\r
+#define RT5621_MIC_CTRL                                                0X22                    //MICROPHONE CONTROL\r
+#define        RT5621_AUDIO_INTERFACE                          0X34                    //AUDIO INTERFACE\r
+#define RT5621_STEREO_AD_DA_CLK_CTRL           0X36                    //STEREO AD/DA CLOCK CONTROL\r
+#define        RT5621_COMPANDING_CTRL                          0X38                    //COMPANDING CONTROL\r
+#define        RT5621_PWR_MANAG_ADD1                           0X3A                    //POWER MANAGMENT ADDITION 1\r
+#define RT5621_PWR_MANAG_ADD2                          0X3C                    //POWER MANAGMENT ADDITION 2\r
+#define RT5621_PWR_MANAG_ADD3                          0X3E                    //POWER MANAGMENT ADDITION 3\r
+#define RT5621_ADD_CTRL_REG                                    0X40                    //ADDITIONAL CONTROL REGISTER\r
+#define        RT5621_GLOBAL_CLK_CTRL_REG                      0X42                    //GLOBAL CLOCK CONTROL REGISTER\r
+#define RT5621_PLL_CTRL                                                0X44                    //PLL CONTROL\r
+#define RT5621_GPIO_OUTPUT_PIN_CTRL                    0X4A                    //GPIO OUTPUT PIN CONTROL\r
+#define RT5621_GPIO_PIN_CONFIG                         0X4C                    //GPIO PIN CONFIGURATION\r
+#define RT5621_GPIO_PIN_POLARITY                       0X4E                    //GPIO PIN POLARITY/TYPE        \r
+#define RT5621_GPIO_PIN_STICKY                         0X50                    //GPIO PIN STICKY       \r
+#define RT5621_GPIO_PIN_WAKEUP                         0X52                    //GPIO PIN WAKE UP\r
+#define RT5621_GPIO_PIN_STATUS                         0X54                    //GPIO PIN STATUS\r
+#define RT5621_GPIO_PIN_SHARING                                0X56                    //GPIO PIN SHARING\r
+#define        RT5621_OVER_TEMP_CURR_STATUS            0X58                    //OVER TEMPERATURE AND CURRENT STATUS\r
+#define RT5621_JACK_DET_CTRL                           0X5A                    //JACK DETECT CONTROL REGISTER\r
+#define RT5621_MISC_CTRL                                       0X5E                    //MISC CONTROL\r
+#define        RT5621_PSEDUEO_SPATIAL_CTRL                     0X60                    //PSEDUEO STEREO & SPATIAL EFFECT BLOCK CONTROL\r
+#define RT5621_EQ_CTRL                                         0X62                    //EQ CONTROL\r
+#define RT5621_EQ_MODE_ENABLE                          0X66                    //EQ MODE CHANGE ENABLE\r
+#define RT5621_AVC_CTRL                                                0X68                    //AVC CONTROL\r
+#define RT5621_HID_CTRL_INDEX                          0X6A                    //HIDDEN CONTROL INDEX PORT\r
+#define RT5621_HID_CTRL_DATA                           0X6C                    //HIDDEN CONTROL DATA PORT\r
+#define RT5621_VENDOR_ID1                              0x7C                    //VENDOR ID1\r
+#define RT5621_VENDOR_ID2                              0x7E                    //VENDOR ID2\r
+\r
+\r
+//global definition\r
+#define RT_L_MUTE                                              (0x1<<15)               //MUTE LEFT CONTROL BIT\r
+#define RT_L_ZC                                                        (0x1<<14)               //LEFT ZERO CROSS CONTROL BIT\r
+#define RT_L_SM                                                        (0x1<<13)               //LEFT SOFTMUTE CONTROL BIT\r
+#define RT_R_MUTE                                              (0x1<<7)                //MUTE RIGHT CONTROL BIT\r
+#define RT_R_ZC                                                        (0x1<<6)                //RIGHT ZERO CROSS CONTROL BIT\r
+#define RT_R_SM                                                        (0x1<<5)                //RIGHT SOFTMUTE CONTROL BIT\r
+#define RT_M_HP_MIXER                                  (0x1<<15)               //Mute source to HP Mixer\r
+#define RT_M_SPK_MIXER                                 (0x1<<14)               //Mute source to Speaker Mixer\r
+#define RT_M_MONO_MIXER                                        (0x1<<13)               //Mute source to Mono Mixer\r
+#define SPK_CLASS_AB                                           0\r
+#define SPK_CLASS_D                                                    1\r
+\r
+//Mic Routing Control(0x10)\r
+#define M_MIC1_TO_HP_MIXER                             (0x1<<15)               //Mute MIC1 to HP mixer\r
+#define M_MIC1_TO_SPK_MIXER                            (0x1<<14)               //Mute MiC1 to SPK mixer\r
+#define M_MIC1_TO_MONO_MIXER                   (0x1<<13)               //Mute MIC1 to MONO mixer\r
+#define MIC1_DIFF_INPUT_CTRL                   (0x1<<12)               //MIC1 different input control\r
+#define M_MIC2_TO_HP_MIXER                             (0x1<<7)                //Mute MIC2 to HP mixer\r
+#define M_MIC2_TO_SPK_MIXER                            (0x1<<6)                //Mute MiC2 to SPK mixer\r
+#define M_MIC2_TO_MONO_MIXER                   (0x1<<5)                //Mute MIC2 to MONO mixer\r
+#define MIC2_DIFF_INPUT_CTRL                   (0x1<<4)                //MIC2 different input control\r
+\r
+//ADC Record Gain(0x12)\r
+#define M_ADC_L_TO_HP_MIXER                            (0x1<<15)               //Mute left of ADC to HP Mixer\r
+#define M_ADC_R_TO_HP_MIXER                            (0x1<<14)               //Mute right of ADC to HP Mixer\r
+#define M_ADC_L_TO_MONO_MIXER                  (0x1<<13)               //Mute left of ADC to MONO Mixer\r
+#define M_ADC_R_TO_MONO_MIXER                  (0x1<<12)               //Mute right of ADC to MONO Mixer\r
+#define ADC_L_GAIN_MASK                                        (0x1f<<7)               //ADC Record Gain Left channel Mask\r
+#define ADC_L_ZC_DET                                   (0x1<<6)                //ADC Zero-Cross Detector Control\r
+#define ADC_R_ZC_DET                                   (0x1<<5)                //ADC Zero-Cross Detector Control\r
+#define ADC_R_GAIN_MASK                                        (0x1f<<0)               //ADC Record Gain Right channel Mask\r
+\r
+//ADC Input Mixer Control(0x14)\r
+#define M_MIC1_TO_ADC_L_MIXER                          (0x1<<14)               //Mute mic1 to left channel of ADC mixer\r
+#define M_MIC2_TO_ADC_L_MIXER                          (0x1<<13)               //Mute mic2 to left channel of ADC mixer\r
+#define M_LINEIN_L_TO_ADC_L_MIXER                      (0x1<<12)               //Mute line In left channel to left channel of ADC mixer\r
+#define M_AUXIN_L_TO_ADC_L_MIXER                       (0x1<<11)               //Mute aux In left channel to left channel of ADC mixer\r
+#define M_HPMIXER_L_TO_ADC_L_MIXER                     (0x1<<10)               //Mute HP mixer left channel to left channel of ADC mixer\r
+#define M_SPKMIXER_L_TO_ADC_L_MIXER                    (0x1<<9)                //Mute SPK mixer left channel to left channel of ADC mixer\r
+#define M_MONOMIXER_L_TO_ADC_L_MIXER           (0x1<<8)                //Mute MONO mixer left channel to left channel of ADC mixer\r
+#define M_MIC1_TO_ADC_R_MIXER                          (0x1<<6)                //Mute mic1 to right channel of ADC mixer\r
+#define M_MIC2_TO_ADC_R_MIXER                          (0x1<<5)                //Mute mic2 to right channel of ADC mixer\r
+#define M_LINEIN_R_TO_ADC_R_MIXER                      (0x1<<4)                //Mute lineIn right channel to right channel of ADC mixer\r
+#define M_AUXIN_R_TO_ADC_R_MIXER                       (0x1<<3)                //Mute aux In right channel to right channel of ADC mixer\r
+#define M_HPMIXER_R_TO_ADC_R_MIXER                     (0x1<<2)                //Mute HP mixer right channel to right channel of ADC mixer\r
+#define M_SPKMIXER_R_TO_ADC_R_MIXER                    (0x1<<1)                //Mute SPK mixer right channel to right channel of ADC mixer\r
+#define M_MONOMIXER_R_TO_ADC_R_MIXER           (0x1<<0)                //Mute MONO mixer right channel to right channel of ADC mixer\r
+\r
+//Output Mixer Control(0x1C)\r
+#define        SPKOUT_N_SOUR_MASK                                      (0x3<<14)       \r
+#define        SPKOUT_N_SOUR_LN                                        (0x2<<14)\r
+#define        SPKOUT_N_SOUR_RP                                        (0x1<<14)\r
+#define        SPKOUT_N_SOUR_RN                                        (0x0<<14)\r
+#define SPK_OUTPUT_CLASS_AB                                    (0x0<<13)\r
+#define SPK_OUTPUT_CLASS_D                                     (0x1<<13)\r
+#define SPK_CLASS_AB_S_AMP                                     (0x0<<12)\r
+#define SPK_CALSS_AB_W_AMP                                     (0x1<<12)\r
+#define SPKOUT_INPUT_SEL_MASK                          (0x3<<10)\r
+#define SPKOUT_INPUT_SEL_MONOMIXER                     (0x3<<10)\r
+#define SPKOUT_INPUT_SEL_SPKMIXER                      (0x2<<10)\r
+#define SPKOUT_INPUT_SEL_HPMIXER                       (0x1<<10)\r
+#define SPKOUT_INPUT_SEL_VMID                          (0x0<<10)\r
+#define HPL_INPUT_SEL_HPLMIXER                         (0x1<<9)\r
+#define HPR_INPUT_SEL_HPRMIXER                         (0x1<<8)        \r
+#define MONO_AUX_INPUT_SEL_MASK                                (0x3<<6)\r
+#define MONO_AUX_INPUT_SEL_MONO                                (0x3<<6)\r
+#define MONO_AUX_INPUT_SEL_SPK                         (0x2<<6)\r
+#define MONO_AUX_INPUT_SEL_HP                          (0x1<<6)\r
+#define MONO_AUX_INPUT_SEL_VMID                                (0x0<<6)\r
+\r
+//Micphone Control define(0x22)\r
+#define MIC1           1\r
+#define MIC2           2\r
+#define MIC_BIAS_90_PRECNET_AVDD       1\r
+#define        MIC_BIAS_75_PRECNET_AVDD        2\r
+\r
+#define MIC1_BOOST_CTRL_MASK           (0x3<<10)\r
+#define MIC1_BOOST_CTRL_BYPASS         (0x0<<10)\r
+#define MIC1_BOOST_CTRL_20DB           (0x1<<10)\r
+#define MIC1_BOOST_CTRL_30DB           (0x2<<10)\r
+#define MIC1_BOOST_CTRL_40DB           (0x3<<10)\r
+\r
+#define MIC2_BOOST_CTRL_MASK           (0x3<<8)\r
+#define MIC2_BOOST_CTRL_BYPASS         (0x0<<8)\r
+#define MIC2_BOOST_CTRL_20DB           (0x1<<8)\r
+#define MIC2_BOOST_CTRL_30DB           (0x2<<8)\r
+#define MIC2_BOOST_CTRL_40DB           (0x3<<8)\r
+\r
+#define MICBIAS_VOLT_CTRL_MASK         (0x1<<5)\r
+#define MICBIAS_VOLT_CTRL_90P          (0x0<<5)\r
+#define MICBIAS_VOLT_CTRL_75P          (0x1<<5)\r
+\r
+#define MICBIAS_SHORT_CURR_DET_MASK            (0x3)\r
+#define MICBIAS_SHORT_CURR_DET_600UA   (0x0)\r
+#define MICBIAS_SHORT_CURR_DET_1200UA  (0x1)\r
+#define MICBIAS_SHORT_CURR_DET_1800UA  (0x2)\r
+\r
+//Audio Interface(0x34)                        \r
+#define SDP_MASTER_MODE                                (0x0<<15)               //Main I2S interface select Master mode\r
+#define SDP_SLAVE_MODE                         (0x1<<15)               //Main I2S interface select Slave mode\r
+#define I2S_PCM_MODE                           (0x1<<14)               //PCM           0:mode A                                ,1:mode B                                                                                                       \r
+#define MAIN_I2S_BCLK_POL_CTRL         (0x1<<7)                //0:Normal 1:Invert\r
+#define ADC_DATA_L_R_SWAP                      (0x1<<5)                //0:ADC data appear at left phase of LRCK\r
+                                                                                                       //1:ADC data appear at right phase of LRCK\r
+#define DAC_DATA_L_R_SWAP                      (0x1<<4)                //0:DAC data appear at left phase of LRCK\r
+                                                                                                       //1:DAC data appear at right phase of LRCK      \r
+//Data Length Slection\r
+#define I2S_DL_MASK                            (0x3<<2)                //main i2s Data Length mask     \r
+#define I2S_DL_16                              (0x0<<2)                //16 bits\r
+#define I2S_DL_20                              (0x1<<2)                //20 bits\r
+#define        I2S_DL_24                               (0x2<<2)                //24 bits\r
+#define I2S_DL_32                              (0x3<<2)                //32 bits\r
+                                                                                                       \r
+//PCM Data Format Selection\r
+#define I2S_DF_MASK                            (0x3)                   //main i2s Data Format mask\r
+#define I2S_DF_I2S                             (0x0)                   //I2S FORMAT \r
+#define I2S_DF_RIGHT                   (0x1)                   //RIGHT JUSTIFIED format\r
+#define        I2S_DF_LEFT                             (0x2)                   //LEFT JUSTIFIED  format\r
+#define I2S_DF_PCM                             (0x3)                   //PCM format\r
+\r
+//Stereo AD/DA Clock Control(0x36h)\r
+#define I2S_PRE_DIV_MASK               (0x7<<12)                       \r
+#define I2S_PRE_DIV_1                  (0x0<<12)                       //DIV 1\r
+#define I2S_PRE_DIV_2                  (0x1<<12)                       //DIV 2\r
+#define I2S_PRE_DIV_4                  (0x2<<12)                       //DIV 4\r
+#define I2S_PRE_DIV_8                  (0x3<<12)                       //DIV 8\r
+#define I2S_PRE_DIV_16                 (0x4<<12)                       //DIV 16\r
+#define I2S_PRE_DIV_32                 (0x5<<12)                       //DIV 32\r
+\r
+#define I2S_SCLK_DIV_MASK              (0x7<<9)                        \r
+#define I2S_SCLK_DIV_1                 (0x0<<9)                        //DIV 1\r
+#define I2S_SCLK_DIV_2                 (0x1<<9)                        //DIV 2\r
+#define I2S_SCLK_DIV_3                 (0x2<<9)                        //DIV 3\r
+#define I2S_SCLK_DIV_4                 (0x3<<9)                        //DIV 4\r
+#define I2S_SCLK_DIV_6                 (0x4<<9)                        //DIV 6\r
+#define I2S_SCLK_DIV_8                 (0x5<<9)                        //DIV 8\r
+#define I2S_SCLK_DIV_12                        (0x6<<9)                        //DIV 12\r
+#define I2S_SCLK_DIV_16                        (0x7<<9)                        //DIV 16\r
+\r
+#define I2S_WCLK_DIV_PRE_MASK          (0xF<<5)                        \r
+#define I2S_WCLK_PRE_DIV_1                     (0x0<<5)                        //DIV 1\r
+#define I2S_WCLK_PRE_DIV_2                     (0x1<<5)                        //DIV 2\r
+#define I2S_WCLK_PRE_DIV_3                     (0x2<<5)                        //DIV 3\r
+#define I2S_WCLK_PRE_DIV_4                     (0x3<<5)                        //DIV 4\r
+#define I2S_WCLK_PRE_DIV_5                     (0x4<<5)                        //DIV 5\r
+#define I2S_WCLK_PRE_DIV_6                     (0x5<<5)                        //DIV 6\r
+#define I2S_WCLK_PRE_DIV_7                     (0x6<<5)                        //DIV 7\r
+#define I2S_WCLK_PRE_DIV_8                     (0x7<<5)                        //DIV 8\r
+//........................\r
+\r
+#define I2S_WCLK_DIV_MASK              (0x7<<2)                        \r
+#define I2S_WCLK_DIV_2                 (0x0<<2)                        //DIV 2\r
+#define I2S_WCLK_DIV_4                 (0x1<<2)                        //DIV 4\r
+#define I2S_WCLK_DIV_8                 (0x2<<2)                        //DIV 8\r
+#define I2S_WCLK_DIV_16                        (0x3<<2)                        //DIV 16\r
+#define I2S_WCLK_DIV_32                        (0x4<<2)                        //DIV 32\r
+\r
+#define ADDA_FILTER_CLK_SEL_256FS      (0<<1)                  //256FS\r
+#define ADDA_FILTER_CLK_SEL_384FS      (1<<1)                  //384FS\r
+\r
+#define ADDA_OSR_SEL_64FS      (0)                                             //64FS\r
+#define ADDA_OSR_SEL_128FS     (1)                                             //128FS\r
+\r
+//Power managment addition 1 (0x3A),0:Disable,1:Enable\r
+#define PWR_MAIN_I2S_EN                                (0x1<<15)\r
+#define PWR_ZC_DET_PD_EN                       (0x1<<14)       \r
+#define PWR_MIC1_BIAS_EN                       (0x1<<11)\r
+#define PWR_SHORT_CURR_DET_EN          (0x1<<10)\r
+#define PWR_SOFTGEN_EN                         (0x1<<8)\r
+#define        PWR_DEPOP_BUF_HP                        (0x1<<6)\r
+#define        PWR_HP_OUT_AMP                          (0x1<<5)\r
+#define        PWR_HP_OUT_ENH_AMP                      (0x1<<4)\r
+#define PWR_DEPOP_BUF_AUX                      (0x1<<2)\r
+#define PWR_AUX_OUT_AMP                                (0x1<<1)\r
+#define PWR_AUX_OUT_ENH_AMP                    (0x1)\r
+\r
+\r
+//Power managment addition 2(0x3C),0:Disable,1:Enable\r
+#define PWR_CLASS_AB                           (0x1<<15)\r
+#define PWR_CLASS_D                                    (0x1<<14)\r
+#define PWR_VREF                                       (0x1<<13)\r
+#define PWR_PLL                                                (0x1<<12)\r
+#define PWR_DAC_REF_CIR                                (0x1<<10)\r
+#define PWR_L_DAC_CLK                          (0x1<<9)\r
+#define PWR_R_DAC_CLK                          (0x1<<8)\r
+#define PWR_L_ADC_CLK_GAIN                     (0x1<<7)\r
+#define PWR_R_ADC_CLK_GAIN                     (0x1<<6)\r
+#define PWR_L_HP_MIXER                         (0x1<<5)\r
+#define PWR_R_HP_MIXER                         (0x1<<4)\r
+#define PWR_SPK_MIXER                          (0x1<<3)\r
+#define PWR_MONO_MIXER                         (0x1<<2)\r
+#define PWR_L_ADC_REC_MIXER                    (0x1<<1)\r
+#define PWR_R_ADC_REC_MIXER                    (0x1)\r
+\r
+//Power managment addition 3(0x3E),0:Disable,1:Enable\r
+#define PWR_MAIN_BIAS                          (0x1<<15)\r
+#define PWR_AUXOUT_L_VOL_AMP           (0x1<<14)\r
+#define PWR_AUXOUT_R_VOL_AMP           (0x1<<13)\r
+#define PWR_SPK_OUT                                    (0x1<<12)\r
+#define PWR_HP_L_OUT_VOL                       (0x1<<10)\r
+#define PWR_HP_R_OUT_VOL                       (0x1<<9)\r
+#define PWR_LINEIN_L_VOL                       (0x1<<7)\r
+#define PWR_LINEIN_R_VOL                       (0x1<<6)\r
+#define PWR_AUXIN_L_VOL                                (0x1<<5)\r
+#define PWR_AUXIN_R_VOL                                (0x1<<4)\r
+#define PWR_MIC1_FUN_CTRL                      (0x1<<3)\r
+#define PWR_MIC2_FUN_CTRL                      (0x1<<2)\r
+#define PWR_MIC1_BOOST_MIXER           (0x1<<1)\r
+#define PWR_MIC2_BOOST_MIXER           (0x1)\r
+\r
+\r
+//Additional Control Register(0x40)\r
+#define AUXOUT_SEL_DIFF                                        (0x1<<15)       //Differential Mode\r
+#define AUXOUT_SEL_SE                                  (0x1<<15)       //Single-End Mode\r
+\r
+#define SPK_AB_AMP_CTRL_MASK                   (0x7<<12)\r
+#define SPK_AB_AMP_CTRL_RATIO_225              (0x0<<12)               //2.25 Vdd\r
+#define SPK_AB_AMP_CTRL_RATIO_200              (0x1<<12)               //2.00 Vdd\r
+#define SPK_AB_AMP_CTRL_RATIO_175              (0x2<<12)               //1.75 Vdd\r
+#define SPK_AB_AMP_CTRL_RATIO_150              (0x3<<12)               //1.50 Vdd\r
+#define SPK_AB_AMP_CTRL_RATIO_125              (0x4<<12)               //1.25 Vdd      \r
+#define SPK_AB_AMP_CTRL_RATIO_100              (0x5<<12)               //1.00 Vdd\r
+\r
+#define SPK_D_AMP_CTRL_MASK                            (0x3<<10)\r
+#define SPK_D_AMP_CTRL_RATIO_175               (0x0<<10)               //1.75 Vdd\r
+#define SPK_D_AMP_CTRL_RATIO_150               (0x1<<10)               //1.50 Vdd      \r
+#define SPK_D_AMP_CTRL_RATIO_125               (0x2<<10)               //1.25 Vdd\r
+#define SPK_D_AMP_CTRL_RATIO_100               (0x3<<10)               //1.00 Vdd\r
+\r
+#define STEREO_DAC_HI_PASS_FILTER_EN   (0x1<<9)                //Stereo DAC high pass filter enable\r
+#define STEREO_ADC_HI_PASS_FILTER_EN   (0x1<<8)                //Stereo ADC high pass filter enable\r
+\r
+#define DIG_VOL_BOOST_MASK                             (0x3<<4)                //Digital volume Boost mask\r
+#define DIG_VOL_BOOST_0DB                              (0x0<<4)                //Digital volume Boost 0DB\r
+#define DIG_VOL_BOOST_6DB                              (0x1<<4)                //Digital volume Boost 6DB\r
+#define DIG_VOL_BOOST_12DB                             (0x2<<4)                //Digital volume Boost 12DB\r
+#define DIG_VOL_BOOST_18DB                             (0x3<<4)                //Digital volume Boost 18DB\r
+\r
+\r
+//Global Clock Control Register(0x42)\r
+#define SYSCLK_SOUR_SEL_MASK                   (0x1<<15)\r
+#define SYSCLK_SOUR_SEL_MCLK                   (0x0<<15)               //system Clock source from MCLK\r
+#define SYSCLK_SOUR_SEL_PLL                            (0x1<<15)               //system Clock source from PLL\r
+#define PLLCLK_SOUR_SEL_MCLK                   (0x0<<14)               //PLL clock source from MCLK\r
+#define PLLCLK_SOUR_SEL_BITCLK                 (0x1<<14)               //PLL clock source from BITCLK\r
+\r
+#define PLLCLK_DIV_RATIO_MASK                  (0x3<<1)                \r
+#define PLLCLK_DIV_RATIO_DIV1                  (0x0<<1)                //DIV 1\r
+#define PLLCLK_DIV_RATIO_DIV2                  (0x1<<1)                //DIV 2\r
+#define PLLCLK_DIV_RATIO_DIV4                  (0x2<<1)                //DIV 4\r
+#define PLLCLK_DIV_RATIO_DIV8                  (0x3<<1)                //DIV 8\r
+\r
+#define PLLCLK_PRE_DIV1                                        (0x0)                   //DIV 1\r
+#define PLLCLK_PRE_DIV2                                        (0x1)                   //DIV 2\r
+\r
+//PLL Control(0x44)\r
+\r
+#define PLL_CTRL_M_VAL(m)              ((m)&0xf)\r
+#define PLL_CTRL_K_VAL(k)              (((k)&0x7)<<4)\r
+#define PLL_CTRL_N_VAL(n)              (((n)&0xff)<<8)\r
+\r
+//GPIO Pin Configuration(0x4C)\r
+#define GPIO_PIN_MASK                          (0x1<<1)\r
+#define GPIO_PIN_SET_INPUT                     (0x1<<1)\r
+#define GPIO_PIN_SET_OUTPUT                    (0x0<<1)\r
+\r
+//Pin Sharing(0x56)\r
+#define LINEIN_L_PIN_SHARING           (0x1<<15)\r
+#define LINEIN_L_PIN_AS_LINEIN_L       (0x0<<15)\r
+#define LINEIN_L_PIN_AS_JD1                    (0x1<<15)\r
+\r
+#define LINEIN_R_PIN_SHARING           (0x1<<14)\r
+#define LINEIN_R_PIN_AS_LINEIN_R       (0x0<<14)\r
+#define LINEIN_R_PIN_AS_JD2                    (0x1<<14)\r
+\r
+#define GPIO_PIN_SHARING                       (0x3)\r
+#define GPIO_PIN_AS_GPIO                       (0x0)\r
+#define GPIO_PIN_AS_IRQOUT                     (0x1)\r
+#define GPIO_PIN_AS_PLLOUT                     (0x3)\r
+\r
+//Jack Detect Control Register(0x5A)\r
+#define JACK_DETECT_MASK                       (0x3<<14)\r
+#define JACK_DETECT_USE_JD2                    (0x3<<14)\r
+#define JACK_DETECT_USE_JD1                    (0x2<<14)\r
+#define JACK_DETECT_USE_GPIO           (0x1<<14)\r
+#define JACK_DETECT_OFF                                (0x0<<14)\r
+\r
+#define        SPK_EN_IN_HI                            (0x1<<11)\r
+#define AUX_R_EN_IN_HI                         (0x1<<10)\r
+#define AUX_L_EN_IN_HI                         (0x1<<9)\r
+#define HP_EN_IN_HI                                    (0x1<<8)\r
+#define        SPK_EN_IN_LO                            (0x1<<7)\r
+#define AUX_R_EN_IN_LO                         (0x1<<6)\r
+#define AUX_L_EN_IN_LO                         (0x1<<5)\r
+#define HP_EN_IN_LO                                    (0x1<<4)\r
+\r
+////MISC CONTROL(0x5E)\r
+#define DISABLE_FAST_VREG                      (0x1<<15)\r
+#define SPK_CLASS_AB_OC_PD                     (0x1<<13)\r
+#define SPK_CLASS_AB_OC_DET                    (0x1<<12)\r
+#define HP_DEPOP_MODE3_EN                      (0x1<<10)\r
+#define HP_DEPOP_MODE2_EN                      (0x1<<9)\r
+#define HP_DEPOP_MODE1_EN                      (0x1<<8)\r
+#define AUXOUT_DEPOP_MODE3_EN          (0x1<<6)\r
+#define AUXOUT_DEPOP_MODE2_EN          (0x1<<5)\r
+#define AUXOUT_DEPOP_MODE1_EN          (0x1<<4)\r
+#define M_DAC_L_INPUT                          (0x1<<3)\r
+#define M_DAC_R_INPUT                          (0x1<<2)\r
+#define IRQOUT_INV_CTRL                                (0x1<<0)\r
+\r
+//Psedueo Stereo & Spatial Effect Block Control(0x60)\r
+#define SPATIAL_CTRL_EN                                (0x1<<15)\r
+#define ALL_PASS_FILTER_EN                     (0x1<<14)\r
+#define PSEUDO_STEREO_EN                       (0x1<<13)\r
+#define STEREO_EXPENSION_EN                    (0x1<<12)\r
+\r
+#define GAIN_3D_PARA_L_MASK                    (0x7<<9)\r
+#define GAIN_3D_PARA_L_1_00                    (0x0<<9)\r
+#define GAIN_3D_PARA_L_1_25                    (0x1<<9)\r
+#define GAIN_3D_PARA_L_1_50                    (0x2<<9)\r
+#define GAIN_3D_PARA_L_1_75                    (0x3<<9)\r
+#define GAIN_3D_PARA_L_2_00                    (0x4<<9)\r
+\r
+#define GAIN_3D_PARA_R_MASK                    (0x7<<6)\r
+#define GAIN_3D_PARA_R_1_00                    (0x0<<6)\r
+#define GAIN_3D_PARA_R_1_25                    (0x1<<6)\r
+#define GAIN_3D_PARA_R_1_50                    (0x2<<6)\r
+#define GAIN_3D_PARA_R_1_75                    (0x3<<6)\r
+#define GAIN_3D_PARA_R_2_00                    (0x4<<6)\r
+\r
+#define RATIO_3D_L_MASK                                (0x3<<4)\r
+#define RATIO_3D_L_0_0                         (0x0<<4)\r
+#define RATIO_3D_L_0_66                                (0x1<<4)\r
+#define RATIO_3D_L_1_0                         (0x2<<4)\r
+\r
+#define RATIO_3D_R_MASK                                (0x3<<2)\r
+#define RATIO_3D_R_0_0                         (0x0<<2)\r
+#define RATIO_3D_R_0_66                                (0x1<<2)\r
+#define RATIO_3D_R_1_0                         (0x2<<2)\r
+\r
+#define APF_MASK                                       (0x3)\r
+#define APF_FOR_48K                                    (0x3)\r
+#define APF_FOR_44_1K                          (0x2)\r
+#define APF_FOR_32K                                    (0x1)\r
+\r
+//EQ CONTROL(0x62)\r
+\r
+#define EN_HW_EQ_BLK                   (0x1<<15)               //HW EQ block control\r
+#define EN_HW_EQ_HPF_MODE              (0x1<<14)               //High Frequency shelving filter mode\r
+#define EN_HW_EQ_SOUR                  (0x1<<11)               //0:DAC PATH,1:ADC PATH\r
+#define EN_HW_EQ_HPF                   (0x1<<4)                //EQ High Pass Filter Control\r
+#define EN_HW_EQ_BP3                   (0x1<<3)                //EQ Band-3 Control\r
+#define EN_HW_EQ_BP2                   (0x1<<2)                //EQ Band-2 Control\r
+#define EN_HW_EQ_BP1                   (0x1<<1)                //EQ Band-1 Control\r
+#define EN_HW_EQ_LPF                   (0x1<<0)                //EQ Low Pass Filter Control\r
+\r
+//EQ Mode Change Enable(0x66)\r
+#define EQ_HPF_CHANGE_EN               (0x1<<4)                //EQ High Pass Filter Mode Change Enable\r
+#define EQ_BP3_CHANGE_EN               (0x1<<3)                //EQ Band-3 Pass Filter Mode Change Enable\r
+#define EQ_BP2_CHANGE_EN               (0x1<<2)                //EQ Band-2 Pass Filter Mode Change Enable\r
+#define EQ_BP1_CHANGE_EN               (0x1<<1)                //EQ Band-1 Pass Filter Mode Change Enable\r
+#define EQ_LPF_CHANGE_EN               (0x1<<0)                //EQ Low Pass Filter Mode Change Enable\r
+\r
+\r
+//AVC Control(0x68)\r
+#define AVC_ENABLE                             (0x1<<15)\r
+#define AVC_TARTGET_SEL_MASK   (0x1<<14)\r
+#define        AVC_TARTGET_SEL_R               (0x1<<14)\r
+#define        AVC_TARTGET_SEL_L               (0x0<<14)\r
+\r
+\r
+struct rt5621_setup_data {\r
+       unsigned short i2c_address;\r
+       unsigned short i2c_bus;\r
+};\r
+\r
+\r
+\r
+#define RT5621_PLL_FR_MCLK                     0\r
+#define RT5621_PLL_FR_BCLK                     1\r
+\r
+\r
+#define USE_DAPM_CONTROL 0\r
+#define REALTEK_HWDEP 0\r
+\r
+//WaveOut channel for realtek codec\r
+enum \r
+{\r
+       RT_WAVOUT_SPK                           =(0x1<<0),\r
+       RT_WAVOUT_SPK_R                         =(0x1<<1),\r
+       RT_WAVOUT_SPK_L                         =(0x1<<2),\r
+       RT_WAVOUT_HP                            =(0x1<<3),\r
+       RT_WAVOUT_HP_R                          =(0x1<<4),\r
+       RT_WAVOUT_HP_L                          =(0x1<<5),      \r
+       RT_WAVOUT_MONO                          =(0x1<<6),\r
+       RT_WAVOUT_AUXOUT                        =(0x1<<7),\r
+       RT_WAVOUT_AUXOUT_R                      =(0x1<<8),\r
+       RT_WAVOUT_AUXOUT_L                      =(0x1<<9),\r
+       RT_WAVOUT_LINEOUT                       =(0x1<<10),\r
+       RT_WAVOUT_LINEOUT_R                     =(0x1<<11),\r
+       RT_WAVOUT_LINEOUT_L                     =(0x1<<12),     \r
+       RT_WAVOUT_DAC                           =(0x1<<13),             \r
+       RT_WAVOUT_ALL_ON                        =(0x1<<14),\r
+};\r
+\r
+//WaveIn channel for realtek codec\r
+enum\r
+{\r
+       RT_WAVIN_R_MONO_MIXER           =(0x1<<0),\r
+       RT_WAVIN_R_SPK_MIXER            =(0x1<<1),\r
+       RT_WAVIN_R_HP_MIXER                     =(0x1<<2),\r
+       RT_WAVIN_R_PHONE                        =(0x1<<3),\r
+       RT_WAVIN_R_AUXIN                        =(0x1<<3),      \r
+       RT_WAVIN_R_LINE_IN                      =(0x1<<4),\r
+       RT_WAVIN_R_MIC2                         =(0x1<<5),\r
+       RT_WAVIN_R_MIC1                         =(0x1<<6),\r
+\r
+       RT_WAVIN_L_MONO_MIXER           =(0x1<<8),\r
+       RT_WAVIN_L_SPK_MIXER            =(0x1<<9),\r
+       RT_WAVIN_L_HP_MIXER                     =(0x1<<10),\r
+       RT_WAVIN_L_PHONE                        =(0x1<<11),\r
+       RT_WAVIN_L_AUXIN                        =(0x1<<11),\r
+       RT_WAVIN_L_LINE_IN                      =(0x1<<12),\r
+       RT_WAVIN_L_MIC2                         =(0x1<<13),\r
+       RT_WAVIN_L_MIC1                         =(0x1<<14),\r
+};\r
+\r
+enum \r
+{\r
+       POWER_STATE_D0=0,\r
+       POWER_STATE_D1,\r
+       POWER_STATE_D1_PLAYBACK,\r
+       POWER_STATE_D1_RECORD,\r
+       POWER_STATE_D2,\r
+       POWER_STATE_D2_PLAYBACK,\r
+       POWER_STATE_D2_RECORD,\r
+       POWER_STATE_D3,\r
+       POWER_STATE_D4\r
+\r
+}; \r
+\r
+#if REALTEK_HWDEP\r
+\r
+struct rt56xx_reg_state\r
+{\r
+       unsigned int reg_index;\r
+       unsigned int reg_value;\r
+};\r
+\r
+struct rt56xx_cmd\r
+{\r
+       size_t number;\r
+       struct rt56xx_reg_state __user *buf;            \r
+};\r
+\r
+enum \r
+{\r
+       RT_READ_CODEC_REG_IOCTL = _IOR('R', 0x01, struct rt56xx_cmd),\r
+       RT_READ_ALL_CODEC_REG_IOCTL = _IOR('R', 0x02, struct rt56xx_cmd),\r
+       RT_WRITE_CODEC_REG_IOCTL = _IOW('R', 0x03, struct rt56xx_cmd),\r
+};\r
+\r
+#endif\r
+\r
+extern struct snd_soc_dai rt5621_dai;  \r
+extern struct snd_soc_codec_device soc_codec_dev_rt5621;\r
+\r
+#endif\r
diff --git a/sound/soc/codecs/rt5631.c b/sound/soc/codecs/rt5631.c
new file mode 100644 (file)
index 0000000..00e6b86
--- /dev/null
@@ -0,0 +1,1556 @@
+/*
+ * rt5631.c  --  RT5631 ALSA Soc Audio driver
+ *
+ * Copyright 2009 Realtek Microelectronics
+ *
+ * Author: flove <flove@realtek.com>
+ *
+ * Based on WM8753.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <linux/spi/spi.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+
+#include "rt5631.h"
+
+#define RT5631_VERSION "0.01 alsa 1.0.21"
+#define ALSA_SOC_VERSION "1.0.21"
+static const u16 rt5631_reg[0x80];
+static int timesofbclk = 32;
+module_param(timesofbclk, int, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+MODULE_PARM_DESC(timeofbclk, "relationship between bclk and fs");
+       
+#define VIRTUAL_POWER_CONTROL 0x90
+/*
+ * bit0: spkl amp power
+ * bit1: spkr amp power
+ * bit2: dmic flag  
+ *  
+*/
+struct rt5631_priv {
+       int master;
+       int sysclk;
+       int dmic_used_flag;     
+};
+
+static unsigned int reg90;
+static int rt5631_write(struct snd_soc_codec *codec, unsigned int reg, unsigned int val);
+static unsigned int rt5631_read(struct snd_soc_codec *codec, unsigned int reg);
+#define rt5631_reset(c) rt5631_write(c, RT5631_RESET, 0)
+#define rt5631_write_mask(c, reg, val, mask) snd_soc_update_bits(c, reg, mask, val)
+static int rt5631_reg_init(struct snd_soc_codec *codec);
+
+static struct snd_soc_device *rt5631_socdev;
+/*
+ * read rt5631 register cache
+ */
+static inline unsigned int rt5631_read_reg_cache(struct snd_soc_codec *codec,
+       unsigned int reg)
+{
+       u16 *cache = codec->reg_cache;
+       if (reg < 1 || reg > (ARRAY_SIZE(rt5631_reg) + 1))
+               return -1;
+       return cache[reg];
+}
+
+
+/*
+ * write rt5631 register cache
+ */
+
+static inline void rt5631_write_reg_cache(struct snd_soc_codec *codec,
+       unsigned int reg, unsigned int value)
+{
+       u16 *cache = codec->reg_cache;
+       if (reg < 0 || reg > 0x7e)
+               return;
+       cache[reg] = value;
+}
+
+static int rt5631_write(struct snd_soc_codec *codec, unsigned int reg, unsigned int val)
+{
+       u8 data[3];
+       
+       if (reg > 0x7e) {
+               if (reg == 0x90) 
+                       reg90 = val;
+       }
+       
+       data[0] = reg;
+       data[1] = (0xff00 & val) >> 8;
+       data[2] = (0xff & val);
+       
+       if (codec->hw_write(codec->control_data, data, 3) == 3) {
+               rt5631_write_reg_cache(codec, reg, val);
+               printk(KERN_INFO "%s reg=0x%x, val=0x%x\n", __func__, reg, val);
+               return 0;       
+       } else {
+               printk(KERN_ERR "%s failed\n", __func__);
+               return -EIO;    
+       }
+}
+
+static unsigned int rt5631_read(struct snd_soc_codec *codec, unsigned int reg)
+{
+       u8 data[2] = {0};
+       unsigned int value = 0x0;
+       
+       if (reg > 0x7e) {
+               if (reg == 0x90)
+                    return reg90;
+       }
+       
+       data[0] = reg;
+       
+       i2c_master_reg8_recv(codec->control_data,reg,data,2,100 * 1000);        
+                     
+    value = (data[0]<<8) | data[1];         
+    
+    printk("rt5631_read reg%x=%x\n",reg,value);
+       
+    return value;      
+}
+
+#define rt5631_write_index_reg(c, addr, data) \
+{ \
+       rt5631_write(c, 0x6a, addr); \
+       rt5631_write(c, 0x6c, data); \
+}
+
+
+struct rt5631_init_reg{
+       u8 reg;
+       u16 val;
+};
+
+static struct rt5631_init_reg init_list[] = {
+
+       {RT5631_SPK_OUT_VOL                     , 0xc8c8},              //speaker channel volume select SPKMIXER,0DB by default
+       {RT5631_HP_OUT_VOL                      , 0xc0c0},              //Headphone channel volume select OUTMIXER,0DB by default
+       {RT5631_MONO_AXO_1_2_VOL        , 0xf0c0},              //AXO1/AXO2 channel volume select OUTMIXER,0DB by default
+       {RT5631_ADC_REC_MIXER           , 0xb0f0},              //Record Mixer source from Mic1 by default
+       {RT5631_MIC_CTRL_2                      , 0x5500},              //Mic1/Mic2 boost 40DB by default
+       {RT5631_OUTMIXER_L_CTRL         , 0xdfC0},              //DAC_L-->OutMixer_L by default
+       {RT5631_OUTMIXER_R_CTRL         , 0xdfC0},              //DAC_R-->OutMixer_R by default
+       {RT5631_AXO1MIXER_CTRL          , 0x8840},              //OutMixer_L-->AXO1Mixer by default
+       {RT5631_AXO2MIXER_CTRL          , 0x8880},              //OutMixer_R-->AXO2Mixer by default
+       {RT5631_SPK_MIXER_CTRL          , 0xd8d8},              //DAC-->SpeakerMixer
+       {RT5631_SPK_MONO_OUT_CTRL       , 0x6c00},              //Speaker volume-->SPOMixer(L-->L,R-->R)        
+       {RT5631_GEN_PUR_CTRL_REG        , 0x4e00},              //Speaker AMP ratio gain is 1.44X
+       {RT5631_SPK_MONO_HP_OUT_CTRL, 0x0000},          //HP from OutMixer,speaker out from SpeakerOut Mixer
+       {RT5631_DEPOP_FUN_CTRL_2        , 0x8000},              //HP depop by register control  
+       {RT5631_INT_ST_IRQ_CTRL_2       , 0x0f18},              //enable HP zero cross  
+       {RT5631_MIC_CTRL_1                      , 0x8000},              //set mic 1 to differnetial mode
+//     {RT5631_GPIO_CTRL                       , 0x0000},              //set GPIO to input pin 
+//     {RT5631_JACK_DET_CTRL           , 0x4e80},              //Jack detect for GPIO,high is HP,low is speaker        
+//     {RT5631_JACK_DET_CTRL           , 0x4bc0},              //Jack detect for GPIO,high is speaker,low is hp        
+};
+
+#define RT5631_INIT_REG_LEN    ARRAY_SIZE(init_list)
+
+static int rt5631_reg_init(struct snd_soc_codec *codec)
+{
+       int i;
+       
+       for (i = 0; i < RT5631_INIT_REG_LEN; i ++) {
+               rt5631_write(codec, init_list[i].reg, init_list[i].val);        
+       }       
+       
+       return 0;
+}
+
+static const char *rt5631_spol_source_sel[] = {"SPOLMIX", "MONOIN_RX", "VDAC", "DACL"};
+static const char *rt5631_spor_source_sel[] = {"SPORMIX", "MONOIN_RX", "VDAC", "DACR"};
+static const char *rt5631_mono_source_sel[] = {"MONOMIX", "MONOIN_RX", "VDAC"};
+static const char *rt5631_input_mode_source_sel[] = {"Single-end", "Differential"}; 
+static const char *rt5631_mic_boost[] = {"Bypass", "+20db", "+24db", "+30db",  
+                       "+35db", "+40db", "+44db", "+50db", "+52db"};
+
+static const struct soc_enum rt5631_enum[] = {
+SOC_ENUM_SINGLE(RT5631_SPK_MONO_HP_OUT_CTRL, 14, 4, rt5631_spol_source_sel),    /*0*/
+SOC_ENUM_SINGLE(RT5631_SPK_MONO_HP_OUT_CTRL, 10, 4, rt5631_spor_source_sel),   /*1*/
+SOC_ENUM_SINGLE(RT5631_SPK_MONO_HP_OUT_CTRL, 6, 3, rt5631_mono_source_sel),    /*2*/
+SOC_ENUM_SINGLE(RT5631_MIC_CTRL_1, 15, 2,  rt5631_input_mode_source_sel),      /*3*/
+SOC_ENUM_SINGLE(RT5631_MIC_CTRL_1, 7, 2,  rt5631_input_mode_source_sel),       /*4*/
+SOC_ENUM_SINGLE(RT5631_MONO_INPUT_VOL, 15, 2, rt5631_input_mode_source_sel),   /*5*/
+SOC_ENUM_SINGLE(RT5631_MIC_CTRL_2, 12, 9, rt5631_mic_boost),                   /*6*/
+SOC_ENUM_SINGLE(RT5631_MIC_CTRL_2, 8, 9, rt5631_mic_boost),                    /*7*/
+};
+
+static int rt5631_dmic_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       unsigned int val;
+
+       val = rt5631_read(codec, VIRTUAL_POWER_CONTROL) & 0x0004;
+       val >>= 2;
+       ucontrol->value.integer.value[0] = val;
+       return 0;
+}
+
+static void rt5631_close_dmic(struct snd_soc_codec *codec)     //disable DMic to ADC filter 
+{
+       rt5631_write_mask(codec, RT5631_DIG_MIC_CTRL, DMIC_L_CH_MUTE | DMIC_R_CH_MUTE, DMIC_L_CH_MUTE_MASK | DMIC_R_CH_MUTE_MASK); 
+
+       rt5631_write_mask(codec, RT5631_DIG_MIC_CTRL, DMIC_DIS, DMIC_ENA_MASK);
+}
+
+static int rt5631_dmic_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       unsigned int old, new;
+       struct rt5631_priv *rt5631 = codec->private_data;       
+
+       old = rt5631_read(codec, VIRTUAL_POWER_CONTROL) & 0x0004;
+       new = ucontrol->value.integer.value[0] << 2;
+
+       if (old == new)
+               return 0;
+
+       rt5631_write_mask(codec, VIRTUAL_POWER_CONTROL, new, 0x0004);
+
+       if (new)
+               rt5631->dmic_used_flag = 1;
+       else
+       {               
+               rt5631_close_dmic(codec);
+               rt5631->dmic_used_flag=0;
+       }
+
+       return 0;
+}
+
+static const struct snd_kcontrol_new rt5631_snd_controls[] = {
+SOC_ENUM("MIC1 Mode Control",  rt5631_enum[3]),   
+SOC_ENUM("MIC1 Boost", rt5631_enum[6]),
+
+SOC_ENUM("MIC2 Mode Control", rt5631_enum[4]),
+SOC_ENUM("MIC2 Boost", rt5631_enum[7]),
+SOC_ENUM("MONOIN Mode Control", rt5631_enum[5]),
+
+SOC_DOUBLE("PCM Playback Volume", RT5631_STEREO_DAC_VOL_2, 8, 0, 255, 1),
+SOC_DOUBLE("PCM Playback Switch", RT5631_STEREO_DAC_VOL_1,15, 7, 1, 1),
+
+SOC_DOUBLE("MONOIN_RX Capture Volume", RT5631_MONO_INPUT_VOL, 8, 0, 31, 1),
+
+SOC_DOUBLE("AXI Capture Volume", RT5631_AUX_IN_VOL, 8, 0, 31, 1),
+
+SOC_SINGLE("AXO1 Playback Switch", RT5631_MONO_AXO_1_2_VOL, 15, 1, 1),
+SOC_SINGLE("AXO2 Playback Switch", RT5631_MONO_AXO_1_2_VOL, 7, 1, 1),
+SOC_DOUBLE("OUTVOL Playback Volume", RT5631_MONO_AXO_1_2_VOL, 8, 0, 31, 1),
+
+SOC_DOUBLE("Speaker Playback Switch", RT5631_SPK_OUT_VOL,15, 7, 1, 1),
+SOC_DOUBLE("Speaker Playback Volume", RT5631_SPK_OUT_VOL, 8, 0, 63, 1),
+
+SOC_SINGLE("MONO Playback Switch", RT5631_MONO_AXO_1_2_VOL, 13, 1, 1),
+
+SOC_DOUBLE("HP Playback Switch", RT5631_HP_OUT_VOL,15, 7, 1, 1),
+SOC_DOUBLE("HP Playback Volume", RT5631_HP_OUT_VOL, 8, 0, 63, 1),
+
+//SOC_SINGLE_EXT("HIFI Loopback", ),/*not finished*/
+//SOC_SINGLE_EXT("Voice Loopback", ), /*not finished*/
+SOC_SINGLE_EXT("DMIC Capture Switch", VIRTUAL_POWER_CONTROL, 2, 1, 0, 
+       rt5631_dmic_get, rt5631_dmic_put),
+};
+
+static int rt5631_add_controls(struct snd_soc_codec *codec)
+{
+       int err, i;
+       
+       for (i = 0; i < ARRAY_SIZE(rt5631_snd_controls); i ++) {
+
+               err = snd_ctl_add(codec->card, 
+                                                               snd_soc_cnew(&rt5631_snd_controls[i],
+                                                                                               codec, NULL));
+               if (err < 0)
+                       return err;     
+       }       
+       
+       return 0;
+}
+
+static const struct snd_kcontrol_new rt5631_recmixl_mixer_controls[] = {
+SOC_DAPM_SINGLE("OUTMIXL Capture Switch", RT5631_ADC_REC_MIXER, 15, 1, 1),
+SOC_DAPM_SINGLE("MIC1_BST1 Capture Switch", RT5631_ADC_REC_MIXER, 14, 1, 1),
+SOC_DAPM_SINGLE("AXILVOL Capture Switch", RT5631_ADC_REC_MIXER, 13, 1, 1),
+SOC_DAPM_SINGLE("MONOIN_RX Capture Switch", RT5631_ADC_REC_MIXER, 12, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5631_recmixr_mixer_controls[] = {
+SOC_DAPM_SINGLE("MONOIN_RX Capture Switch", RT5631_ADC_REC_MIXER, 4, 1, 1),
+SOC_DAPM_SINGLE("AXIRVOL Capture Switch", RT5631_ADC_REC_MIXER, 5, 1, 1),
+SOC_DAPM_SINGLE("MIC2_BST2 Capture Switch", RT5631_ADC_REC_MIXER, 6, 1, 1),
+SOC_DAPM_SINGLE("OUTMIXR Capture Switch", RT5631_ADC_REC_MIXER, 7, 1, 1),
+};
+
+
+static const struct snd_kcontrol_new rt5631_spkmixl_mixer_controls[] = {
+SOC_DAPM_SINGLE("RECMIXL Playback Switch", RT5631_SPK_MIXER_CTRL, 15, 1, 1),
+SOC_DAPM_SINGLE("MIC1_P Playback Switch", RT5631_SPK_MIXER_CTRL, 14, 1, 1),    
+SOC_DAPM_SINGLE("DACL Playback Switch", RT5631_SPK_MIXER_CTRL, 13, 1, 1),
+SOC_DAPM_SINGLE("OUTMIXL Playback Switch", RT5631_SPK_MIXER_CTRL, 12, 1, 1)
+};
+
+static const struct snd_kcontrol_new rt5631_spkmixr_mixer_controls[] = {
+SOC_DAPM_SINGLE("OUTMIXR Playback Switch", RT5631_SPK_MIXER_CTRL, 4, 1, 1),
+SOC_DAPM_SINGLE("DACR Playback Switch", RT5631_SPK_MIXER_CTRL, 5, 1, 1),
+SOC_DAPM_SINGLE("MIC2_P Playback Switch", RT5631_SPK_MIXER_CTRL, 6, 1, 1),
+SOC_DAPM_SINGLE("RECMIXR Playback Switch", RT5631_SPK_MIXER_CTRL, 7, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5631_outmixl_mixer_controls[] = {
+SOC_DAPM_SINGLE("RECMIXL Playback Switch", RT5631_OUTMIXER_L_CTRL, 15, 1, 1),
+SOC_DAPM_SINGLE("RECMIXR Playback Switch", RT5631_OUTMIXER_L_CTRL, 14, 1, 1),
+SOC_DAPM_SINGLE("DACL Playback Switch", RT5631_OUTMIXER_L_CTRL, 13, 1, 1),
+SOC_DAPM_SINGLE("MIC1_BST1 Playback Switch", RT5631_OUTMIXER_L_CTRL, 12, 1, 1),
+SOC_DAPM_SINGLE("MIC2_BST2 Playback Switch", RT5631_OUTMIXER_L_CTRL, 11, 1, 1),
+SOC_DAPM_SINGLE("MONOIN_RXP Playback Switch", RT5631_OUTMIXER_L_CTRL, 10, 1, 1),
+SOC_DAPM_SINGLE("AXILVOL Playback Switch", RT5631_OUTMIXER_L_CTRL, 9, 1, 1),
+SOC_DAPM_SINGLE("AXIRVOL Playback Switch", RT5631_OUTMIXER_L_CTRL, 8, 1, 1),
+SOC_DAPM_SINGLE("VDAC Playback Switch", RT5631_OUTMIXER_L_CTRL, 7, 1, 1)
+};
+
+static const struct snd_kcontrol_new rt5631_outmixr_mixer_controls[] = {
+SOC_DAPM_SINGLE("VDAC Playback Switch", RT5631_OUTMIXER_R_CTRL, 7, 1, 1),
+SOC_DAPM_SINGLE("AXIRVOL Playback Switch", RT5631_OUTMIXER_R_CTRL, 8, 1, 1),
+SOC_DAPM_SINGLE("AXILVOL Playback Switch", RT5631_OUTMIXER_R_CTRL, 9, 1, 1),
+SOC_DAPM_SINGLE("MONOIN_RXN Playback Switch", RT5631_OUTMIXER_R_CTRL, 10, 1, 1),
+SOC_DAPM_SINGLE("MIC2_BST2 Playback Switch", RT5631_OUTMIXER_R_CTRL, 11, 1, 1),
+SOC_DAPM_SINGLE("MIC1_BST1 Playback Switch", RT5631_OUTMIXER_R_CTRL, 12, 1, 1),        
+SOC_DAPM_SINGLE("DACR Playback Switch", RT5631_OUTMIXER_R_CTRL, 13, 1, 1),
+SOC_DAPM_SINGLE("RECMIXR Playback Switch", RT5631_OUTMIXER_R_CTRL, 14, 1, 1),
+SOC_DAPM_SINGLE("RECMIXL Playback Switch", RT5631_OUTMIXER_R_CTRL, 15, 1, 1),
+};
+
+
+static const struct snd_kcontrol_new rt5631_AXO1MIX_mixer_controls[] = {
+SOC_DAPM_SINGLE("MIC1_BST1 Playback Switch", RT5631_AXO1MIXER_CTRL, 15 , 1, 1),
+SOC_DAPM_SINGLE("MIC2_BST2 Playback Switch", RT5631_AXO1MIXER_CTRL, 11, 1, 1),         
+SOC_DAPM_SINGLE("OUTVOLL Playback Switch", RT5631_AXO1MIXER_CTRL, 7 ,1 ,1),
+SOC_DAPM_SINGLE("OUTVOLR Playback Switch", RT5631_AXO1MIXER_CTRL, 6, 1, 1),
+};
+
+
+static const struct snd_kcontrol_new rt5631_AXO2MIX_mixer_controls[] = {
+SOC_DAPM_SINGLE("MIC1_BST1 Playback Switch", RT5631_AXO2MIXER_CTRL, 15, 1, 1),
+SOC_DAPM_SINGLE("MIC2_BST2 Playback Switch", RT5631_AXO2MIXER_CTRL, 11, 1, 1),  
+SOC_DAPM_SINGLE("OUTVOLL Playback Switch", RT5631_AXO2MIXER_CTRL, 7, 1, 1),
+SOC_DAPM_SINGLE("OUTVOLR Playback Switch", RT5631_AXO2MIXER_CTRL, 6, 1 ,1),            
+};
+
+static const struct snd_kcontrol_new rt5631_spolmix_mixer_controls[] = {
+SOC_DAPM_SINGLE("SPKVOLL Playback Switch", RT5631_SPK_MONO_OUT_CTRL, 15, 1, 1),
+SOC_DAPM_SINGLE("SPKVOLR Playback Switch", RT5631_SPK_MONO_OUT_CTRL, 14, 1, 1),        
+};
+
+
+static const struct snd_kcontrol_new rt5631_spormix_mixer_controls[] = {
+SOC_DAPM_SINGLE("SPKVOLL Playback Switch", RT5631_SPK_MONO_OUT_CTRL, 13, 1, 1),
+SOC_DAPM_SINGLE("SPKVOLR Playback Switch", RT5631_SPK_MONO_OUT_CTRL, 12, 1, 1),
+};
+
+
+static const struct snd_kcontrol_new rt5631_monomix_mixer_controls[] = {
+SOC_DAPM_SINGLE("OUTVOLL Playback Switch", RT5631_SPK_MONO_OUT_CTRL, 11, 1, 1),
+SOC_DAPM_SINGLE("OUTVOLR Playback Switch", RT5631_SPK_MONO_OUT_CTRL, 10, 1, 1),
+};
+
+
+static const struct snd_kcontrol_new rt5631_spol_mux_control = 
+SOC_DAPM_ENUM("Route", rt5631_enum[0]);
+static const struct snd_kcontrol_new rt5631_spor_mux_control = 
+SOC_DAPM_ENUM("Route", rt5631_enum[1]);
+static const struct snd_kcontrol_new rt5631_mono_mux_control = 
+SOC_DAPM_ENUM("Route", rt5631_enum[2]);
+
+
+
+static int spk_event(struct snd_soc_dapm_widget *w, 
+       struct snd_kcontrol *kcontrol, int event)
+{
+       struct snd_soc_codec *codec = w->codec;
+       unsigned int l, r;
+       
+       l = rt5631_read(codec, VIRTUAL_POWER_CONTROL) & 0x0001;
+       r = (rt5631_read(codec, VIRTUAL_POWER_CONTROL) & 0x0002) >> 1;
+       
+       switch (event) {
+       case SND_SOC_DAPM_POST_PMD:
+               printk("spk_event --SND_SOC_DAPM_POST_PMD\n");
+                       rt5631_write_mask(codec, RT5631_SPK_OUT_VOL, 0x8080, 0x8080);
+
+               if ((l == 0) && (r == 0))
+                       rt5631_write_mask(codec, RT5631_PWR_MANAG_ADD1, 0x0000, 0x1000);
+                       
+                       rt5631_write_mask(codec, RT5631_PWR_MANAG_ADD4, 0x0000, 0xC000);
+               break;
+       case SND_SOC_DAPM_POST_PMU:
+               printk("spk_event --SND_SOC_DAPM_POST_PMU\n");
+               if ((l != 0) || (r != 0))
+                       rt5631_write_mask(codec, RT5631_PWR_MANAG_ADD1, 0x1000, 0x1000);
+                       rt5631_write_mask(codec, RT5631_PWR_MANAG_ADD4, 0xC000, 0xC000);
+                       rt5631_write_mask(codec, RT5631_SPK_OUT_VOL, 0x0000, 0x8080);
+               break;
+       default:
+               return -EINVAL; 
+       }
+       
+       return 0;
+}
+
+
+static void hp_depop2(struct snd_soc_codec *codec,unsigned int EnableHPOut)
+{      
+
+       unsigned int SoftVol,HPZeroCross;
+
+       SoftVol = rt5631_read(codec, RT5631_SOFT_VOL_CTRL);
+       rt5631_write(codec,RT5631_SOFT_VOL_CTRL,0);
+       HPZeroCross=rt5631_read(codec, RT5631_INT_ST_IRQ_CTRL_2);
+       rt5631_write(codec,RT5631_INT_ST_IRQ_CTRL_2,HPZeroCross&0xf7ff);        //disable Zero Cross of HP
+       //enable HP out
+       if(EnableHPOut)
+       {               
+               
+               rt5631_write_index_reg(codec,0x56,0x303e);
+               
+               rt5631_write_mask(codec,RT5631_PWR_MANAG_ADD3,PWR_CHARGE_PUMP|PWR_HP_L_AMP|PWR_HP_R_AMP
+                                                                                                ,PWR_CHARGE_PUMP|PWR_HP_L_AMP|PWR_HP_R_AMP);                                                                                            
+               rt5631_write(codec,RT5631_DEPOP_FUN_CTRL_1,POW_ON_SOFT_GEN|EN_DEPOP2_FOR_HP);
+               schedule_timeout_uninterruptible(msecs_to_jiffies(100));        
+               rt5631_write_mask(codec,RT5631_PWR_MANAG_ADD3,PWR_HP_DEPOP_DIS|PWR_HP_AMP_DRIVING,PWR_HP_DEPOP_DIS|PWR_HP_AMP_DRIVING);
+       }
+       else    //disable HP out
+       {
+               rt5631_write_index_reg(codec,0x56,0x303F);      
+               rt5631_write(codec,RT5631_DEPOP_FUN_CTRL_1,POW_ON_SOFT_GEN|EN_MUTE_UNMUTE_DEPOP|PD_HPAMP_L_ST_UP|PD_HPAMP_R_ST_UP);
+               schedule_timeout_uninterruptible(msecs_to_jiffies(75));
+               rt5631_write(codec,RT5631_DEPOP_FUN_CTRL_1,POW_ON_SOFT_GEN|PD_HPAMP_L_ST_UP|PD_HPAMP_R_ST_UP);
+               rt5631_write_mask(codec,RT5631_PWR_MANAG_ADD3,0,PWR_HP_DEPOP_DIS|PWR_HP_AMP_DRIVING);   
+               rt5631_write(codec,RT5631_DEPOP_FUN_CTRL_1,POW_ON_SOFT_GEN|EN_DEPOP2_FOR_HP|PD_HPAMP_L_ST_UP|PD_HPAMP_R_ST_UP);
+               schedule_timeout_uninterruptible(msecs_to_jiffies(80)); 
+               rt5631_write(codec,RT5631_DEPOP_FUN_CTRL_1,POW_ON_SOFT_GEN);
+               rt5631_write_mask(codec,RT5631_PWR_MANAG_ADD3,0,PWR_CHARGE_PUMP|PWR_HP_L_AMP|PWR_HP_R_AMP);
+       }
+       
+       rt5631_write(codec,RT5631_SOFT_VOL_CTRL,SoftVol);
+       rt5631_write(codec,RT5631_INT_ST_IRQ_CTRL_2,HPZeroCross);       
+
+}
+
+static void HP_Mute_Unmute_Depop(struct snd_soc_codec *codec,unsigned int EnableHPOut)
+{
+
+       unsigned int SoftVol,HPZeroCross;
+
+       SoftVol = rt5631_read(codec, RT5631_SOFT_VOL_CTRL);
+       rt5631_write(codec,RT5631_SOFT_VOL_CTRL,0);
+       HPZeroCross=rt5631_read(codec, RT5631_INT_ST_IRQ_CTRL_2);
+       rt5631_write(codec,RT5631_INT_ST_IRQ_CTRL_2,HPZeroCross&0xf7ff);        //disable Zero Cross of HP
+
+       if(EnableHPOut) //unmute HP out
+       {
+               schedule_timeout_uninterruptible(msecs_to_jiffies(10));
+               rt5631_write_index_reg(codec,0x56,0x302f);                              
+               rt5631_write(codec,RT5631_DEPOP_FUN_CTRL_1,POW_ON_SOFT_GEN|EN_MUTE_UNMUTE_DEPOP|EN_HP_R_M_UN_MUTE_DEPOP|EN_HP_L_M_UN_MUTE_DEPOP);
+               rt5631_write_mask(codec,RT5631_HP_OUT_VOL,0x0000,0x8080);
+               schedule_timeout_uninterruptible(msecs_to_jiffies(160));        
+               
+       }
+       else            //mute HP out
+       {       
+               rt5631_write_index_reg(codec,0x56,0x302f);      
+               rt5631_write(codec,RT5631_DEPOP_FUN_CTRL_1,POW_ON_SOFT_GEN|EN_MUTE_UNMUTE_DEPOP|EN_HP_R_M_UN_MUTE_DEPOP|EN_HP_L_M_UN_MUTE_DEPOP);                               
+               rt5631_write_mask(codec,RT5631_HP_OUT_VOL,0x8080,0x8080);                       
+               schedule_timeout_uninterruptible(msecs_to_jiffies(150));
+       }
+       
+       rt5631_write(codec,RT5631_SOFT_VOL_CTRL,SoftVol);
+       rt5631_write(codec,RT5631_INT_ST_IRQ_CTRL_2,HPZeroCross);
+
+}
+
+static int open_hp_end_widgets(struct snd_soc_codec *codec)
+{
+       /*need to be fixed*/
+       /*
+       * 
+       *open hp last widget, e.g. power, switch
+       */
+
+       HP_Mute_Unmute_Depop(codec,1);
+
+       return 0;
+}
+
+static int close_hp_end_widgets(struct snd_soc_codec *codec)
+{
+       /*need to be fixed*/
+       /*
+       *
+       *close hp last widget, e.g. power, switch
+       */
+
+       HP_Mute_Unmute_Depop(codec,0);
+
+       return 0;
+}
+static int hp_event(struct snd_soc_dapm_widget *w, 
+       struct snd_kcontrol *kcontrol, int event)
+{
+       struct snd_soc_codec *codec = w->codec;
+       unsigned int l, r;
+       static unsigned int hp_out_enable=0;
+       
+       l = (rt5631_read(codec, RT5631_PWR_MANAG_ADD4) & (0x01 << 11)) >> 11;
+       r = (rt5631_read(codec, RT5631_PWR_MANAG_ADD4) & (0x01 << 10)) >> 10;
+       
+       switch (event) {
+       case SND_SOC_DAPM_PRE_PMD:
+               printk("hp_event --SND_SOC_DAPM_PRE_PMD\n");    
+               if ((l && r)&&(hp_out_enable))  
+               {
+                       close_hp_end_widgets(codec);
+                       hp_depop2(codec,0);     
+                       hp_out_enable=0;
+               }
+               break;
+       case SND_SOC_DAPM_POST_PMU:
+               printk("hp_event --SND_SOC_DAPM_POST_PMU\n");   
+               if ((l && r)&&(!hp_out_enable))
+               {
+                       hp_depop2(codec,1);
+               open_hp_end_widgets(codec);
+                       hp_out_enable=1;
+               }
+               break;
+       default:
+               return -EINVAL; 
+       }
+       
+       return 0;
+}
+
+
+static const struct snd_soc_dapm_widget rt5631_dapm_widgets[] = {
+
+SND_SOC_DAPM_INPUT("MIC1"),
+SND_SOC_DAPM_INPUT("MIC2"),
+SND_SOC_DAPM_INPUT("AXIL"),
+SND_SOC_DAPM_INPUT("AXIR"),
+SND_SOC_DAPM_INPUT("MONOIN_RXN"),
+SND_SOC_DAPM_INPUT("MONOIN_RXP"),
+
+
+SND_SOC_DAPM_PGA("Mic1 Boost", RT5631_PWR_MANAG_ADD2, 5, 0, NULL, 0),  
+
+SND_SOC_DAPM_PGA("Mic2 Boost", RT5631_PWR_MANAG_ADD2, 4, 0, NULL, 0), 
+
+SND_SOC_DAPM_PGA("MONOIN_RXP Boost", RT5631_PWR_MANAG_ADD4, 7, 0, NULL, 0), 
+SND_SOC_DAPM_PGA("MONOIN_RXN Boost", RT5631_PWR_MANAG_ADD4, 6, 0, NULL, 0), 
+
+SND_SOC_DAPM_PGA("AXIL Boost", RT5631_PWR_MANAG_ADD4, 9, 0, NULL, 0), 
+SND_SOC_DAPM_PGA("AXIR Boost", RT5631_PWR_MANAG_ADD4, 8, 0, NULL, 0),
+SND_SOC_DAPM_MIXER("MONO_IN", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+SND_SOC_DAPM_MIXER("RECMIXL Mixer", RT5631_PWR_MANAG_ADD2, 11, 0, 
+       &rt5631_recmixl_mixer_controls[0], ARRAY_SIZE(rt5631_recmixl_mixer_controls)),
+SND_SOC_DAPM_MIXER("RECMIXR Mixer", RT5631_PWR_MANAG_ADD2, 10, 0, 
+       &rt5631_recmixr_mixer_controls[0], ARRAY_SIZE(rt5631_recmixr_mixer_controls)),
+
+SND_SOC_DAPM_MIXER("ADC Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+SND_SOC_DAPM_ADC("Left ADC", "Left ADC HIFI Capture", RT5631_PWR_MANAG_ADD1, 11, 0),
+SND_SOC_DAPM_ADC("Right ADC", "Right ADC HIFI Capture", RT5631_PWR_MANAG_ADD1, 10, 0),
+SND_SOC_DAPM_DAC("Left DAC", "Left DAC HIFI Playback", RT5631_PWR_MANAG_ADD1, 9, 0),
+SND_SOC_DAPM_DAC("Right DAC", "Right DAC HIFI Playback", RT5631_PWR_MANAG_ADD1, 8, 0),
+SND_SOC_DAPM_DAC("Voice DAC", "Voice DAC Mono Playback", SND_SOC_NOPM, 0, 0),
+SND_SOC_DAPM_PGA("Voice DAC Boost", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+SND_SOC_DAPM_MIXER("SPKMIXL Mixer", RT5631_PWR_MANAG_ADD2, 13, 0, 
+       &rt5631_spkmixl_mixer_controls[0], ARRAY_SIZE(rt5631_spkmixl_mixer_controls)),
+SND_SOC_DAPM_MIXER("OUTMIXL Mixer", RT5631_PWR_MANAG_ADD2, 15, 0, 
+       &rt5631_outmixl_mixer_controls[0], ARRAY_SIZE(rt5631_outmixl_mixer_controls)),
+SND_SOC_DAPM_MIXER("OUTMIXR Mixer", RT5631_PWR_MANAG_ADD2, 14, 0, 
+       &rt5631_outmixr_mixer_controls[0], ARRAY_SIZE(rt5631_outmixr_mixer_controls)),
+SND_SOC_DAPM_MIXER("SPKMIXR Mixer", RT5631_PWR_MANAG_ADD2, 12, 0, 
+       &rt5631_spkmixr_mixer_controls[0], ARRAY_SIZE(rt5631_spkmixr_mixer_controls)),
+SND_SOC_DAPM_PGA("Left SPK Vol", RT5631_PWR_MANAG_ADD4, 15, 0, NULL, 0),
+SND_SOC_DAPM_PGA("Right SPK Vol", RT5631_PWR_MANAG_ADD4, 14, 0, NULL, 0),
+SND_SOC_DAPM_PGA_E("Left HP Vol", RT5631_PWR_MANAG_ADD4, 11, 0, NULL, 0,
+               hp_event, SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_E("Right HP Vol", RT5631_PWR_MANAG_ADD4, 10, 0, NULL, 0,
+               hp_event, SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA("Left Out Vol", RT5631_PWR_MANAG_ADD4, 13, 0, NULL, 0),
+SND_SOC_DAPM_PGA("Right Out Vol", RT5631_PWR_MANAG_ADD4, 12, 0, NULL, 0),
+
+SND_SOC_DAPM_MIXER("AXO1MIX Mixer", RT5631_PWR_MANAG_ADD3, 11, 0, 
+       &rt5631_AXO1MIX_mixer_controls[0], ARRAY_SIZE(rt5631_AXO1MIX_mixer_controls)),
+SND_SOC_DAPM_MIXER("SPOLMIX Mixer", SND_SOC_NOPM, 0, 0, 
+       &rt5631_spolmix_mixer_controls[0], ARRAY_SIZE(rt5631_spolmix_mixer_controls)),
+SND_SOC_DAPM_MIXER("MONOMIX Mixer", RT5631_PWR_MANAG_ADD3, 9, 0, 
+       &rt5631_monomix_mixer_controls[0], ARRAY_SIZE(rt5631_monomix_mixer_controls)),
+SND_SOC_DAPM_MIXER("SPORMIX Mixer", SND_SOC_NOPM, 0, 0, 
+       &rt5631_spormix_mixer_controls[0], ARRAY_SIZE(rt5631_spormix_mixer_controls)),
+SND_SOC_DAPM_MIXER("AXO2MIX Mixer", RT5631_PWR_MANAG_ADD3, 10, 0, 
+       &rt5631_AXO2MIX_mixer_controls[0], ARRAY_SIZE(rt5631_AXO2MIX_mixer_controls)), 
+
+
+SND_SOC_DAPM_MUX("SPOL Mux", SND_SOC_NOPM, 0, 0, &rt5631_spol_mux_control),
+SND_SOC_DAPM_MUX("SPOR Mux", SND_SOC_NOPM, 0, 0, &rt5631_spor_mux_control),
+SND_SOC_DAPM_MUX("Mono Mux", SND_SOC_NOPM, 0, 0, &rt5631_mono_mux_control),
+
+SND_SOC_DAPM_PGA("Mono Amp", RT5631_PWR_MANAG_ADD3, 7, 0, NULL, 0),
+
+
+SND_SOC_DAPM_PGA_E("SPKL Amp", VIRTUAL_POWER_CONTROL, 0, 0, NULL, 0,
+               spk_event, SND_SOC_DAPM_POST_PMD | SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_E("SPKR Amp", VIRTUAL_POWER_CONTROL, 1, 0, NULL, 0,
+               spk_event, SND_SOC_DAPM_POST_PMD | SND_SOC_DAPM_POST_PMU),
+
+SND_SOC_DAPM_MICBIAS("Mic Bias1", RT5631_PWR_MANAG_ADD2, 3, 0),
+SND_SOC_DAPM_MICBIAS("Mic Bias2", RT5631_PWR_MANAG_ADD2, 2, 0),
+
+SND_SOC_DAPM_OUTPUT("LOUT"),
+SND_SOC_DAPM_OUTPUT("ROUT"),
+SND_SOC_DAPM_OUTPUT("SPOL"),
+SND_SOC_DAPM_OUTPUT("SPOR"),
+SND_SOC_DAPM_OUTPUT("HPOL"),
+SND_SOC_DAPM_OUTPUT("HPOR"),
+SND_SOC_DAPM_OUTPUT("MONO"),
+
+};
+
+
+static const struct snd_soc_dapm_route audio_map[] = {
+
+       {"Mic1 Boost", NULL, "MIC1"},
+       {"Mic2 Boost", NULL, "MIC2"},
+       {"MONOIN_RXP Boost", NULL, "MONOIN_RXP"},
+       {"MONOIN_RXN Boost", NULL, "MONOIN_RXN"},
+       {"AXIL Boost", NULL, "AXIL"},
+       {"AXIR Boost", NULL, "AXIR"},
+
+       {"MONO_IN", NULL, "MONOIN_RXP Boost"},
+       {"MONO_IN", NULL, "MONOIN_RXN Boost"},
+
+       {"RECMIXL Mixer", "OUTMIXL Capture Switch", "OUTMIXL Mixer"},
+       {"RECMIXL Mixer", "MIC1_BST1 Capture Switch", "Mic1 Boost"},
+       {"RECMIXL Mixer", "AXILVOL Capture Switch", "AXIL Boost"},
+       {"RECMIXL Mixer", "MONOIN_RX Capture Switch", "MONO_IN"},
+
+       {"RECMIXR Mixer", "OUTMIXR Capture Switch", "OUTMIXR Mixer"},
+       {"RECMIXR Mixer", "MIC2_BST2 Capture Switch", "Mic2 Boost"},
+       {"RECMIXR Mixer", "AXIRVOL Capture Switch", "AXIR Boost"},
+       {"RECMIXR Mixer", "MONOIN_RX Capture Switch", "MONO_IN"},
+
+       {"ADC Mixer", NULL, "RECMIXL Mixer"},
+       {"ADC Mixer", NULL, "RECMIXR Mixer"},
+       {"Left ADC", NULL, "ADC Mixer"},
+       {"Right ADC", NULL,"ADC Mixer"},        
+
+       {"Voice DAC Boost", NULL, "Voice DAC"},
+
+       {"SPKMIXL Mixer", "RECMIXL Playback Switch", "RECMIXL Mixer"},
+       {"SPKMIXL Mixer", "MIC1_P Playback Switch", "MIC1"},
+       {"SPKMIXL Mixer", "DACL Playback Switch", "Left DAC"},
+       {"SPKMIXL Mixer", "OUTMIXL Playback Switch", "OUTMIXL Mixer"},
+
+       {"SPKMIXR Mixer", "OUTMIXR Playback Switch", "OUTMIXR Mixer"},
+       {"SPKMIXR Mixer", "DACR Playback Switch", "Right DAC"},
+       {"SPKMIXR Mixer", "MIC2_P Playback Switch", "MIC2"},
+       {"SPKMIXR Mixer", "RECMIXR Playback Switch", "RECMIXR Mixer"},
+
+
+       {"OUTMIXL Mixer", "RECMIXL Playback Switch", "RECMIXL Mixer"},
+       {"OUTMIXL Mixer", "RECMIXR Playback Switch", "RECMIXR Mixer"},
+       {"OUTMIXL Mixer", "DACL Playback Switch", "Left DAC"},
+       {"OUTMIXL Mixer", "MIC1_BST1 Playback Switch", "Mic1 Boost"},
+       {"OUTMIXL Mixer", "MIC2_BST2 Playback Switch", "Mic2 Boost"},
+       {"OUTMIXL Mixer", "MONOIN_RXP Playback Switch", "MONOIN_RXP Boost"},
+       {"OUTMIXL Mixer", "AXILVOL Playback Switch", "AXIL Boost"},
+       {"OUTMIXL Mixer", "AXIRVOL Playback Switch", "AXIR Boost"},
+       {"OUTMIXL Mixer", "VDAC Playback Switch", "Voice DAC Boost"},
+
+       {"OUTMIXR Mixer", "RECMIXL Playback Switch", "RECMIXL Mixer"},
+       {"OUTMIXR Mixer", "RECMIXR Playback Switch", "RECMIXR Mixer"},
+       {"OUTMIXR Mixer", "DACR Playback Switch", "Right DAC"},
+       {"OUTMIXR Mixer", "MIC1_BST1 Playback Switch", "Mic1 Boost"},
+       {"OUTMIXR Mixer", "MIC2_BST2 Playback Switch", "Mic2 Boost"},
+       {"OUTMIXR Mixer", "MONOIN_RXN Playback Switch", "MONOIN_RXN Boost"},
+       {"OUTMIXR Mixer", "AXILVOL Playback Switch", "AXIL Boost"},
+       {"OUTMIXR Mixer", "AXIRVOL Playback Switch", "AXIR Boost"},
+       {"OUTMIXR Mixer", "VDAC Playback Switch", "Voice DAC Boost"},
+
+       {"Left SPK Vol",  NULL, "SPKMIXL Mixer"},
+       {"Right SPK Vol",  NULL, "SPKMIXR Mixer"},
+       {"Left HP Vol",  NULL, "OUTMIXL Mixer"},
+       {"Left Out Vol",  NULL, "OUTMIXL Mixer"},
+       {"Right Out Vol",  NULL, "OUTMIXR Mixer"},
+       {"Right HP Vol",  NULL, "OUTMIXR Mixer"},
+
+
+       {"AXO1MIX Mixer", "MIC1_BST1 Playback Switch", "Mic1 Boost"},
+       {"AXO1MIX Mixer", "OUTVOLL Playback Switch", "Left Out Vol"},
+       {"AXO1MIX Mixer", "OUTVOLR Playback Switch", "Right Out Vol"},
+       {"AXO1MIX Mixer", "MIC2_BST2 Playback Switch", "Mic2 Boost"},
+
+
+       {"AXO2MIX Mixer", "MIC1_BST1 Playback Switch", "Mic1 Boost"},
+       {"AXO2MIX Mixer", "OUTVOLL Playback Switch", "Left Out Vol"},
+       {"AXO2MIX Mixer", "OUTVOLR Playback Switch", "Right Out Vol"},
+       {"AXO2MIX Mixer", "MIC2_BST2 Playback Switch", "Mic2 Boost"},
+
+
+       {"SPOLMIX Mixer", "SPKVOLL Playback Switch", "Left SPK Vol"},
+       {"SPOLMIX Mixer", "SPKVOLR Playback Switch", "Right SPK Vol"},
+
+       {"SPORMIX Mixer", "SPKVOLL Playback Switch", "Left SPK Vol"},
+       {"SPORMIX Mixer", "SPKVOLR Playback Switch", "Right SPK Vol"},
+
+
+       {"MONOMIX Mixer", "OUTVOLL Playback Switch", "Left Out Vol"},
+       {"MONOMIX Mixer", "OUTVOLR Playback Switch", "Right Out Vol"},
+
+
+
+       {"SPOL Mux", "SPOLMIX", "SPOLMIX Mixer"},
+       {"SPOL Mux", "MONOIN_RX", "MONO_IN"},
+       {"SPOL Mux", "VDAC", "Voice DAC Boost"},
+       {"SPOL Mux", "DACL", "Left DAC"},
+
+       {"SPOR Mux", "SPORMIX", "SPORMIX Mixer"},
+       {"SPOR Mux", "MONOIN_RX", "MONO_IN"},
+       {"SPOR Mux", "VDAC", "Voice DAC Boost"},
+       {"SPOR Mux", "DACR", "Right DAC"},
+       
+       {"Mono Mux", "MONOMIX", "MONOMIX Mixer"},
+       {"Mono Mux", "MONOIN_RX", "MONO_IN"},
+       {"Mono Mux", "VDAC", "Voice DAC Boost"},
+
+       {"SPKL Amp", NULL, "SPOL Mux"},
+       {"SPKR Amp", NULL, "SPOR Mux"},
+       {"Mono Amp", NULL, "Mono Mux"},
+       
+       {"LOUT", NULL, "AXO1MIX Mixer"},
+       {"ROUT", NULL, "AXO2MIX Mixer"},
+       {"SPOL", NULL, "SPKL Amp"},
+       {"SPOR", NULL, "SPKR Amp"},
+       {"HPOL", NULL, "Left HP Vol"},
+       {"HPOR", NULL, "Right HP Vol"},
+       {"MONO", NULL, "Mono Amp"}
+
+};
+
+static int rt5631_add_widgets(struct snd_soc_codec *codec)
+{
+       snd_soc_dapm_new_controls(codec, rt5631_dapm_widgets,
+                                               ARRAY_SIZE(rt5631_dapm_widgets));
+       snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
+       snd_soc_dapm_new_widgets(codec);
+
+       return 0;
+}
+
+struct _coeff_div{
+       unsigned int mclk;       //pllout or MCLK
+       unsigned int bclk;       //master mode
+       unsigned int rate;
+       unsigned int reg_val;
+};
+/*PLL divisors*/
+struct _pll_div {
+       u32 pll_in;
+       u32 pll_out;
+       u16 regvalue;
+};
+
+static const struct _pll_div codec_master_pll_div[] = {
+       
+       {  2048000,  8192000,   0x0ea0},                
+       {  3686400,  8192000,   0x4e27},        
+       { 12000000,  8192000,   0x456b},   
+       { 13000000,  8192000,   0x495f},
+       { 13100000,      8192000,       0x0320},        
+       {  2048000,  11289600,  0xf637},
+       {  3686400,  11289600,  0x2f22},        
+       { 12000000,  11289600,  0x3e2f},   
+       { 13000000,  11289600,  0x4d5b},
+       { 13100000,      11289600,      0x363b},        
+       {  2048000,  16384000,  0x1ea0},
+       {  3686400,  16384000,  0x9e27},        
+       { 12000000,  16384000,  0x452b},   
+       { 13000000,  16384000,  0x542f},
+       { 13100000,      16384000,      0x03a0},        
+       {  2048000,  16934400,  0xe625},
+       {  3686400,  16934400,  0x9126},        
+       { 12000000,  16934400,  0x4d2c},   
+       { 13000000,  16934400,  0x742f},
+       { 13100000,      16934400,      0x3c27},                        
+       {  2048000,  22579200,  0x2aa0},
+       {  3686400,  22579200,  0x2f20},        
+       { 12000000,  22579200,  0x7e2f},   
+       { 13000000,  22579200,  0x742f},
+       { 13100000,      22579200,      0x3c27},                
+       {  2048000,  24576000,  0x2ea0},
+       {  3686400,  24576000,  0xee27},        
+       { 12000000,  24576000,  0x2915},   
+       { 13000000,  24576000,  0x772e},
+       { 13100000,      24576000,      0x0d20},        
+       { 26000000,  24576000,  0x2027},
+       { 26000000,  22579200,  0x392f},        
+       { 24576000,  22579200,  0x0921},        
+       { 24576000,  24576000,  0x02a0},        
+};
+
+static const struct _pll_div codec_slave_pll_div[] = {
+       {   256000,   4096000,  0x3ea0},
+       {       352800,   5644800,      0x3ea0},
+       {       512000,   8192000,      0x3ea0},
+       {       705600,  11289600,      0x3ea0},
+       {  1024000,  16384000,  0x3ea0},        
+       {  1411200,  22579200,  0x3ea0},
+       {  1536000,      24576000,      0x3ea0},        
+       {  2048000,  16384000,  0x1ea0},        
+       {  2822400,  22579200,  0x1ea0},
+       {  3072000,      24576000,      0x1ea0},
+       {       705600,  11289600,      0x3ea0},
+       { 705600,         8467200,      0x3ab0},
+                       
+};
+
+struct _coeff_div coeff_div[] = {
+       //sysclk is 256fs
+       { 2048000,  8000 * 32,  8000, 0x1000},
+       { 2048000,  8000 * 64,  8000, 0x0000},
+       { 2822400, 11025 * 32, 11025, 0x1000},
+       { 2822400, 11025 * 64, 11025, 0x0000},
+       { 4096000, 16000 * 32, 16000, 0x1000},
+       { 4096000, 16000 * 64, 16000, 0x0000},
+       { 5644800, 22050 * 32, 22050, 0x1000},
+       { 5644800, 22050 * 64, 22050, 0x0000},  
+       { 8192000, 32000 * 32, 32000, 0x1000},
+       { 8192000, 32000 * 64, 32000, 0x0000},
+       {11289600, 44100 * 32, 44100, 0x1000},
+       {11289600, 44100 * 64, 44100, 0x0000},
+       {12288000, 48000 * 32, 48000, 0x1000},
+       {12288000, 48000 * 64, 48000, 0x0000},
+       //sysclk is 512fs
+       { 4096000,  8000 * 32,  8000, 0x3000},
+       { 4096000,  8000 * 64,  8000, 0x2000},
+       { 5644800, 11025 * 32, 11025, 0x3000},
+       { 5644800, 11025 * 64, 11025, 0x2000},
+       { 8192000, 16000 * 32, 16000, 0x3000},
+       { 8192000, 16000 * 64, 16000, 0x2000},
+       {11289600, 22050 * 32, 22050, 0x3000},
+       {11289600, 22050 * 64, 22050, 0x2000},  
+       {16384000, 32000 * 32, 32000, 0x3000},
+       {16384000, 32000 * 64, 32000, 0x2000},
+       {22579200, 44100 * 32, 44100, 0x3000},
+       {22579200, 44100 * 64, 44100, 0x2000},
+       {24576000, 48000 * 32, 48000, 0x3000},
+       {24576000, 48000 * 64, 48000, 0x2000},
+       //sysclk is 24.576Mhz or 22.579200Mhz
+       {24576000,  8000 * 32,  8000, 0x7080},
+       {24576000,  8000 * 64,  8000, 0x6080},
+       {24576000, 16000 * 32, 16000, 0x5080},
+       {24576000, 16000 * 64, 16000, 0x4080},
+       {24576000, 24000 * 32, 24000, 0x5000},
+       {24576000, 24000 * 64, 24000, 0x4000},
+       {24576000, 32000 * 32, 32000, 0x3080},
+       {24576000, 32000 * 64, 32000, 0x2080},  
+       
+       {22579200, 11025 * 32, 11025, 0x7000},
+       {22579200, 11025 * 64, 11025, 0x6000},
+       {22579200, 22050 * 32, 22050, 0x5000},
+       {22579200, 22050 * 64, 22050, 0x4000},                                  
+       
+};
+
+
+
+
+static int get_coeff(int mclk, int rate, int timesofbclk)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(coeff_div); i++) {
+               if ((coeff_div[i].mclk == mclk) 
+                               && (coeff_div[i].rate == rate)
+                               && ((coeff_div[i].bclk / coeff_div[i].rate) == timesofbclk))
+                               return i;
+       }
+
+               return -1;
+}
+
+static int get_coeff_in_slave_mode(int mclk, int rate)
+{
+       return get_coeff(mclk, rate, timesofbclk);
+}
+
+static int get_coeff_in_master_mode(int mclk, int rate, int bclk)
+{
+       return get_coeff(mclk, rate, (bclk / rate));    
+}
+static void rt5631_set_dmic_params(struct snd_soc_codec *codec, struct snd_pcm_hw_params *params)
+{
+//     struct rt5631_priv *rt5631 = codec->private_data;
+
+       unsigned int rate;
+
+       printk(KERN_DEBUG "enter %s\n", __func__);      
+       rt5631_write_mask(codec, RT5631_GPIO_CTRL, GPIO_PIN_FUN_SEL_GPIO_DIMC|GPIO_DMIC_FUN_SEL_DIMC
+                                                                                        , GPIO_PIN_FUN_SEL_MASK|GPIO_DMIC_FUN_SEL_MASK);
+       rt5631_write_mask(codec, RT5631_DIG_MIC_CTRL, DMIC_ENA, DMIC_ENA_MASK);
+       rt5631_write_mask(codec, RT5631_DIG_MIC_CTRL,DMIC_L_CH_LATCH_FALLING|DMIC_R_CH_LATCH_RISING
+                                                                                               ,DMIC_L_CH_LATCH_MASK|DMIC_R_CH_LATCH_MASK);
+
+       rate = params_rate(params);
+       switch (rate) {
+       case 44100:
+       case 48000:
+               rt5631_write_mask(codec, RT5631_DIG_MIC_CTRL, DMIC_CLK_CTRL_TO_32FS, DMIC_CLK_CTRL_MASK);
+               break;
+       case 32000:
+       case 22050:
+               rt5631_write_mask(codec, RT5631_DIG_MIC_CTRL, DMIC_CLK_CTRL_TO_64FS, DMIC_CLK_CTRL_MASK);
+               break;
+       case 16000:
+       case 11025:
+       case 8000: 
+               rt5631_write_mask(codec, RT5631_DIG_MIC_CTRL, DMIC_CLK_CTRL_TO_128FS, DMIC_CLK_CTRL_MASK);
+               break;
+       }
+       
+       rt5631_write_mask(codec, RT5631_DIG_MIC_CTRL, 
+               DMIC_L_CH_UNMUTE | DMIC_R_CH_UNMUTE, DMIC_L_CH_MUTE_MASK | DMIC_R_CH_MUTE_MASK);
+       
+}
+
+static int rt5631_hifi_pcm_params(struct snd_pcm_substream *substream, 
+                       struct snd_pcm_hw_params *params,
+                       struct snd_soc_dai *dai)
+{
+//     struct snd_soc_codec *codec = dai->codec;
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_device *socdev = rtd->socdev;
+       struct snd_soc_codec *codec = socdev->card->codec;
+       struct rt5631_priv *rt5631 = codec->private_data;
+       int stream = substream->stream;
+       unsigned int iface = 0;
+       int rate = params_rate(params);
+       int coeff = 0;
+       unsigned int CodecRegData;
+       
+       printk(KERN_DEBUG "enter %s\n", __func__);      
+
+       if (!rt5631->master)
+               coeff = get_coeff_in_slave_mode(rt5631->sysclk, rate);
+       else
+               coeff = get_coeff_in_master_mode(rt5631->sysclk, rate, rate * timesofbclk);
+
+       if (coeff < 0) {
+               printk(KERN_ERR "%s get_coeff err!\n", __func__);
+       //      return -EINVAL;
+       }
+
+       switch (params_format(params))
+       {
+               case SNDRV_PCM_FORMAT_S16_LE:
+                       break;
+               case SNDRV_PCM_FORMAT_S20_3LE:
+                       iface |= 0x0004;
+                       break;
+               case SNDRV_PCM_FORMAT_S24_LE:
+                       iface |= 0x0008;
+                       break;
+               case SNDRV_PCM_FORMAT_S8:
+                       iface |= 0x000c;
+                       break;
+               default:
+                       return -EINVAL;
+       }
+
+       if (stream == SNDRV_PCM_STREAM_CAPTURE) {
+               if (rt5631->dmic_used_flag)     //use Digital Mic 
+                       rt5631_set_dmic_params(codec, params);
+               else    //use Analog Mic
+               {
+                       CodecRegData=rt5631_read(codec,RT5631_ADC_REC_MIXER);
+                       if((CodecRegData&0x4040)==0)    //use stereo mic from mic1&mic2,no copy ADC channel
+                       {
+                               rt5631_write_mask(codec, RT5631_INT_ST_IRQ_CTRL_2, 0x0000, 0xc000);
+                       }
+                       else if((CodecRegData&0x4000)==0) //use mic1,copy ADC left to right
+                       {
+                               rt5631_write_mask(codec, RT5631_INT_ST_IRQ_CTRL_2, 0x4000, 0xc000);
+                       }
+                       else if((CodecRegData&0x0040)==0)//use mic2,copy ADC right to left      
+                       {
+                               rt5631_write_mask(codec, RT5631_INT_ST_IRQ_CTRL_2, 0x8000, 0xc000);
+                       }
+                       else
+                       {
+                                       rt5631_write_mask(codec, RT5631_INT_ST_IRQ_CTRL_2, 0x0000, 0xc000);
+                       }
+                       
+               }       
+       }
+       
+       rt5631_write_mask(codec, RT5631_SDP_CTRL, iface, SDP_I2S_DL_MASK);
+
+       if(coeff>=0)
+       rt5631_write(codec, RT5631_STEREO_AD_DA_CLK_CTRL, coeff_div[coeff].reg_val);
+
+
+       rt5631_write_mask(codec, RT5631_PWR_MANAG_ADD1, 0x80e0, 0x80e0);
+
+return 0;
+}
+
+static int rt5631_hifi_codec_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+       struct rt5631_priv *rt5631 = codec->private_data;
+       u16 iface = 0;
+       
+       printk(KERN_DEBUG "enter %s\n", __func__);      
+       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+       case SND_SOC_DAIFMT_CBM_CFM:
+               rt5631->master = 1;
+               break;
+       case SND_SOC_DAIFMT_CBS_CFS:
+               iface |= (0x0001 << 15);
+               rt5631->master = 0;
+               break;
+       default:
+               return -EINVAL;
+       }
+       
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_I2S:
+               break;
+       case SND_SOC_DAIFMT_LEFT_J:
+               iface |= (0x0001);
+               break;
+       case SND_SOC_DAIFMT_DSP_A:
+               iface |= (0x0002);
+               break;
+       case SND_SOC_DAIFMT_DSP_B:
+               iface  |= (0x0003);
+               break;
+       default:
+               return -EINVAL;
+       }
+       
+       switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+       case SND_SOC_DAIFMT_NB_NF:
+               break;
+       case SND_SOC_DAIFMT_IB_NF:
+               iface |= (0x0001 << 7);
+               break;
+       default:
+               return -EINVAL; 
+       }
+       
+       rt5631_write(codec, RT5631_SDP_CTRL, iface);
+
+       return 0;
+}
+static int rt5631_hifi_codec_set_dai_sysclk(struct snd_soc_dai *codec_dai, 
+               int clk_id, unsigned int freq, int dir)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+       struct rt5631_priv *rt5631 = codec->private_data;
+       
+       printk(KERN_DEBUG "enter %s\n", __func__);      
+       if ((freq >= (256 * 8000)) && (freq <= (512 * 48000))) {
+               rt5631->sysclk = freq;
+               return 0;       
+       }
+       
+       printk("unsupported sysclk freq %u for audio i2s\n", freq);
+       printk("Set sysclk to 24.576Mhz by default\n"); 
+
+       rt5631->sysclk = 24576000;
+       return 0;       
+       //return -EINVAL;
+}
+
+static int rt5631_codec_set_dai_pll(struct snd_soc_dai *codec_dai, 
+               int pll_id, unsigned int freq_in, unsigned int freq_out)
+{
+       struct snd_soc_codec *codec = codec_dai->codec; 
+       struct rt5631_priv *rt5631 = codec->private_data;
+       int i;
+       int ret = -EINVAL;
+       
+       
+       printk(KERN_DEBUG "enter %s\n", __func__);      
+//     rt5631_write_mask(codec, RT5631_PWR_MANAG_ADD2, 0, PWR_PLL);
+
+       if (!freq_in || !freq_out)
+               return 0;
+               
+       if (rt5631->master) {
+               for (i = 0; i < ARRAY_SIZE(codec_master_pll_div); i ++) {
+
+                       if ((freq_in == codec_master_pll_div[i].pll_in) && (freq_out == codec_master_pll_div[i].pll_out)) {
+
+                               rt5631_write(codec, RT5631_PLL_CTRL, codec_master_pll_div[i].regvalue);
+                               rt5631_write_mask(codec, RT5631_PWR_MANAG_ADD2, PWR_PLL, PWR_PLL);
+                               schedule_timeout_uninterruptible(msecs_to_jiffies(20));
+                               rt5631_write(codec, RT5631_GLOBAL_CLK_CTRL, 0x4000);    
+                               ret = 0;
+
+                       }
+
+               }       
+       } else {
+
+               for (i = 0; i < ARRAY_SIZE(codec_slave_pll_div); i ++) {
+
+                       if ((freq_in == codec_slave_pll_div[i].pll_in) && (freq_out == codec_slave_pll_div[i].pll_out))  {
+
+                               rt5631_write(codec, RT5631_PLL_CTRL, codec_slave_pll_div[i].regvalue);
+                               rt5631_write_mask(codec, RT5631_PWR_MANAG_ADD2, PWR_PLL, PWR_PLL);
+                               schedule_timeout_uninterruptible(msecs_to_jiffies(20));
+                               rt5631_write(codec, RT5631_GLOBAL_CLK_CTRL, 0x5000);
+                               ret = 0;
+
+                       }
+
+               }
+       }
+       
+       return 0;
+}
+
+static void rt5631_hifi_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *codec_dai)
+{
+               
+}
+
+#define RT5631_STEREO_RATES            (SNDRV_PCM_RATE_8000_48000)
+#define RT5631_FORMAT                  (SNDRV_PCM_FMTBIT_S16_LE |\
+                       SNDRV_PCM_FMTBIT_S20_3LE |\
+                       SNDRV_PCM_FMTBIT_S24_LE |\
+                       SNDRV_PCM_FMTBIT_S8)
+
+struct snd_soc_dai_ops rt5631_ops = {
+                       .hw_params = rt5631_hifi_pcm_params,
+                       .set_fmt = rt5631_hifi_codec_set_dai_fmt,
+                       .set_sysclk = rt5631_hifi_codec_set_dai_sysclk,
+                       .set_pll = rt5631_codec_set_dai_pll,
+                       .shutdown = rt5631_hifi_shutdown,       
+};
+                       
+struct snd_soc_dai rt5631_dai[] = { 
+       {
+               .name = "RT5631 HIFI",
+               .id = 1,
+               .playback = {
+                       .stream_name = "HIFI Playback",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = RT5631_STEREO_RATES,
+                       .formats = RT5631_FORMAT,       
+               }       ,
+               .capture = {
+                       .stream_name = "HIFI Capture",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = RT5631_STEREO_RATES,   
+                       .formats = RT5631_FORMAT,
+               },
+               .ops =&rt5631_ops,
+       },
+       
+       {
+               .name = "RT5631 Reserved",
+               .id = 2,
+       }
+};
+
+EXPORT_SYMBOL_GPL(rt5631_dai);
+
+static int rt5631_set_bias_level(struct snd_soc_codec *codec, enum snd_soc_bias_level level)
+{
+       printk(KERN_DEBUG "enter %s\n", __func__);
+
+       printk("rt5631_set_bias_level=%d\n",level);     
+
+       switch (level) {
+       case SND_SOC_BIAS_ON:
+               break;
+       case SND_SOC_BIAS_PREPARE:
+               rt5631_write_mask(codec, RT5631_PWR_MANAG_ADD3,PWR_VREF|PWR_MAIN_BIAS, PWR_VREF|PWR_MAIN_BIAS);
+               rt5631_write_mask(codec, RT5631_PWR_MANAG_ADD2,0x000c, 0x000c); 
+               break;
+       case SND_SOC_BIAS_STANDBY:
+
+               break;
+       case SND_SOC_BIAS_OFF:
+               rt5631_write_mask(codec, RT5631_SPK_OUT_VOL     ,0x8080, 0x8080);
+               rt5631_write_mask(codec, RT5631_HP_OUT_VOL      ,0x8080, 0x8080);
+               rt5631_write(codec, RT5631_PWR_MANAG_ADD1, 0x0000);
+               rt5631_write(codec, RT5631_PWR_MANAG_ADD2, 0x0000);
+               rt5631_write(codec, RT5631_PWR_MANAG_ADD3, 0x0000);
+               rt5631_write(codec, RT5631_PWR_MANAG_ADD4, 0x0000);
+               break;
+       }
+       
+       codec->bias_level = level;
+       return 0;
+}
+
+static int rt5631_init(struct snd_soc_device *socdev)
+{
+       struct snd_soc_codec *codec = socdev->card->codec;
+       int ret;
+       
+       printk(KERN_DEBUG "enter %s\n", __func__);      
+       codec->name = "RT5631";
+       codec->owner = THIS_MODULE;
+       codec->read = rt5631_read;
+       codec->write = rt5631_write;
+       codec->set_bias_level = rt5631_set_bias_level;
+       codec->dai = rt5631_dai;
+       codec->num_dai = 2;
+       codec->reg_cache_size = ARRAY_SIZE(rt5631_reg);
+       codec->reg_cache_step = 1;
+       codec->reg_cache = kmemdup(rt5631_reg, sizeof(rt5631_reg), GFP_KERNEL);
+       
+       if (codec->reg_cache == NULL)
+               return -ENOMEM;
+               
+       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
+       if (ret < 0) {
+               printk(KERN_ERR "rt5631: failed to create pcms\n");
+               goto pcm_err;   
+       }
+       
+       rt5631_reset(codec);
+       rt5631_write_mask(codec, RT5631_PWR_MANAG_ADD3,PWR_VREF|PWR_MAIN_BIAS, PWR_VREF|PWR_MAIN_BIAS);
+       schedule_timeout_uninterruptible(msecs_to_jiffies(110));
+       rt5631_write_mask(codec, RT5631_PWR_MANAG_ADD3, PWR_FAST_VREF_CTRL, PWR_FAST_VREF_CTRL);        
+       codec->bias_level = SND_SOC_BIAS_STANDBY;
+       schedule_delayed_work(&codec->delayed_work, msecs_to_jiffies(100));
+
+       rt5631_reg_init(codec);
+       rt5631_add_controls(codec);
+       rt5631_add_widgets(codec);
+       ret = snd_soc_init_card(socdev);
+       if (ret < 0) {
+               printk(KERN_ERR "rt5631: failed to register card!\n");
+               goto card_err;  
+       }
+       printk(KERN_INFO "rt5631 initial ok!\n");
+       return 0;
+       
+       
+card_err:
+       snd_soc_free_pcms(socdev);
+       snd_soc_dapm_free(socdev);
+pcm_err:
+       kfree(codec->reg_cache);
+       codec->reg_cache = NULL;
+       return ret;
+}
+
+
+static const struct i2c_device_id rt5631_i2c_id[] = {
+               {"rt5631", 0},
+                       {}
+};
+MODULE_DEVICE_TABLE(i2c, rt5631_i2c_id);
+
+static int rt5631_i2c_probe(struct i2c_client *i2c,
+                           const struct i2c_device_id *id)
+{
+       struct snd_soc_device *socdev = rt5631_socdev;
+       struct snd_soc_codec *codec = socdev->card->codec;
+       int ret;
+       
+       printk(KERN_DEBUG "enter %s\n", __func__);      
+       i2c_set_clientdata(i2c, codec);
+       codec->control_data = i2c;
+       
+       ret = rt5631_init(socdev);
+       if (ret < 0)
+               pr_err("failed to initialise rt5631!\n");
+               
+       return ret;
+       
+       
+}
+
+static int rt5631_i2c_remove(struct i2c_client *client)
+{
+       struct snd_soc_codec *codec = i2c_get_clientdata(client);
+       
+       printk(KERN_DEBUG "enter %s\n", __func__);      
+       kfree(codec->reg_cache);
+       return 0;
+}
+
+struct i2c_driver rt5631_i2c_driver = {
+       .driver = {
+               .name = "RT5631 I2C Codec",
+               .owner = THIS_MODULE,
+       },
+       .probe = rt5631_i2c_probe,
+       .remove = rt5631_i2c_remove,
+       .id_table = rt5631_i2c_id,
+};
+
+
+static int rt5631_add_i2c_device(struct platform_device *pdev, 
+               const struct rt5631_setup_data *setup)
+{
+#if 0  
+       struct i2c_board_info info;
+       struct i2c_adapter *adapter;
+       struct i2c_client *client;
+#endif 
+       int ret;
+       
+       printk(KERN_DEBUG "enter %s\n", __func__);      
+       ret = i2c_add_driver(&rt5631_i2c_driver);
+       if (ret != 0) {
+               dev_err(&pdev->dev, "can't add i2c driver\n");
+               return ret;     
+       }       
+       
+#if 0  
+       memset(&info, '\0', sizeof(struct i2c_board_info));
+       info.addr = setup->i2c_address;
+       info.platform_data = pdev;
+       strlcpy(info.type, "rt5631", I2C_NAME_SIZE);
+       
+       adapter = i2c_get_adapter(setup->i2c_bus);
+       if (!adapter) {
+               dev_err(&pdev->dev, "can't get i2c adapter %d\n", 
+                               setup->i2c_bus);
+               goto err_driver;        
+       }
+       
+       client = i2c_new_device(adapter, &info);
+       i2c_put_adapter(adapter);
+       if (!client) {
+               dev_err(&pdev->dev, "can't add i2c device at 0x%x\n",
+                               (unsigned int)info.addr);
+               goto err_driver;
+       }
+#endif 
+
+       return 0;
+
+#if 0  
+err_driver:
+       i2c_del_driver(&rt5631_i2c_driver);
+       return -ENODEV;
+#endif
+       
+}
+
+static void rt5631_work(struct work_struct *work)
+{
+       struct snd_soc_codec *codec = container_of(work, struct snd_soc_codec, delayed_work.work);
+       
+       rt5631_set_bias_level(codec, codec->bias_level);        
+}
+
+static int rt5631_probe(struct platform_device *pdev) 
+{
+       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+       struct rt5631_setup_data *setup;
+       struct snd_soc_codec *codec;
+       struct rt5631_priv *rt5631;
+       int ret = 0;
+       
+       printk(KERN_DEBUG "enter %s\n", __func__);      
+
+       pr_info("RT5631 Audio Codec %s", RT5631_VERSION);
+
+       if(socdev->codec_data)
+       {
+               setup = socdev->codec_data;             
+       }
+
+       codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
+       if (codec == NULL) {
+               return -ENOMEM; 
+       }
+       
+       
+       rt5631 = kzalloc(sizeof(struct rt5631_priv), GFP_KERNEL);
+       if (rt5631 == NULL) {
+               ret = -ENOMEM;
+               goto priv_err;  
+       } 
+       codec->private_data = rt5631;
+       socdev->card->codec = codec;
+       mutex_init(&codec->mutex);
+       rt5631_socdev = socdev;
+       INIT_LIST_HEAD(&codec->dapm_widgets);
+       INIT_LIST_HEAD(&codec->dapm_paths);
+       INIT_DELAYED_WORK(&codec->delayed_work, rt5631_work);
+       
+#if 0
+       if (setup->i2c_address) {
+               codec->hw_write = (hw_write_t)i2c_master_send;
+
+               ret = rt5631_add_i2c_device(pdev, setup);       
+       }
+#else  
+       //probe i2c device driver
+       {
+               codec->hw_write = (hw_write_t)i2c_master_send;
+               //      codec->hw_read = (hw_read_t)i2c_master_recv;
+               ret = rt5631_add_i2c_device(pdev, setup);
+       }
+#endif
+       
+       if (ret != 0) {
+               goto i2c_device_err;
+       }
+       return 0;       
+
+i2c_device_err:
+       kfree(rt5631);
+       socdev->card->codec->private_data = NULL;
+
+priv_err:
+       kfree(codec);
+       socdev->card->codec = NULL;             
+
+       return ret;
+}
+
+static int run_delayed_work(struct delayed_work *dwork) 
+{
+       int ret;
+       
+       ret = cancel_delayed_work(dwork);
+       
+       if (ret) {
+               schedule_delayed_work(dwork, 0);
+               flush_scheduled_work(); 
+       }       
+       
+       return ret;
+}
+
+static int rt5631_remove(struct platform_device *pdev)
+{
+       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+
+       struct snd_soc_codec *codec =socdev->card->codec;
+
+       if (codec->control_data) 
+               rt5631_set_bias_level(codec, SND_SOC_BIAS_OFF);
+       run_delayed_work(&codec->delayed_work);
+       snd_soc_free_pcms(socdev);
+       snd_soc_dapm_free(socdev);
+       i2c_unregister_device(codec->control_data);
+       i2c_del_driver(&rt5631_i2c_driver);
+       kfree(codec->private_data);
+       kfree(codec);
+       
+       return 0;
+               
+}
+
+static int rt5631_suspend(struct platform_device *pdev, pm_message_t state)
+{
+       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+
+       struct snd_soc_codec *codec =socdev->card->codec;
+
+       rt5631_set_bias_level(codec, SND_SOC_BIAS_OFF);
+       return 0;
+}
+
+static int rt5631_resume(struct platform_device *pdev)
+{
+       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+       struct snd_soc_codec *codec = socdev->card->codec;
+
+//     int i;
+//     u8 data[3];
+//     u16 *cache = codec->reg_cache;
+       
+#if 1
+       rt5631_write_mask(codec, RT5631_PWR_MANAG_ADD3,PWR_VREF|PWR_MAIN_BIAS, PWR_VREF|PWR_MAIN_BIAS);
+       schedule_timeout_uninterruptible(msecs_to_jiffies(110));
+       rt5631_write_mask(codec, RT5631_PWR_MANAG_ADD3, PWR_FAST_VREF_CTRL, PWR_FAST_VREF_CTRL);        
+       rt5631_reg_init(codec);
+       rt5631_write_mask(codec, RT5631_PWR_MANAG_ADD1, 0x80e0, 0x80e0);
+#else  
+       printk(KERN_DEBUG "enter %s\n", __func__);      
+       for (i = 0; i < ARRAY_SIZE(rt5631_reg); i++) {
+               if (i == RT5631_RESET)
+                       continue;
+               data[0] = i << 1;
+               data[1] = (0xff00 & cache[i]) >> 8;
+               data[2] = 0x00ff & cache[i];
+               codec->hw_write(codec->control_data, data, 2);
+       }
+       
+       rt5631_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+#endif
+       
+       if (codec->suspend_bias_level == SND_SOC_BIAS_ON) {
+               rt5631_set_bias_level(codec, SND_SOC_BIAS_PREPARE);
+               codec->bias_level = SND_SOC_BIAS_ON;
+               schedule_delayed_work(&codec->delayed_work, msecs_to_jiffies(100));     
+       }
+       
+       return 0;
+
+       
+}
+
+struct snd_soc_codec_device soc_codec_dev_rt5631 = 
+{
+       .probe = rt5631_probe,
+       .remove = rt5631_remove,
+       .suspend = rt5631_suspend,
+       .resume = rt5631_resume,
+};
+
+EXPORT_SYMBOL_GPL(soc_codec_dev_rt5631);
+
+static int __init rt5631_modinit(void)
+{
+       return snd_soc_register_dais(rt5631_dai, ARRAY_SIZE(rt5631_dai));       
+}
+
+static void __exit rt5631_modexit(void) 
+{
+       snd_soc_unregister_dais(rt5631_dai, ARRAY_SIZE(rt5631_dai));
+}
+
+module_init(rt5631_modinit);
+module_exit(rt5631_modexit);
+MODULE_DESCRIPTION("ASoC RT5631 driver");
+MODULE_AUTHOR("flove");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/rt5631.h b/sound/soc/codecs/rt5631.h
new file mode 100644 (file)
index 0000000..b2e316f
--- /dev/null
@@ -0,0 +1,578 @@
+#ifndef __RTCODEC5631_H__\r
+#define __RTCODEC5631_H__\r
+\r
+\r
+#define RT5631_RESET                                           0X00                    //RESET CODEC TO DEFAULT\r
+#define RT5631_SPK_OUT_VOL                                     0X02                    //SPEAKER OUT VOLUME\r
+#define RT5631_HP_OUT_VOL                                      0X04                    //HEADPHONE OUTPUT VOLUME\r
+#define RT5631_MONO_AXO_1_2_VOL                                0X06                    //MONO/AUXOUT OUTPUT VOLUME\r
+#define RT5631_AUX_IN_VOL                                      0X0A                    //AUX IN VOLUME\r
+#define RT5631_STEREO_DAC_VOL_1                                0X0C                    //STEREO DAC VOLUME 1\r
+#define RT5631_MIC_CTRL_1                                      0X0E                    //MICROPHONE CONTROL 1\r
+#define RT5631_STEREO_DAC_VOL_2                                0X10                    //STEREO DAC VOLUME 2\r
+#define RT5631_ADC_CTRL_1                                      0X12                    //STEREO ADC CONTROL 1\r
+#define RT5631_ADC_REC_MIXER                           0X14                    //ADC RECORD MIXER CONTROL\r
+#define RT5631_ADC_CTRL_2                                      0X16                    //STEREO ADC CONTROL 2\r
+#define RT5631_OUTMIXER_L_CTRL                         0X1A                    //LEFT OUTPUT MIXER CONTROL\r
+#define RT5631_OUTMIXER_R_CTRL                         0X1C                    //RIGHT OUTPUT MIXER CONTROL\r
+#define RT5631_AXO1MIXER_CTRL                          0X1E                    //LOUT MIXER CONTROL\r
+#define RT5631_AXO2MIXER_CTRL                          0X20                    //LOUT MIXER CONTROL\r
+#define RT5631_MIC_CTRL_2                                      0X22                    //MICROPHONE CONTROL 2\r
+#define RT5631_DIG_MIC_CTRL                                    0X24                    //DIGITAL MICROPHONE CONTROL\r
+#define RT5631_MONO_INPUT_VOL                          0X26                    //MONO INPUT VOLUME\r
+#define RT5631_SPK_MIXER_CTRL                          0X28                    //SPEAKER MIXER CONTROL\r
+#define RT5631_SPK_MONO_OUT_CTRL                       0X2A                    //SPEAKER/MONO OUTPUT CONTROL\r
+#define RT5631_SPK_MONO_HP_OUT_CTRL                    0X2C                    //SPEAKER/MONO/HP OUTPUT CONTROL\r
+#define        RT5631_SDP_CTRL                                         0X34                    //STEREO I2S SERIAL DATA PORT CONTROL\r
+#define RT5631_STEREO_AD_DA_CLK_CTRL           0X38                    //STEREO AD/DA CLOCK CONTROL\r
+#define        RT5631_PWR_MANAG_ADD1                           0X3A                    //POWER MANAGMENT ADDITION 1\r
+#define        RT5631_PWR_MANAG_ADD2                           0X3B                    //POWER MANAGMENT ADDITION 2\r
+#define RT5631_PWR_MANAG_ADD3                          0X3C                    //POWER MANAGMENT ADDITION 3\r
+#define RT5631_PWR_MANAG_ADD4                          0X3E                    //POWER MANAGMENT ADDITION 4\r
+#define RT5631_GEN_PUR_CTRL_REG                                0X40                    //GENERAL PURPOSE CONTROL REGISTER\r
+#define        RT5631_GLOBAL_CLK_CTRL                          0X42                    //GLOBAL CLOCK CONTROL\r
+#define RT5631_PLL_CTRL                                                0X44                    //PLL CONTROL\r
+#define RT5631_INT_ST_IRQ_CTRL_1                       0X48                    //INTERNAL STATUS AND IRQ CONTROL 1\r
+#define RT5631_INT_ST_IRQ_CTRL_2                       0X4A                    //INTERNAL STATUS AND IRQ CONTROL 2\r
+#define RT5631_GPIO_CTRL                                       0X4C                    //GPIO OUTPUT CONTROL\r
+#define RT5631_MISC_CTRL                                       0X52                    //MISC CONTROL\r
+#define RT5631_DEPOP_FUN_CTRL_1                                0X54                    //DE-POP FUNCTION CONTROL 1\r
+#define RT5631_DEPOP_FUN_CTRL_2                                0X56                    //DE-POP FUNCTION CONTROL 2\r
+#define RT5631_JACK_DET_CTRL                           0X5A                    //JACK DETECT CONTROL REGISTER\r
+#define RT5631_SOFT_VOL_CTRL                           0X5C                    //SOFT VOLUME CONTROL\r
+#define RT5631_ALC_CTRL_1                                      0X64                    //ALC CONTROL 1\r
+#define RT5631_ALC_CTRL_2                                      0X65                    //ALC CONTROL 2\r
+#define RT5631_ALC_CTRL_3                                      0X66                    //ALC CONTROL 3\r
+#define RT5631_PSEUDO_SPATL_CTRL                       0X68                    //PSEUDO STEREO AND SPATIAL EFFECT CONTROL\r
+#define RT5631_INDEX_ADD                                       0X6A                    //INDEX ADDRESS\r
+#define RT5631_INDEX_DATA                                      0X6C                    //INDEX DATA\r
+#define RT5631_EQ_CTRL                                         0X6E                    //EQ CONTROL \r
+#define RT5631_VENDOR_ID1                              0x7C                    //VENDOR ID1\r
+#define RT5631_VENDOR_ID2                              0x7E                    //VENDOR ID2\r
+\r
+\r
+//global definition\r
+#define RT_L_MUTE                                              (0x1<<15)               //MUTE LEFT CONTROL BIT\r
+#define RT_R_MUTE                                              (0x1<<7)                //MUTE RIGHT CONTROL BIT\r
+\r
+//Speaker Output Control(0x02)\r
+#define SPK_L_VOL_SEL_MASK                     (0x1<<14)               //Speaker left channel volume input select MASK\r
+#define SPK_L_VOL_SEL_VMID                     (0x0<<14)               //Speaker left channel volume input select VMID\r
+#define SPK_L_VOL_SEL_SPKMIX_L         (0x1<<14)               //Speaker left channel volume input select SPKMIXER LEFT\r
+#define SPK_R_VOL_SEL_MASK                     (0x1<< 6)               //Speaker right channel volume input select MASK\r
+#define SPK_R_VOL_SEL_VMID                     (0x0<< 6)               //Speaker right channel volume input select VMID\r
+#define SPK_R_VOL_SEL_SPKMIX_R         (0x1<< 6)               //Speaker right channel volume input select SPKMIXER RIGHT\r
+\r
+//Headphone Output Control(0x04)\r
+#define HP_L_VOL_SEL_MASK                      (0x1<<14)               //HP left channel volume input select MASK\r
+#define HP_L_VOL_SEL_VMID                      (0x0<<14)               //HP left channel volume input select VMID\r
+#define HP_L_VOL_SEL_OUTMIX_L          (0x1<<14)               //HP left channel volume input select OUTMIXER LEFT\r
+#define HP_R_VOL_SEL_MASK                      (0x1<< 6)               //HP right channel volume input select MASK\r
+#define HP_R_VOL_SEL_VMID                      (0x0<< 6)               //HP right channel volume input select VMID\r
+#define HP_R_VOL_SEL_OUTMIX_R          (0x1<< 6)               //HP right channel volume input select OUTMIXER RIGHT \r
+\r
+\r
+//Output Control for AUXOUT/MONO(0x06)\r
+#define AUXOUT_1_VOL_SEL_MASK                  (0x1<<14)               //LOUT channel volume input select MASK\r
+#define AUXOUT_1_VOL_SEL_VMID                  (0x0<<14)               //LOUT channel volume input select VMID\r
+#define AUXOUT_1_VOL_SEL_OUTMIX_L              (0x1<<14)               //LOUT channel volume input select OUTMIXER LEFT\r
+#define MUTE_MONO                                              (0x1<<13)               //Mute Mono control\r
+#define AUXOUT_2_VOL_SEL_MASK                  (0x1<< 6)               //ROUT channel volume input select MASK\r
+#define AUXOUT_2_VOL_SEL_VMID                  (0x0<< 6)               //ROUT channel volume input select VMID\r
+#define AUXOUT_2_VOL_SEL_OUTMIX_R              (0x1<< 6)               //ROUT channel volume input select OUTMIXER RIGHT \r
+\r
+\r
+//Microphone Input Control 1(0x0E)\r
+#define MIC1_DIFF_INPUT_CTRL                   (0x1<<15)               //MIC1 different input control\r
+#define MIC2_DIFF_INPUT_CTRL                   (0x1<< 7)               //MIC2 different input control\r
+\r
+\r
+//ADC Recording Mixer Control(0x14)\r
+#define M_OUTMIXER_L_TO_RECMIXER_L             (0x1<<15)               //Mute left OUTMIXER to left RECMIXER\r
+#define M_MIC1_TO_RECMIXER_L                   (0x1<<14)               //Mute mic1 to left RECMIXER\r
+#define M_AXIL_TO_RECMIXER_L                   (0x1<<13)               //Mute AXIL to left RECMIXER\r
+#define M_MONO_IN_TO_RECMIXER_L                        (0x1<<12)               //Mute BB_RX to left RECMIXER\r
+#define M_OUTMIXER_R_TO_RECMIXER_R             (0x1<< 7)               //Mute right OUTMIXER to right RECMIXER\r
+#define M_MIC2_TO_RECMIXER_R                   (0x1<< 6)               //Mute mic2 to right RECMIXER\r
+#define M_AXIR_TO_RECMIXER_R                   (0x1<< 5)               //Mute AXIR to right RECMIXER\r
+#define M_MONO_IN_TO_RECMIXER_R                        (0x1<< 4)               //Mute BB_RX to right RECMIXER\r
+\r
+//Left Output Mixer Control(0x1A)\r
+#define        M_RECMIXER_L_TO_OUTMIXER_L              (0x1<<15)               //Mute Left RecMixer to Left OutMixer   \r
+#define        M_RECMIXER_R_TO_OUTMIXER_L              (0x1<<14)               //Mute Right RecMixer to Left OutMixer  \r
+#define        M_DAC_L_TO_OUTMIXER_L                   (0x1<<13)               //Mute Left Dac to Left OutMixer        \r
+#define        M_MIC1_TO_OUTMIXER_L                    (0x1<<12)               //Mute Mic1 to Left OutMixer    \r
+#define M_MIC2_TO_OUTMIXER_L                   (0x1<<11)               //Mute Mic2 to Left OutMixer    \r
+#define M_MONO_IN_P_TO_OUTMIXER_L              (0x1<<10)               //Mute MONO IN positive to Left OutMixer                \r
+#define M_AXIL_TO_OUTMIXER_L                   (0x1<< 9)               //Mute AXIL to Left OutMixer    \r
+#define M_AXIR_TO_OUTMIXER_L                   (0x1<< 8)               //Mute AXIR to Left OutMixer    \r
+\r
+\r
+//Right Output Mixer Control(0x1C)\r
+#define        M_RECMIXER_L_TO_OUTMIXER_R              (0x1<<15)               //Mute Left RecMixer to Right OutMixer  \r
+#define        M_RECMIXER_R_TO_OUTMIXER_R              (0x1<<14)               //Mute Right RecMixer to Right OutMixer \r
+#define        M_DAC_R_TO_OUTMIXER_R                   (0x1<<13)               //Mute Left Dac to Right OutMixer       \r
+#define        M_MIC1_TO_OUTMIXER_R                    (0x1<<12)               //Mute Mic1 to Right OutMixer   \r
+#define M_MIC2_TO_OUTMIXER_R                   (0x1<<11)               //Mute Mic2 to Right OutMixer   \r
+#define M_MONO_IN_N_TO_OUTMIXER_R                      (0x1<<10)               //Mute MONO IN Negative to Right OutMixer               \r
+#define M_AXIL_TO_OUTMIXER_R                   (0x1<< 9)               //Mute AXIL to Right OutMixer   \r
+#define M_AXIR_TO_OUTMIXER_R                   (0x1<< 8)               //Mute AXIR to Right OutMixer   \r
+\r
+\r
+//Lout Mixer Control(0x1E)\r
+#define M_MIC1_TO_AXO1MIXER                            (0x1<<15)               //Mute MIC1 to LOUT Mixer\r
+#define M_MIC2_TO_AXO1MIXER                            (0x1<<11)               //Mute MIC2 to LOUT Mixer\r
+#define M_OUTMIXER_L_TO_AXO1MIXER              (0x1<< 7)               //Mute Left Output mixer to LOUT Mixer\r
+#define M_OUTMIXER_R_TO_AXO1MIXER              (0x1<< 6)               //Mute Right Output mixer to LOUT Mixer\r
+\r
+\r
+//Rout Mixer Control(0x20)\r
+#define M_MIC1_TO_AXO2MIXER                            (0x1<<15)               //Mute MIC1 to ROUT Mixer\r
+#define M_MIC2_TO_AXO2MIXER                            (0x1<<11)               //Mute MIC2 to ROUT Mixer\r
+#define M_OUTMIXER_L_TO_AXO2MIXER              (0x1<< 7)               //Mute Left Output mixer to ROUT Mixer\r
+#define M_OUTMIXER_R_TO_AXO2MIXER              (0x1<< 6)               //Mute Right Output mixer to ROUT Mixer\r
+\r
+//Micphone Input Control 2(0x22)\r
+#define MIC_BIAS_90_PRECNET_AVDD       1\r
+#define        MIC_BIAS_75_PRECNET_AVDD        2\r
+\r
+#define MIC1_BOOST_CTRL_MASK           (0xf<<12)\r
+#define MIC1_BOOST_CTRL_BYPASS         (0x0<<12)\r
+#define MIC1_BOOST_CTRL_20DB           (0x1<<12)\r
+#define MIC1_BOOST_CTRL_24DB           (0x2<<12)\r
+#define MIC1_BOOST_CTRL_30DB           (0x3<<12)\r
+#define MIC1_BOOST_CTRL_35DB           (0x4<<12)\r
+#define MIC1_BOOST_CTRL_40DB           (0x5<<12)\r
+#define MIC1_BOOST_CTRL_34DB           (0x6<<12)\r
+#define MIC1_BOOST_CTRL_50DB           (0x7<<12)\r
+#define MIC1_BOOST_CTRL_52DB           (0x8<<12)\r
+\r
+#define MIC2_BOOST_CTRL_MASK           (0xf<< 8)\r
+#define MIC2_BOOST_CTRL_BYPASS         (0x0<< 8)\r
+#define MIC2_BOOST_CTRL_20DB           (0x1<< 8)\r
+#define MIC2_BOOST_CTRL_24DB           (0x2<< 8)\r
+#define MIC2_BOOST_CTRL_30DB           (0x3<< 8)\r
+#define MIC2_BOOST_CTRL_35DB           (0x4<< 8)\r
+#define MIC2_BOOST_CTRL_40DB           (0x5<< 8)\r
+#define MIC2_BOOST_CTRL_34DB           (0x6<< 8)\r
+#define MIC2_BOOST_CTRL_50DB           (0x7<< 8)\r
+#define MIC2_BOOST_CTRL_52DB           (0x8<< 8)\r
+\r
+#define MICBIAS1_VOLT_CTRL_MASK                (0x1<< 7)\r
+#define MICBIAS1_VOLT_CTRL_90P         (0x0<< 7)\r
+#define MICBIAS1_VOLT_CTRL_75P         (0x1<< 7)\r
+\r
+#define MICBIAS1_S_C_DET_MASK          (0x1<< 6)\r
+#define MICBIAS1_S_C_DET_DIS           (0x0<< 6)\r
+#define MICBIAS1_S_C_DET_ENA           (0x1<< 6)\r
+\r
+#define MICBIAS1_SHORT_CURR_DET_MASK   (0x3<< 4)\r
+#define MICBIAS1_SHORT_CURR_DET_600UA  (0x0<< 4)\r
+#define MICBIAS1_SHORT_CURR_DET_1500UA (0x1<< 4)\r
+#define MICBIAS1_SHORT_CURR_DET_2000UA (0x2<< 4)\r
+\r
+#define MICBIAS2_VOLT_CTRL_MASK                (0x1<< 3)\r
+#define MICBIAS2_VOLT_CTRL_90P         (0x0<< 3)\r
+#define MICBIAS2_VOLT_CTRL_75P         (0x1<< 3)\r
+\r
+#define MICBIAS2_S_C_DET_MASK          (0x1<< 2)\r
+#define MICBIAS2_S_C_DET_DIS           (0x0<< 2)\r
+#define MICBIAS2_S_C_DET_ENA           (0x1<< 2)\r
+\r
+#define MICBIAS2_SHORT_CURR_DET_MASK   (0x3)\r
+#define MICBIAS2_SHORT_CURR_DET_600UA  (0x0)\r
+#define MICBIAS2_SHORT_CURR_DET_1500UA (0x1)\r
+#define MICBIAS2_SHORT_CURR_DET_2000UA (0x2)\r
+\r
+\r
+//Digital Microphone Control(0x24)\r
+#define DMIC_ENA_MASK                          (0x1<<15)       \r
+#define DMIC_ENA                                       (0x1<<15)               //use DMIC to ADC Digital filter\r
+#define DMIC_DIS                                       (0x0<<15)               //use ADC mixer to ADC Digital filter\r
+\r
+#define DMIC_L_CH_MUTE_MASK                    (0x1<<13)\r
+#define DMIC_L_CH_UNMUTE                       (0x0<<13)\r
+#define DMIC_L_CH_MUTE                         (0x1<<13)\r
+\r
+#define DMIC_R_CH_MUTE_MASK                    (0x1<<12)\r
+#define DMIC_R_CH_UNMUTE                       (0x0<<12)\r
+#define DMIC_R_CH_MUTE                         (0x1<<12)\r
+\r
+#define DMIC_L_CH_LATCH_MASK           (0x1<< 9)\r
+#define DMIC_L_CH_LATCH_RISING         (0x1<< 9)\r
+#define DMIC_L_CH_LATCH_FALLING                (0x0<< 9)\r
+\r
+#define DMIC_R_CH_LATCH_MASK           (0x1<< 8)\r
+#define DMIC_R_CH_LATCH_RISING         (0x1<< 8)\r
+#define DMIC_R_CH_LATCH_FALLING                (0x0<< 8)\r
+\r
+#define DMIC_CLK_CTRL_MASK                     (0x3<<4)\r
+#define DMIC_CLK_CTRL_TO_128FS         (0x0<<4)\r
+#define DMIC_CLK_CTRL_TO_64FS          (0x1<<4)\r
+#define DMIC_CLK_CTRL_TO_32FS          (0x2<<4)\r
+\r
+\r
+//Speaker Mixer Control(0x28)\r
+#define        M_RECMIXER_L_TO_SPKMIXER_L              (0x1<<15)               //Mute Left RecMixer to Left Speaker Mixer\r
+#define        M_MIC1_P_TO_SPKMIXER_L                  (0x1<<14)               //Mute MIC1 Positive to Left Speaker Mixer      \r
+#define        M_DAC_L_TO_SPKMIXER_L                   (0x1<<13)               //Mute Left Dac to Left Speaker Mixer   \r
+#define        M_OUTMIXER_L_TO_SPKMIXER_L              (0x1<<12)               //Mute Left OutMixer to Left Speaker Mixer      \r
+\r
+#define        M_RECMIXER_R_TO_SPKMIXER_R              (0x1<< 7)               //Mute Right RecMixer to Right Speaker Mixer\r
+#define        M_MIC2_P_TO_SPKMIXER_R                  (0x1<< 6)               //Mute MIC1 Positive to Right Speaker Mixer     \r
+#define        M_DAC_R_TO_SPKMIXER_R                   (0x1<< 5)               //Mute Right Dac to Right Speaker Mixer \r
+#define        M_OUTMIXER_R_TO_SPKMIXER_R              (0x1<< 4)               //Mute Right OutMixer to Right Speaker Mixer    \r
+\r
+\r
+\r
+//Speaker/Mono Output Control(0x2A)\r
+#define        M_SPKVOL_L_TO_SPOL_MIXER                (0x1<<15)               //Mute Left Speaker Volume to SPOL Mixer\r
+#define        M_SPKVOL_R_TO_SPOL_MIXER                (0x1<<14)               //Mute Right Speaker Volume to SPOL Mixer       \r
+#define        M_SPKVOL_L_TO_SPOR_MIXER                (0x1<<13)               //Mute Left Speaker Volume to  SPOR Mixer\r
+#define        M_SPKVOL_R_TO_SPOR_MIXER                (0x1<<12)               //Mute Right Speaker Volume to SPOR Mixer       \r
+#define        M_OUTVOL_L_TO_MONOMIXER                 (0x1<<11)               //Mute Left Output Volume to Mono Mixer\r
+#define        M_OUTVOL_R_TO_MONOMIXER                 (0x1<<10)               //Mute Right Output Volume to Mono Mixer        \r
+\r
+\r
+//Speaker/Mono/HP Output Control(0x2C)\r
+#define SPK_L_MUX_SEL_MASK                             (0x3<<14)               //Left Speaker mux select Mask\r
+#define SPK_L_MUX_SEL_SPKMIXER_L               (0x0<<14)               //Left Speaker mux select Speaker mixer left\r
+#define SPK_L_MUX_SEL_MONO_IN                  (0x1<<14)               //Left Speaker mux select MONO input\r
+#define SPK_L_MUX_SEL_DAC_L                            (0x3<<14)               //Left Speaker mux select Dac left\r
+\r
+#define SPK_R_MUX_SEL_MASK                             (0x3<<10)               //Right Speaker mux select Mask\r
+#define SPK_R_MUX_SEL_SPKMIXER_R               (0x0<<10)               //Right Speaker mux select Speaker mixer right\r
+#define SPK_R_MUX_SEL_MONO_IN                  (0x1<<10)               //Right Speaker mux select MONO input\r
+#define SPK_R_MUX_SEL_DAC_R                            (0x3<<10)               //Right Speaker mux select Dac right\r
+\r
+#define MONO_MUX_SEL_MASK                              (0x3<< 6)               //Monoout mux select Mask\r
+#define MONO_MUX_SEL_MONOMIXER                 (0x0<< 6)               //Monoout mux select Mono Mixer \r
+#define MONO_MUX_SEL_MONO_IN                   (0x1<< 6)               //Monoout mux select MONO input\r
+\r
+#define HP_L_MUX_SEL_MASK                              (0x1<< 3)               //HP left mux select Mask\r
+#define HP_L_MUX_SEL_HPVOL_L                   (0x0<< 3)               //HP left mux select left HP output volume      \r
+#define HP_L_MUX_SEL_DAC_L                             (0x1<< 3)               //HP left mux select Dac left channel\r
+\r
+#define HP_R_MUX_SEL_MASK                              (0x1<< 2)               //HP left mux select Mask\r
+#define HP_R_MUX_SEL_HPVOL_R                   (0x0<< 2)               //HP left mux select left HP output volume\r
+#define HP_R_MUX_SEL_DAC_R                             (0x1<< 2)               //HP left mux select Dac left channel\r
+\r
+\r
+//Stereo I2S Serial Data Port Control(0x34)\r
+#define SDP_MODE_SEL_MASK                              (0x1<<15)               //Main I2S interface select MASK                \r
+#define SDP_MODE_SEL_MASTER                            (0x0<<15)               //Main I2S interface select MASTER MODE\r
+#define SDP_MODE_SEL_SLAVE                             (0x1<<15)               //Main I2S interface select SLAVE MODE\r
+\r
+#define SDP_ADC_CPS_SEL_MASK                   (0x3<<10)               //ADC Compress select Mask\r
+#define SDP_ADC_CPS_SEL_OFF                            (0x0<<10)               //ADC Compress select OFF\r
+#define SDP_ADC_CPS_SEL_U_LAW                  (0x1<<10)               //ADC Compress select u_law\r
+#define SDP_ADC_CPS_SEL_A_LAW                  (0x2<<10)               //ADC Compress select a_law\r
+\r
+#define SDP_DAC_CPS_SEL_MASK                   (0x3<< 8)               //DAC Compress select Mask\r
+#define SDP_DAC_CPS_SEL_OFF                            (0x0<< 8)               //DAC Compress select OFF\r
+#define SDP_DAC_CPS_SEL_U_LAW                  (0x1<< 8)               //DAC Compress select u_law\r
+#define SDP_DAC_CPS_SEL_A_LAW                  (0x2<< 8)               //DAC Compress select a_law\r
+                                                                                                       \r
+#define SDP_I2S_BCLK_POL_CTRL                  (0x1<<7)                //0:Normal 1:Invert\r
+\r
+#define SDP_DAC_R_INV                                  (0x1<<6)                //0:Normal 1:Invert\r
+\r
+#define SDP_ADC_DATA_L_R_SWAP                  (0x1<<5)                //0:ADC data appear at left phase of LRCK\r
+                                                                                                               //1:ADC data appear at right phase of LRCK\r
+#define SDP_DAC_DATA_L_R_SWAP                  (0x1<<4)                //0:DAC data appear at left phase of LRCK\r
+                                                                                                               //1:DAC data appear at right phase of LRCK      \r
+//Data Length Slection\r
+#define SDP_I2S_DL_MASK                                        (0x3<<2)                //Stereo Serial Data Length mask        \r
+#define SDP_I2S_DL_16                                  (0x0<<2)                //16 bits\r
+#define SDP_I2S_DL_20                                  (0x1<<2)                //20 bits\r
+#define        SDP_I2S_DL_24                                   (0x2<<2)                //24 bits\r
+#define SDP_I2S_DL_8                                   (0x3<<2)                //8  bits\r
+                                                                                                       \r
+//PCM Data Format Selection\r
+#define SDP_I2S_DF_MASK                                        (0x3)                   //main i2s Data Format mask\r
+#define SDP_I2S_DF_I2S                                 (0x0)                   //I2S FORMAT \r
+#define SDP_I2S_DF_LEFT                                        (0x1)                   //Left JUSTIFIED\r
+#define        SDP_I2S_DF_PCM_A                                (0x2)                   //PCM format A\r
+#define SDP_I2S_DF_PCM_B                               (0x3)                   //PCM format B\r
+\r
+//Stereo AD/DA Clock Control(0x38h)\r
+#define I2S_PRE_DIV_MASK                               (0x7<<13)                       \r
+#define I2S_PRE_DIV_1                                  (0x0<<13)                       //DIV 1\r
+#define I2S_PRE_DIV_2                                  (0x1<<13)                       //DIV 2\r
+#define I2S_PRE_DIV_4                                  (0x2<<13)                       //DIV 4\r
+#define I2S_PRE_DIV_8                                  (0x3<<13)                       //DIV 8\r
+#define I2S_PRE_DIV_16                                 (0x4<<13)                       //DIV 16\r
+#define I2S_PRE_DIV_32                                 (0x5<<13)                       //DIV 32\r
+\r
+#define I2S_LRCK_SEL_N_BCLK_MASK               (0x1<<12)                       //CLOCK RELATIVE OF BCLK AND LCRK\r
+#define I2S_LRCK_SEL_64_BCLK                   (0x0<<12)                       //64FS\r
+#define I2S_LRCK_SEL_32_BCLK                   (0x1<<12)                       //32FS\r
+\r
+#define DAC_OSR_SEL_MASK                               (0x3<<10)                       \r
+#define DAC_OSR_SEL_128FS                              (0x3<<10)\r
+#define DAC_OSR_SEL_64FS                               (0x3<<10)\r
+#define DAC_OSR_SEL_32FS                               (0x3<<10)\r
+#define DAC_OSR_SEL_16FS                               (0x3<<10)\r
+\r
+#define ADC_OSR_SEL_MASK                               (0x3<< 8)\r
+#define ADC_OSR_SEL_128FS                              (0x3<< 8)       \r
+#define ADC_OSR_SEL_64FS                               (0x3<< 8)       \r
+#define ADC_OSR_SEL_32FS                               (0x3<< 8)       \r
+#define ADC_OSR_SEL_16FS                               (0x3<< 8)                                               \r
+\r
+#define ADDA_FILTER_CLK_SEL_256FS              (0<<7)                  //256FS\r
+#define ADDA_FILTER_CLK_SEL_384FS              (1<<7)                  //384FS\r
+\r
+\r
+\r
+//Power managment addition 1 (0x3A),0:Disable,1:Enable\r
+#define PWR_MAIN_I2S_EN                                        (0x1<<15)\r
+#define PWR_CLASS_D                                            (0x1<<12)       \r
+#define PWR_ADC_L_CLK                                  (0x1<<11)\r
+#define PWR_ADC_R_CLK                                  (0x1<<10)\r
+#define PWR_DAC_L_CLK                                  (0x1<< 9)\r
+#define        PWR_DAC_R_CLK                                   (0x1<< 8)\r
+#define        PWR_DAC_REF                                             (0x1<< 7)\r
+#define        PWR_DAC_L_TO_MIXER                                      (0x1<< 6)\r
+#define        PWR_DAC_R_TO_MIXER                                      (0x1<<5)\r
+\r
+\r
+//Power managment addition 2 (0x3B),0:Disable,1:Enable\r
+#define PWR_OUTMIXER_L                                 (0x1<<15)\r
+#define PWR_OUTMIXER_R                                 (0x1<<14)\r
+#define PWR_SPKMIXER_L                                 (0x1<<13)\r
+#define PWR_SPKMIXER_R                                 (0x1<<12)\r
+#define PWR_RECMIXER_L                                 (0x1<<11)\r
+#define PWR_RECMIXER_R                                 (0x1<<10)\r
+#define PWR_MIC1_BOOT_GAIN                             (0x1<< 5)\r
+#define PWR_MIC2_BOOT_GAIN                             (0x1<< 4)\r
+#define PWR_MICBIAS1_VOL                               (0x1<< 3)\r
+#define PWR_MICBIAS2_VOL                               (0x1<< 2)\r
+#define PWR_PLL                                                        (0x1<< 1)\r
+\r
+\r
+//Power managment addition 3(0x3C),0:Disable,1:Enable\r
+#define PWR_VREF                                       (0x1<<15)\r
+#define PWR_FAST_VREF_CTRL                     (0x1<<14)\r
+#define PWR_MAIN_BIAS                          (0x1<<13)\r
+#define PWR_AXO1MIXER                          (0x1<<11)\r
+#define PWR_AXO2MIXER                          (0x1<<10)\r
+#define PWR_MONOMIXER                          (0x1<< 9)\r
+#define PWR_MONO_DEPOP_DIS                     (0x1<< 8)\r
+#define PWR_MONO_AMP_EN                                (0x1<< 7)\r
+#define PWR_CHARGE_PUMP                                (0x1<<4)\r
+#define PWR_HP_L_AMP                           (0x1<<3)\r
+#define PWR_HP_R_AMP                           (0x1<<2)\r
+#define PWR_HP_DEPOP_DIS                       (0x1<<1)\r
+#define PWR_HP_AMP_DRIVING                     (0x1)\r
+\r
+\r
+//Power managment addition 4(0x3E),0:Disable,1:Enable\r
+#define PWR_SPK_L_VOL                          (0x1<<15)\r
+#define PWR_SPK_R_VOL                          (0x1<<14)\r
+#define PWR_LOUT_VOL                           (0x1<<13)\r
+#define PWR_ROUT_VOL                           (0x1<<12)\r
+#define PWR_HP_L_OUT_VOL                       (0x1<<11)\r
+#define PWR_HP_R_OUT_VOL                       (0x1<<10)\r
+#define PWR_AXIL_IN_VOL                                (0x1<< 9)\r
+#define PWR_AXIR_IN_VOL                                (0x1<< 8)\r
+#define PWR_MONO_IN_P_VOL                      (0x1<< 7)\r
+#define PWR_MONO_IN_N_VOL                      (0x1<< 6)\r
+\r
+\r
+//General Purpose Control Register(0x40)\r
+#define SPK_AMP_AUTO_RATIO_EN                  (0x1<<15)       //Speaker Amplifier Auto Ratio Gain Control\r
+\r
+#define SPK_AMP_RATIO_CTRL_MASK                        (0x7<<12)\r
+#define SPK_AMP_RATIO_CTRL_2_34                        (0x0<<12)               //7.40DB\r
+#define SPK_AMP_RATIO_CTRL_1_99                        (0x1<<12)               //5.99DB\r
+#define SPK_AMP_RATIO_CTRL_1_68                        (0x2<<12)               //4.50DB\r
+#define SPK_AMP_RATIO_CTRL_1_56                        (0x3<<12)               //3.86DB\r
+#define SPK_AMP_RATIO_CTRL_1_44                        (0x4<<12)               //3.16DB        \r
+#define SPK_AMP_RATIO_CTRL_1_27                        (0x5<<12)               //2.10DB\r
+#define SPK_AMP_RATIO_CTRL_1_09                        (0x6<<12)               //0.80DB\r
+#define SPK_AMP_RATIO_CTRL_1_00                        (0x7<<12)               //0.00DB\r
+\r
+#define STEREO_DAC_HI_PASS_FILT_EN             (0x1<<11)               //Stereo DAC high pass filter enable\r
+#define STEREO_ADC_HI_PASS_FILT_EN             (0x1<<10)               //Stereo ADC high pass filter enable\r
+\r
+#define ADC_WIND_FILT_MASK                             (0x3<<4)                //Select ADC Wind Filter Clock type\r
+#define ADC_WIND_FILT_8_16_32K                 (0x0<<4)                //8/16/32k\r
+#define ADC_WIND_FILT_11_22_44K                        (0x1<<4)                //11/22/44k\r
+#define ADC_WIND_FILT_12_24_48K                        (0x2<<4)                //12/24/48k\r
+\r
+#define ADC_WIND_FILT_EN                               (0x1<<3)                //Enable ADC Wind Filter\r
+\r
+#define ADC_WIND_CNR_FREQ_MASK                 (0x7<<0)                //SelectADC Wind Filter Corner Frequency        \r
+#define ADC_WIND_CNR_FREQ_82_113_122   (0x0<<0)                //82/113/122 Hz\r
+#define ADC_WIND_CNR_FREQ_102_141_153  (0x1<<0)                //102/141/153 Hz        \r
+#define ADC_WIND_CNR_FREQ_131_180_156  (0x2<<0)                //131/180/156 Hz\r
+#define ADC_WIND_CNR_FREQ_163_225_245  (0x3<<0)                //163/225/245 Hz\r
+#define ADC_WIND_CNR_FREQ_204_281_306  (0x4<<0)                //204/281/306 Hz\r
+#define ADC_WIND_CNR_FREQ_261_360_392  (0x5<<0)                //261/360/392 Hz\r
+#define ADC_WIND_CNR_FREQ_327_450_490  (0x6<<0)                //327/450/490 Hz\r
+#define ADC_WIND_CNR_FREQ_408_563_612  (0x7<<0)                //408/563/612 Hz\r
+\r
+\r
+//Global Clock Control Register(0x42)\r
+#define SYSCLK_SOUR_SEL_MASK                   (0x1<<14)\r
+#define SYSCLK_SOUR_SEL_MCLK                   (0x0<<14)               //system Clock source from MCLK\r
+#define SYSCLK_SOUR_SEL_PLL                            (0x1<<14)               //system Clock source from PLL\r
+#define SYSCLK_SOUR_SEL_PLL_TCK                        (0x2<<14)               //system Clock source from PLL track\r
+\r
+#define PLLCLK_SOUR_SEL_MCLK                   (0x0<<12)               //PLL clock source from MCLK\r
+#define PLLCLK_SOUR_SEL_BITCLK                 (0x1<<12)               //PLL clock source from BITCLK\r
+\r
+#define PLLCLK_PRE_DIV1                                        (0x0<<11)                       //DIV 1\r
+#define PLLCLK_PRE_DIV2                                        (0x1<<11)                       //DIV 2\r
+\r
+//PLL Control(0x44)\r
+\r
+#define PLL_CTRL_M_VAL(m)                              ((m)&0xf)                       //M code for analog PLL\r
+#define PLL_CTRL_K_VAL(k)                              (((k)&0x7)<<4)          //K code for analog PLL\r
+#define PLL_CTRL_N_VAL(n)                              (((n)&0xff)<<8)         //N code for analog PLL\r
+\r
+\r
+//GPIO Pin Configuration(0x4C)\r
+#define GPIO_PIN_FUN_SEL_MASK                  (0x1<<15)\r
+#define GPIO_PIN_FUN_SEL_IRQ                   (0x1<<15)                       //GPIO pin SELECT IRQ\r
+#define GPIO_PIN_FUN_SEL_GPIO_DIMC             (0x0<<15)                       //GPIO PIN SELECT GPIO_DMIC\r
+\r
+\r
+#define GPIO_DMIC_FUN_SEL_MASK                 (0x1<<3)\r
+#define GPIO_DMIC_FUN_SEL_DIMC                 (0x1<<3)                        //GPIO pin SELECT DMIC\r
+#define GPIO_DMIC_FUN_SEL_GPIO                 (0x0<<3)                        //GPIO PIN SELECT GPIO\r
+\r
+#define GPIO_PIN_CON_MASK                              (0x1<<2)\r
+#define GPIO_PIN_SET_INPUT                             (0x0<<2)                        //GPIO pin select input\r
+#define GPIO_PIN_SET_OUTPUT                            (0x1<<2)                        //GPIO pin select output\r
+\r
+//De-POP function Control 1(0x54)\r
+#define POW_ON_SOFT_GEN                                        (0x1<<15)                       //POWER ON SOFT GENERATOR\r
+#define EN_MUTE_UNMUTE_DEPOP                   (0x1<<14)                       //Enable mute/unmute depop\r
+#define EN_DEPOP2_FOR_HP                               (0x1<<7)                        //Enable depop 2 for HP\r
+#define PD_HPAMP_L_ST_UP                               (0x1<<5)                        //Power Down HPAMP_L Starts Up Signal\r
+#define PD_HPAMP_R_ST_UP                               (0x1<<4)                        //Power Down HPAMP_R Starts Up Signal\r
+#define EN_HP_L_M_UN_MUTE_DEPOP                        (0x1<<1)                        //Enable left HP mute/unmute depop\r
+#define EN_HP_R_M_UN_MUTE_DEPOP                        (0x1<<0)                        //Enable right HP mute/unmute depop\r
+\r
+//De-POP Fnction Control(0x56)\r
+#define ENA_CAP_FREE_DEPOP                             (0x1<<14)                       //enable depop for Capfree block\r
+\r
+\r
+//Jack Detect Control Register(0x5A)\r
+#define JD_USE_MASK                                    (0x3<<14)                               //JD Pin select\r
+#define JD_USE_JD2                                     (0x3<<14)                               //select JD2\r
+#define JD_USE_JD1                                     (0x2<<14)                               //select JD1\r
+#define JD_USE_GPIO                                    (0x1<<14)                               //select GPIO\r
+#define JD_OFF                                         (0x0<<14)                               //off\r
+\r
+#define        JD_HP_EN                                        (0x1<<11)                               //JD trigger enable for HP\r
+#define JD_HP_TRI_MASK                         (0x1<<10)                               //Trigger mask\r
+#define JD_HP_TRI_HI                           (0x1<<10)                               //high trigger\r
+#define JD_HP_TRI_LO                           (0x1<<10)                               //low trigger\r
+\r
+#define JD_SPK_L_EN                                    (0x1<<9)                                //JD trigger enable for speaker LP/LN\r
+#define JD_SPK_L_TRI_MASK                      (0x1<<8)                                //Trigger mask\r
+#define JD_SPK_L_TRI_HI                                (0x1<<8)                                //high trigger\r
+#define JD_SPK_L_TRI_LO                                (0x0<<8)                                //low trigger\r
+\r
+#define JD_SPK_R_EN                                    (0x1<<7)                                //JD trigger enable for speaker RP/RN\r
+#define JD_SPK_R_TRI_MASK                      (0x1<<6)                                //Trigger mask\r
+#define JD_SPK_R_TRI_HI                                (0x1<<6)                                //high trigger\r
+#define JD_SPK_R_TRI_LO                                (0x0<<6)                                //low trigger\r
+\r
+#define JD_MONO_EN                                     (0x1<<5)                                //JD trigger enable for monoout\r
+#define JD_MONO_TRI_MASK                       (0x1<<4)                                //Trigger mask\r
+#define JD_MONO_TRI_HI                         (0x1<<4)                                //high trigger\r
+#define JD_MONO_TRI_LO                         (0x0<<4)                                //low trigger\r
+\r
+#define JD_AUX_1_EN                                    (0x1<<3)                                //JD trigger enable for Lout\r
+#define JD_AUX_1_MASK                          (0x1<<2)                                //Trigger mask\r
+#define JD_AUX_1_TRI_HI                                (0x1<<2)                                //high trigger\r
+#define JD_AUX_1_TRI_LO                                (0x0<<2)                                //low trigger\r
+\r
+#define JD_AUX_2_EN                                    (0x1<<1)                                //JD trigger enable for Rout\r
+\r
+#define JD_AUX_2_MASK                          (0x1<<0)                                //Trigger mask\r
+#define JD_AUX_2_TRI_HI                                (0x1<<0)                                //high trigger\r
+#define JD_AUX_2_TRI_LO                                (0x0<<0)                                //low trigger\r
+\r
+\r
+////ALC CONTROL 1(0x64)\r
+#define ALC_ATTACK_RATE_MASK           (0x1F<<8)                               //select ALC attack rate\r
+#define ALC_RECOVERY_RATE_MASK         (0x1F<<0)                               //select ALC Recovery rate\r
+\r
+\r
+////ALC CONTROL 2(0x65)\r
+#define ALC_COM_NOISE_GATE_MASK                (0xF<<0)                                //select Compensation gain for Noise gate function\r
+\r
+\r
+////ALC CONTROL 3(0x66)\r
+#define ALC_FUN_MASK                           (0x3<<14)                               //select ALC path \r
+#define ALC_FUN_DIS                                    (0x0<<14)                               //disable\r
+#define ALC_ENA_DAC_PATH                       (0x1<<14)                               //DAC path\r
+#define ALC_ENA_ADC_PATH                       (0x3<<14)                               //ADC path\r
+\r
+#define ALC_PARA_UPDATE                                (0x1<<13)                               //update ALC parameter\r
+\r
+#define ALC_LIMIT_LEVEL_MASK           (0x1F<<8)                               //ALC limit level\r
+\r
+#define ALC_NOISE_GATE_FUN_MASK                (0x1<<7)                                //ALC noise gate function\r
+#define ALC_NOISE_GATE_FUN_DIS         (0x0<<7)                                //disable\r
+#define ALC_NOISE_GATE_FUN_ENA         (0x1<<7)                                //enable\r
+\r
+#define ALC_NOISE_GATE_H_D_MASK                (0x1<<6)                                //ALC noise gate hold data function\r
+#define ALC_NOISE_GATE_H_D_DIS         (0x0<<6)                                //disable\r
+#define ALC_NOISE_GATE_H_D_ENA         (0x1<<6)                                //enable\r
+\r
+//Psedueo Stereo & Spatial Effect Block Control(0x68)\r
+#define SPATIAL_CTRL_EN                                (0x1<<15)                               //enable Spatial effect\r
+#define ALL_PASS_FILTER_EN                     (0x1<<14)                               //enable all pass filter\r
+#define PSEUDO_STEREO_EN                       (0x1<<13)                               //enable pseudo stereo block\r
+#define STEREO_EXPENSION_EN                    (0x1<<12)                               //enable stereo expansion block\r
+\r
+#define GAIN_3D_PARA_MASK                      (0x3<<6)                                //3D gain parameter\r
+#define GAIN_3D_PARA_1_00                      (0x0<<6)                                //3D gain 1.0\r
+#define GAIN_3D_PARA_1_50                      (0x1<<6)                                //3D gain 1.5\r
+#define GAIN_3D_PARA_2_00                      (0x2<<6)                                //3D gain 2.0\r
+\r
+#define RATIO_3D_MASK                          (0x3<<4)                                //3D ratio parameter\r
+#define RATIO_3D_0_0                           (0x0<<4)                                //3D ratio 0.0\r
+#define RATIO_3D_0_66                          (0x1<<4)                                //3D ratio 0.66\r
+#define RATIO_3D_1_0                           (0x2<<4)                                //3D ratio 1.0\r
+\r
+#define APF_FUN_SLE_MASK                       (0x3<<0)                                //select samplerate for all pass filter \r
+#define APF_FUN_SEL_48K                                (0x3<<0)                                //select 48k\r
+#define APF_FUN_SEL_44_1K                      (0x2<<0)                                //select 44.1k\r
+#define APF_FUN_SEL_32K                                (0x1<<0)                                //select 32k\r
+#define APF_FUN_DIS                                    (0x0<<0)                                //disable\r
+\r
+\r
+//EQ CONTROL 1(0x6E)\r
+\r
+#define HW_EQ_PATH_SEL_MASK                    (0x1<<15)               //HW EQ FUN SEL\r
+#define HW_EQ_PATH_SEL_DAC                     (0x0<<15)               //HW EQ FOR DAC PATH\r
+#define HW_EQ_PATH_SEL_ADC                     (0x1<<15)               //HW EQ FOR ADC PATH\r
+\r
+#define HW_EQ_UPDATE_CTRL                      (0x1<<14)               //HW EQ Update CTRL\r
+\r
+#define EN_HW_EQ_HPF2                          (0x1<<5)                //EQ High Pass Filter 2 Control\r
+#define EN_HW_EQ_HPF1                          (0x1<<4)                //EQ High Pass Filter 1 Control\r
+#define EN_HW_EQ_BP3                           (0x1<<3)                //EQ Band-3 Control\r
+#define EN_HW_EQ_BP2                           (0x1<<2)                //EQ Band-2 Control\r
+#define EN_HW_EQ_BP1                           (0x1<<1)                //EQ Band-1 Control\r
+#define EN_HW_EQ_LPF                           (0x1<<0)                //EQ Low Pass Filter Control\r
+\r
+#define REALTEK_HWDEP  0\r
+struct rt5631_setup_data {\r
+       int i2c_address;\r
+       int i2c_bus;    \r
+};\r
+\r
+\r
+extern struct snd_soc_dai rt5631_dai[];\r
+extern struct snd_soc_codec_device soc_codec_dev_rt5631;\r
+\r
+\r
+#endif //__RTCODEC5631_H__\r
old mode 100755 (executable)
new mode 100644 (file)
index 84e5666..2eeac42
@@ -40,7 +40,22 @@ config SND_RK29_SOC_WM8900
        help
          Say Y if you want to add support for SoC audio on rockchip
          with the WM8900.
-
+config SND_RK29_SOC_alc5621
+       tristate "SoC I2S Audio support for rockchip - alc5621"
+       depends on SND_RK29_SOC && I2C_RK29
+       select SND_RK29_SOC_I2S
+       select SND_SOC_alc5621
+       help
+         Say Y if you want to add support for SoC audio on rockchip
+         with the alc5621.
+config SND_RK29_SOC_alc5631
+       tristate "SoC I2S Audio support for rockchip - alc5631"
+       depends on SND_RK29_SOC && I2C_RK29
+       select SND_RK29_SOC_I2S
+       select SND_SOC_alc5631
+       help
+         Say Y if you want to add support for SoC audio on rockchip
+         with the alc5631.
 config SND_RK29_SOC_WM8994
        tristate "SoC I2S Audio support for rockchip - WM8994"
        depends on SND_RK29_SOC && I2C_RK29
@@ -59,7 +74,7 @@ config SND_RK29_SOC_RK1000
          Say Y if you want to add support for SoC audio on rockchip
          with the RK1000.       
           
-if SND_RK29_SOC_WM8988 || SND_RK29_SOC_RK1000 || SND_RK29_SOC_WM8994 || SND_RK29_SOC_WM8900
+if SND_RK29_SOC_WM8988 || SND_RK29_SOC_RK1000 || SND_RK29_SOC_WM8994 || SND_RK29_SOC_WM8900 || SND_RK29_SOC_alc5621 || SND_RK29_SOC_alc5631
 choice
   prompt "Set i2s type"
        config SND_RK29_CODEC_SOC_MASTER
old mode 100755 (executable)
new mode 100644 (file)
index 3e00a89..17e5b94
@@ -7,6 +7,8 @@ obj-$(CONFIG_SND_RK29_SOC_I2S) += snd-soc-rockchip-i2s.o
 
 # ROCKCHIP Machine Support
 snd-soc-wm8900-objs := rk29_wm8900.o
+snd-soc-alc5621-objs := rk29_alc5621.o
+snd-soc-alc5631-objs := rk29_rt5631.o
 snd-soc-wm8988-objs := rk29_wm8988.o
 snd-soc-rk1000-objs := rk29_rk1000codec.o
 snd-soc-wm8994-objs := rk29_wm8994.o
@@ -14,4 +16,6 @@ snd-soc-wm8994-objs := rk29_wm8994.o
 obj-$(CONFIG_SND_RK29_SOC_WM8994) += snd-soc-wm8994.o
 obj-$(CONFIG_SND_RK29_SOC_WM8988) += snd-soc-wm8988.o
 obj-$(CONFIG_SND_RK29_SOC_WM8900) += snd-soc-wm8900.o
+obj-$(CONFIG_SND_RK29_SOC_alc5621) += snd-soc-alc5621.o
+obj-$(CONFIG_SND_RK29_SOC_alc5631) += snd-soc-alc5631.o
 obj-$(CONFIG_SND_RK29_SOC_RK1000) += snd-soc-rk1000.o
diff --git a/sound/soc/rk29/rk29_alc5621.c b/sound/soc/rk29/rk29_alc5621.c
new file mode 100644 (file)
index 0000000..62f2ed5
--- /dev/null
@@ -0,0 +1,249 @@
+/*
+ * rk29_wm8900.c  --  SoC audio for rockchip
+ *
+ * Driver for rockchip alc5623 audio
+ *
+ *  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.
+ *
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <asm/io.h>
+#include <mach/hardware.h>
+#include <mach/rk29_iomap.h>
+#include "../codecs/alc5621.h"
+#include "rk29_pcm.h"
+#include "rk29_i2s.h"
+
+#if 1
+#define        DBG(x...)       printk(KERN_INFO x)
+#else
+#define        DBG(x...)
+#endif
+
+
+
+static int rk29_hw_params_alc5623(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params)
+{
+        struct snd_soc_pcm_runtime *rtd = substream->private_data;
+        struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
+        struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+        unsigned int pll_out = 0i,sys_clk; 
+        int ret;
+          
+        DBG("rk29_hw_params for rk29_alc5623\n");    
+        /*by Vincent Hsiung for EQ Vol Change*/
+        #define HW_PARAMS_FLAG_EQVOL_ON 0x21
+        #define HW_PARAMS_FLAG_EQVOL_OFF 0x22
+        if ((params->flags == HW_PARAMS_FLAG_EQVOL_ON)||(params->flags == HW_PARAMS_FLAG_EQVOL_OFF))
+        {
+               ret = codec_dai->ops->hw_params(substream, params, codec_dai); //by Vincent
+               DBG("rk29_hw_params set EQ vol for rk29_alc5623\n");
+        }
+        else
+        {
+                
+            /* set codec DAI configuration for codec side */
+            #if defined (CONFIG_SND_RK29_CODEC_SOC_SLAVE) 
+                DBG("rk29_hw_params for rk29_alc5623  codec as slave\n");    
+                ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
+            #endif     
+
+                   #if defined (CONFIG_SND_RK29_CODEC_SOC_MASTER) 
+                ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM ); 
+            #endif
+                if (ret < 0)return ret; 
+
+            /* set cpu DAI configuration */
+            #if defined (CONFIG_SND_RK29_CODEC_SOC_SLAVE) 
+                DBG("rk29_hw_params for rk29_alc5623  cpu as master\n");    
+                ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
+            #endif     
+
+                       #if defined (CONFIG_SND_RK29_CODEC_SOC_MASTER) 
+                ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);        
+             #endif            
+                if (ret < 0)return ret;
+
+        }
+
+
+        switch(params_rate(params)) {
+        case 8000:
+              sys_clk=  12288000;
+              pll_out = 12288000;
+             break; 
+        case 16000:
+             sys_clk=  11289600;
+             pll_out = 12288000;
+             break;
+        case 24000:
+             sys_clk = 24576000;
+             pll_out = 12288000;
+             break;
+        case 32000:
+             sys_clk=  12288000;
+             pll_out = 12288000;
+        case 48000:
+             sys_clk =  12288000;
+              pll_out = 12288000;
+                break;
+        /*------------------------------*/
+        case 11025:
+             sys_clk = 11289600; 
+             pll_out = 11289600;
+             break;
+        case 22050:
+             sys_clk = 11289600;
+             pll_out = 11289600;
+             break;
+
+        case 44100:
+             sys_clk = 11289600;
+             pll_out = 11289600;
+             break;
+        default:
+                DBG("rk29_hw_params for rk29_alc5623,invalid sapmleRate:%d\n",params_rate(params));
+                return -EINVAL;
+                break;
+        }
+        DBG("rk29_hw_params for rk29_alc5623, sapmleRate:%d\n",params_rate(params));
+
+                   
+          /*Set the system clk for codec*/
+           ret=snd_soc_dai_set_sysclk(codec_dai, 0,sys_clk,SND_SOC_CLOCK_IN);//ALC5621 system clk from MCLK or PLL
+           if (ret < 0)
+           {
+              DBG("rk29_hw_params_alc5623:failed to set the sysclk for codec side\n"); 
+                  return ret;
+               }
+
+            /*Set the pll of alc5621,the Pll source from MCLK no matter slave or master mode*/
+           ret=snd_soc_dai_set_pll(codec_dai,RT5621_PLL_FR_BCLK,params_rate(params)*64,sys_clk);
+           if (ret < 0)
+           { 
+              DBG("rk29_hw_params_alc5623:failed to set the pll for codec side\n"); 
+                  return ret;
+           }
+        
+
+        #if defined (CONFIG_SND_RK29_CODEC_SOC_MASTER) 
+        snd_soc_dai_set_clkdiv(codec_dai, ALC5623_BCLK_DIV, ALC5623_BCLK_DIV_4);        
+       snd_soc_dai_set_clkdiv(codec_dai, ALC5623_DAC_LRCLK,(pll_out/4)/params_rate(params));
+        snd_soc_dai_set_clkdiv(codec_dai, ALC5623_ADC_LRCLK,(pll_out/4)/params_rate(params));
+        #endif
+
+        #if defined (CONFIG_SND_RK29_CODEC_SOC_SLAVE)
+        snd_soc_dai_set_sysclk(cpu_dai, 0, pll_out, 0);
+        snd_soc_dai_set_clkdiv(cpu_dai, ROCKCHIP_DIV_BCLK, (pll_out/4)/params_rate(params)-1);
+        snd_soc_dai_set_clkdiv(cpu_dai, ROCKCHIP_DIV_MCLK, 3);
+        #endif
+        DBG("rk29_hw_params_alc5623:,LRCK=%d\n",(pll_out/4)/params_rate(params));        
+        return 0;
+}
+
+static const struct snd_soc_dapm_widget alc5623_dapm_widgets[] = {
+       SND_SOC_DAPM_LINE("Audio Out", NULL),
+       SND_SOC_DAPM_LINE("Line in", NULL),
+       SND_SOC_DAPM_MIC("Micn", NULL),
+       SND_SOC_DAPM_MIC("Micp", NULL),
+};
+
+static const struct snd_soc_dapm_route audio_map[]= {
+       
+       {"Audio Out", NULL, "HP_L"},
+       {"Audio Out", NULL, "HP_R"},
+       {"Line in", NULL, "RINPUT1"},
+       {"Line in", NULL, "LINPUT1"},
+       {"Micn", NULL, "RINPUT2"},
+       {"Micp", NULL, "LINPUT2"},
+};
+
+/*
+ * Logic for a wm8900 as connected on a rockchip board.
+ */
+static int rk29_alc5623_init(struct snd_soc_codec *codec)
+{
+         
+    DBG("rk29_alc5623_init\n");
+
+    /* Add specific widgets */
+       snd_soc_dapm_new_controls(codec, alc5623_dapm_widgets, ARRAY_SIZE(alc5623_dapm_widgets));
+               
+    /* Set up specific audio path audio_mapnects */
+    snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
+    snd_soc_dapm_nc_pin(codec, "HP_L");
+    snd_soc_dapm_nc_pin(codec, "HP_R");
+       snd_soc_dapm_sync(codec);
+    DBG("rk29_alc5623_init   end\n");
+    return 0;
+}
+
+static struct snd_soc_ops rk29_ops = {
+       .hw_params = rk29_hw_params_alc5623,
+};
+
+static struct snd_soc_dai_link rk29_dai_alc5623 = {
+       .name = "ALC5623",
+       .stream_name = "ALC5623 PCM",
+       .cpu_dai = &rk29_i2s_dai[0],
+       .codec_dai = &rt5621_dai,
+       .init = rk29_alc5623_init,
+       .ops = &rk29_ops,
+};
+
+static struct snd_soc_card snd_soc_card_rk29_alc5623 = {
+         .name = "RK29_ALC5623",
+         .platform = &rk29_soc_platform,
+         .dai_link = &rk29_dai_alc5623,
+         .num_links = 1,
+};
+
+
+static struct snd_soc_device rk29_snd_devdata_alc5623 = {
+         .card = &snd_soc_card_rk29_alc5623,
+         .codec_dev = &soc_codec_dev_rt5621,
+};
+
+static struct platform_device *rk29_snd_device_alc5623;
+
+static int __init audio_card_init_alc5623(void)
+{
+       int ret =0;     
+        DBG("audio_card_init_alc5623\n");
+       rk29_snd_device_alc5623 = platform_device_alloc("soc-audio", -1);
+       if (!rk29_snd_device_alc5623) {
+           DBG("audio_card_init_alc5623:platform device allocation failed\n");
+          ret = -ENOMEM;
+          return ret;
+       }
+       platform_set_drvdata(rk29_snd_device_alc5623, &rk29_snd_devdata_alc5623);
+       rk29_snd_devdata_alc5623.dev = &rk29_snd_device_alc5623->dev;
+       ret = platform_device_add(rk29_snd_device_alc5623);
+       if (ret) {
+               DBG("audio_card_init_alc5623:platform device add failed\n");
+               platform_device_put(rk29_snd_device_alc5623);
+       }
+       return ret;
+}
+
+static void __exit audio_card_exit_alc5623(void)
+{
+       platform_device_unregister(rk29_snd_device_alc5623);
+}
+
+module_init(audio_card_init_alc5623);
+module_exit(audio_card_exit_alc5623);
+/* Module information */
+MODULE_AUTHOR("rockchip");
+MODULE_DESCRIPTION("ROCKCHIP i2s ASoC Interface");
+MODULE_LICENSE("GPL");
old mode 100755 (executable)
new mode 100644 (file)
index cdf68ec..bba344a
@@ -123,86 +123,93 @@ static struct rockchip_pcm_dma_params rockchip_i2s_pcm_stereo_in[MAX_I2S] = {
 /* 
  *Turn on or off the transmission path. 
  */
+static int flag_i2s_tx = 0;
+static int flag_i2s_rx = 0;
 static void rockchip_snd_txctrl(struct rk29_i2s_info *i2s, int on)
 {
-        u32 opr,xfer,fifosts;
-        int  xor=0;
-    
-        opr  = readl(&(pheadi2s->I2S_DMACR));
-        xfer = readl(&(pheadi2s->I2S_XFER));
+    u32 opr,xfer,fifosts;
 
-        if(xfer & I2S_RX_TRAN_START) {
-                xor = 1;
-        }
+    opr  = readl(&(pheadi2s->I2S_DMACR));
+    xfer = readl(&(pheadi2s->I2S_XFER));
+
+    opr  &= ~I2S_TRAN_DMA_ENABLE;
+    xfer &= ~I2S_RX_TRAN_START;
+    xfer &= ~I2S_TX_TRAN_START;
+    
+    if (on) 
+    {         
+        I2S_DBG("rockchip_snd_txctrl: on\n");
         
-        opr  &= ~I2S_TRAN_DMA_ENABLE;
-        xfer &= ~I2S_TX_TRAN_START;     
+        //stop tx
+        if ((flag_i2s_rx == 0) && (flag_i2s_tx == 0))
+            writel(xfer, &(pheadi2s->I2S_XFER));
+        writel(opr, &(pheadi2s->I2S_DMACR));
+
+        //start tx
+        opr  |= I2S_TRAN_DMA_ENABLE;
+           xfer |= I2S_TX_TRAN_START;
+           xfer |= I2S_RX_TRAN_START;
+        writel(opr, &(pheadi2s->I2S_DMACR));         
+        writel(xfer, &(pheadi2s->I2S_XFER));
+
+        flag_i2s_tx = 1;
+    }
+    else
+    {
+        //stop tx
+        flag_i2s_tx = 0;
         
-        if (on) 
-        {                
-                if(xor) {
-                        xfer &= ~I2S_RX_TRAN_START;
-                }
-                writel(0, &(pheadi2s->I2S_XFER));
-                writel(opr, &(pheadi2s->I2S_DMACR));
-
-                opr  |= I2S_TRAN_DMA_ENABLE;
-                xfer |= I2S_TX_TRAN_START;
-                if(xor) {
-                        xfer |= I2S_RX_TRAN_START;
-                }
-                
-                writel(opr, &(pheadi2s->I2S_DMACR));         
-                writel(xfer, &(pheadi2s->I2S_XFER));
-        }
-        else
-        {
-                writel(xfer, &(pheadi2s->I2S_XFER));
-                udelay(5);                
-                writel(opr, &(pheadi2s->I2S_DMACR));  
+        if ((flag_i2s_rx == 0) && (flag_i2s_tx == 0))
+            writel(xfer, &(pheadi2s->I2S_XFER));
+        udelay(5);                
+        writel(opr, &(pheadi2s->I2S_DMACR));  
 
-        } 
-        I2S_DBG("Enter %s, %d, opr=0x%08X, xfer=0x%08X\n", __func__, __LINE__, opr, xfer);
+        I2S_DBG("rockchip_snd_txctrl: off\n");
+    } 
 }
 
 static void rockchip_snd_rxctrl(struct rk29_i2s_info *i2s, int on)
 {
-        u32 opr,xfer,fifosts;
-        int  xor=0;
-        
-        opr  = readl(&(pheadi2s->I2S_DMACR));
-        xfer = readl(&(pheadi2s->I2S_XFER));
+       u32 opr,xfer,fifosts;
+         
 
-        if(xfer & I2S_TX_TRAN_START){
-                xor = 1;
-        }
-        
-        opr  &= ~I2S_RECE_DMA_ENABLE;
-        xfer &= ~I2S_RX_TRAN_START;
+       opr  = readl(&(pheadi2s->I2S_DMACR));
+       xfer = readl(&(pheadi2s->I2S_XFER));
+
+       opr  &= ~I2S_RECE_DMA_ENABLE;
+       xfer &= ~I2S_RX_TRAN_START;
+       xfer &= ~I2S_TX_TRAN_START;
+       if (on) 
+       {                                
+           I2S_DBG("rockchip_snd_rxctrl: on\n");
+           
+               //stop rx
+               if ((flag_i2s_rx == 0) && (flag_i2s_tx == 0))
+               writel(xfer, &(pheadi2s->I2S_XFER));
+               writel(opr, &(pheadi2s->I2S_DMACR));
+
+               //start rx
+               opr  |= I2S_RECE_DMA_ENABLE;
+           xfer |= I2S_TX_TRAN_START;
+           xfer |= I2S_RX_TRAN_START;
+               writel(opr, &(pheadi2s->I2S_DMACR));
+               writel(xfer, &(pheadi2s->I2S_XFER));
+
+        flag_i2s_rx = 1;
+       }
+       else
+       {
+               //stop rx
+        flag_i2s_rx = 0;
         
-        if (on) 
-        {        
-                if(xor) {
-                        xfer &= ~I2S_TX_TRAN_START;
-                }
-                writel(0, &(pheadi2s->I2S_XFER));
-                writel(opr, &(pheadi2s->I2S_DMACR));  
-                
-                opr  |= I2S_RECE_DMA_ENABLE;
-                xfer |= I2S_RX_TRAN_START;
-                if(xor) {
-                        xfer |= I2S_TX_TRAN_START;
-                }
-                writel(opr, &(pheadi2s->I2S_DMACR));
-                writel(xfer, &(pheadi2s->I2S_XFER));
-        }
-        else
-        {
-                writel(xfer, &(pheadi2s->I2S_XFER));
-                udelay(5);
-                writel(opr, &(pheadi2s->I2S_DMACR));     
-        }  
-        I2S_DBG("Enter %s, %d, opr=0x%08X, xfer=0x%08X\n", __func__, __LINE__, opr, xfer);
+        if ((flag_i2s_rx == 0) && (flag_i2s_tx == 0))
+            writel(xfer, &(pheadi2s->I2S_XFER));
+        udelay(5);
+           writel(opr, &(pheadi2s->I2S_DMACR));
+           
+           I2S_DBG("rockchip_snd_rxctrl: off\n");
+       }
 }
 
 /*
@@ -569,8 +576,6 @@ static int __devinit rockchip_i2s_probe(struct platform_device *pdev)
 {
         struct rk29_i2s_info *i2s;
         struct snd_soc_dai *dai;
-               struct clk *general_pll;
-               unsigned long i2smclk;
         int    ret;
 
         I2S_DBG("Enter %s, %d pdev->id = %d >>>>>>>>>>>\n", __func__, __LINE__, pdev->id);
@@ -633,21 +638,7 @@ static int __devinit rockchip_i2s_probe(struct platform_device *pdev)
        }
 
        clk_enable(i2s->iis_clk);
-       general_pll=clk_get(NULL, "general_pll");
-       if(clk_get_rate(general_pll)>260000000)
-       {
-               i2smclk=11289600;
-       }
-       else if(clk_get_rate(general_pll)>130000000)
-       {
-               i2smclk=11289600/2;
-       }
-       else
-       {
-               i2smclk=11289600/4;
-       }
-       I2S_DBG("func is %s,general pll=%ld,mclk=%ld\n",__FUNCTION__,clk_get_rate(general_pll),i2smclk);
-       clk_set_rate(i2s->iis_clk, i2smclk);
+        clk_set_rate(i2s->iis_clk, 11289600);
        ret = rk29_i2s_probe(pdev, dai, i2s, 0);
        if (ret)
                goto err_clk;
diff --git a/sound/soc/rk29/rk29_rt5631.c b/sound/soc/rk29/rk29_rt5631.c
new file mode 100644 (file)
index 0000000..690c00a
--- /dev/null
@@ -0,0 +1,258 @@
+/*
+ * rk29_rt5631.c  --  SoC audio for rockchip
+ *
+ * Driver for rockchip rt5631 audio
+ *
+ *  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.
+ *
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <asm/io.h>
+#include <mach/hardware.h>
+#include <mach/rk29_iomap.h>
+#include "../codecs/rt5631.h"
+#include "rk29_pcm.h"
+#include "rk29_i2s.h"
+
+#if 0
+#define        DBG(x...)       printk(KERN_INFO x)
+#else
+#define        DBG(x...)
+#endif
+
+static int rk29_hw_params(struct snd_pcm_substream *substream,
+       struct snd_pcm_hw_params *params)
+{
+        struct snd_soc_pcm_runtime *rtd = substream->private_data;
+        struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
+        struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+        unsigned int pll_out = 0; 
+        unsigned int lrclk = 0;
+        int ret;
+          
+        DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);    
+        /*by Vincent Hsiung for EQ Vol Change*/
+        #define HW_PARAMS_FLAG_EQVOL_ON 0x21
+        #define HW_PARAMS_FLAG_EQVOL_OFF 0x22
+        if ((params->flags == HW_PARAMS_FLAG_EQVOL_ON)||(params->flags == HW_PARAMS_FLAG_EQVOL_OFF))
+        {
+               ret = codec_dai->ops->hw_params(substream, params, codec_dai); //by Vincent
+               DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
+        }
+        else
+        {
+                
+                /* set codec DAI configuration */
+                #if defined (CONFIG_SND_RK29_CODEC_SOC_SLAVE) 
+                ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
+                                SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
+                #endif 
+                #if defined (CONFIG_SND_RK29_CODEC_SOC_MASTER) 
+                ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
+                                SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM ); 
+                #endif
+                if (ret < 0)
+                  return ret; 
+
+                /* set cpu DAI configuration */
+                #if defined (CONFIG_SND_RK29_CODEC_SOC_SLAVE) 
+                ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
+                                SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
+                #endif 
+                #if defined (CONFIG_SND_RK29_CODEC_SOC_MASTER) 
+                ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
+                                SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);        
+                #endif         
+                if (ret < 0)
+                  return ret;
+
+        }
+
+
+        switch(params_rate(params)) {
+        case 8000:
+        case 16000:
+        case 24000:
+        case 32000:
+        case 48000:
+                pll_out = 12288000;
+                break;
+        case 11025:
+        case 22050:
+        case 44100:
+                pll_out = 11289600;
+                break;
+        default:
+                DBG("Enter:%s, %d, Error rate=%d\n",__FUNCTION__,__LINE__,params_rate(params));
+                return -EINVAL;
+                break;
+        }
+        DBG("Enter:%s, %d, rate=%d\n",__FUNCTION__,__LINE__,params_rate(params));
+
+               #if defined (CONFIG_SND_RK29_CODEC_SOC_SLAVE)
+#if 0          //use pll from blck
+          /*Set the pll of rt5631,the Pll source from BITCLK on CPU is master mode*/
+         //bitclk is 64fs           
+                   ret=snd_soc_dai_set_pll(codec_dai,0,params_rate(params)*64,pll_out);
+                   if (ret < 0)
+                   { 
+                      DBG("rk29_hw_params_rt5631:failed to set the pll for codec side\n"); 
+                          return ret;
+                   }
+#endif     
+                  /*Set the system clk for codec*/
+                   ret=snd_soc_dai_set_sysclk(codec_dai, 0,pll_out,SND_SOC_CLOCK_IN);
+                   if (ret < 0)
+                   {
+                      DBG("rk29_hw_params_rt5631:failed to set the sysclk for codec side\n"); 
+                          return ret;
+                       }           
+               #endif
+  
+/*
+        #if defined (CONFIG_SND_RK29_CODEC_SOC_MASTER) 
+
+                  if((24576000%params_rate(params))==0)        //for 8k,16k,32k,48k
+                       {
+                               snd_soc_dai_set_pll(codec_dai,0,pll_out, 24576000);
+                               snd_soc_dai_set_sysclk(codec_dai,0, 24576000, SND_SOC_CLOCK_IN);                        
+                       }
+                  else if((22579200%params_rate(params))==0)   //for 11k,22k,44k
+                       {
+                               snd_soc_dai_set_pll(codec_dai,0,pll_out, 22579200);
+                               snd_soc_dai_set_sysclk(codec_dai,0, 22579200, SND_SOC_CLOCK_IN);                        
+                       }
+      
+        #endif
+*/
+
+        #if defined (CONFIG_SND_RK29_CODEC_SOC_SLAVE)
+        snd_soc_dai_set_sysclk(cpu_dai, 0, pll_out, 0);
+        snd_soc_dai_set_clkdiv(cpu_dai, ROCKCHIP_DIV_BCLK, (pll_out/4)/params_rate(params)-1);
+        snd_soc_dai_set_clkdiv(cpu_dai, ROCKCHIP_DIV_MCLK, 3);
+        #endif
+
+        DBG("Enter:%s, %d, LRCK=%d\n",__FUNCTION__,__LINE__,(pll_out/4)/params_rate(params));
+        
+        return 0;
+}
+
+static const struct snd_soc_dapm_widget rt5631_dapm_widgets[] = {
+       
+       SND_SOC_DAPM_MIC("Mic Jack", NULL),
+       SND_SOC_DAPM_SPK("Ext Spk", NULL),
+       SND_SOC_DAPM_HP("Headphone Jack", NULL),
+
+};
+
+static const struct snd_soc_dapm_route audio_map[]={
+
+       /* Mic Jack --> MIC_IN*/
+       {"Mic Bias1", NULL, "Mic Jack"},
+       {"MIC1", NULL, "Mic Bias1"},
+       /* HP_OUT --> Headphone Jack */
+       {"Headphone Jack", NULL, "HPOL"},
+       {"Headphone Jack", NULL, "HPOR"},
+       /* LINE_OUT --> Ext Speaker */
+       {"Ext Spk", NULL, "SPOL"},
+       {"Ext Spk", NULL, "SPOR"},
+
+} ;
+
+/*
+ * Logic for a rt5631 as connected on a rockchip board.
+ */
+static int rk29_rt5631_init(struct snd_soc_codec *codec)
+{
+       struct snd_soc_dai *codec_dai = &codec->dai[0];
+       int ret;
+         
+        DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
+
+        /* Add specific widgets */
+       snd_soc_dapm_new_controls(codec, rt5631_dapm_widgets,
+                                 ARRAY_SIZE(rt5631_dapm_widgets));
+       DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
+        /* Set up specific audio path audio_mapnects */
+        snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
+        DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
+//        snd_soc_dapm_nc_pin(codec, "HP_L");
+        DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
+//     snd_soc_dapm_nc_pin(codec, "HP_R");
+       DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
+        snd_soc_dapm_sync(codec);
+        DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
+
+        return 0;
+}
+
+static struct snd_soc_ops rk29_ops = {
+         .hw_params = rk29_hw_params,
+};
+
+static struct snd_soc_dai_link rk29_dai = {
+         .name = "RT5631",
+         .stream_name = "RT5631 PCM",
+         .cpu_dai = &rk29_i2s_dai[0],
+         .codec_dai = &rt5631_dai,
+         .init = rk29_rt5631_init,
+         .ops = &rk29_ops,
+};
+
+static struct snd_soc_card snd_soc_card_rk29 = {
+         .name = "RK29_RT5631",
+         .platform = &rk29_soc_platform,
+         .dai_link = &rk29_dai,
+         .num_links = 1,
+};
+
+
+static struct snd_soc_device rk29_snd_devdata = {
+         .card = &snd_soc_card_rk29,
+         .codec_dev = &soc_codec_dev_rt5631,
+};
+
+static struct platform_device *rk29_snd_device;
+
+static int __init audio_card_init(void)
+{
+       int ret =0;     
+        DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
+       rk29_snd_device = platform_device_alloc("soc-audio", -1);
+       if (!rk29_snd_device) {
+                 DBG("platform device allocation failed\n");
+                 ret = -ENOMEM;
+                 return ret;
+       }
+       platform_set_drvdata(rk29_snd_device, &rk29_snd_devdata);
+       rk29_snd_devdata.dev = &rk29_snd_device->dev;
+       ret = platform_device_add(rk29_snd_device);
+       if (ret) {
+               DBG("platform device add failed\n");
+               platform_device_put(rk29_snd_device);
+       }
+       return ret;
+}
+
+static void __exit audio_card_exit(void)
+{
+       platform_device_unregister(rk29_snd_device);
+}
+
+module_init(audio_card_init);
+module_exit(audio_card_exit);
+/* Module information */
+MODULE_AUTHOR("rockchip");
+MODULE_DESCRIPTION("ROCKCHIP i2s ASoC Interface");
+MODULE_LICENSE("GPL");
+\r