Merge remote-tracking branch 'kernel-2.6.32/develop' into develop-2.6.36
author黄涛 <huangtao@rock-chips.com>
Mon, 1 Aug 2011 06:52:01 +0000 (14:52 +0800)
committer黄涛 <huangtao@rock-chips.com>
Mon, 1 Aug 2011 06:52:01 +0000 (14:52 +0800)
drivers/cpufreq/cpufreq_ondemand.c
sound/soc/codecs/rt5625.c.enc [new file with mode: 0644]

index 406fa1540398ad6bd7b4cfc581963181ec2a6904..11eebdac96c5aaff624f7263b99dde9af11505bc 100644 (file)
@@ -118,11 +118,7 @@ static struct dbs_tuners {
 } dbs_tuners_ins = {
        .up_threshold = DEF_FREQUENCY_UP_THRESHOLD,
        .down_differential = DEF_FREQUENCY_DOWN_DIFFERENTIAL,
-#ifdef CONFIG_ARCH_RK29
-       .ignore_nice = 1,
-#else
        .ignore_nice = 0,
-#endif
        .powersave_bias = 0,
 };
 
diff --git a/sound/soc/codecs/rt5625.c.enc b/sound/soc/codecs/rt5625.c.enc
new file mode 100644 (file)
index 0000000..78877c8
--- /dev/null
@@ -0,0 +1,2491 @@
+/*\r
+RK1 SPKOUT Mux\r
+RK11 HP Mixer\r
+RK12 SPK Mixer\r
+RK13 MoNo Mixer\r
+RK2 SPKOUT Playback Switch\r
+RK3 SPKOUT Playback Volume\r
+RK4 PCM Playback Volume\r
+RK5 Left HP Mixer\r
+RK6 Right HP Mixer\r
+RK7 HPLOUT Mux\r
+RK71 HPL Mixer\r
+RK8 HPROUT Mux\r
+RK81 HPR Mixer\r
+RK9 HPOUT Playback Switch\r
+RKA HPOUT Playback Volume\r
+RKB AUXOUT Mux\r
+RKC AUXOUT Playback Switch\r
+RKD AUXOUT Playback Volume\r
+RKE Left Rec Mixer\r
+RKF Right Rec Mixer\r
+RKG DAC Mixer Playback Switch\r
+RKH HIFI DAC Playback Switch\r
+RKI Mic1 Playback Switch\r
+RKJ Phone Playback Switch\r
+RKK Mic1 Capture Switch\r
+RKL Phone Capture Switch\r
+RKM Voice DAC Playback Switch\r
+*/\r
+\r
+\r
+#include <linux/module.h>\r
+#include <linux/moduleparam.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
+#include <linux/spi/spi.h>\r
+#include <linux/jiffies.h>\r
+#include <asm/delay.h>\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 <sound/tlv.h>\r
+#include <asm/div64.h>\r
+\r
+#include "rt5625.h"\r
+\r
+#if REALTEK_HWDEP\r
+\r
+#include <linux/ioctl.h>\r
+#include <linux/types.h>\r
+\r
+#endif\r
+\r
+#if 0\r
+#define DBG(x...) printk(KERN_INFO x)\r
+#else\r
+#define DBG(x...) do { } while (0)\r
+#endif\r
+\r
+#define AUDIO_NAME "rt5625"\r
+#define RT5625_VERSION "0.03 alsa 1.0.21"\r
+#define ALSA_SOC_VERSION "1.0.21"\r
+\r
+#define RT5625_EQ_FUNC_ENA  0\r
+\r
+static void hp_depop_mode2(struct snd_soc_codec *codec);\r
+static void hp_mute_unmute_depop(struct snd_soc_codec *codec,int mute); \r
+\r
+struct rt5625_priv {\r
+       unsigned int stereo_sysclk;\r
+       unsigned int voice_sysclk;\r
+};\r
+\r
+struct rt5625_init_reg {\r
+       u8 reg_index;\r
+       u16 reg_value;  \r
+};\r
+\r
+static struct rt5625_init_reg rt5625_init_list[] = {\r
+\r
+       {RT5625_HP_OUT_VOL                      , 0x8888},      //default is -12db\r
+       {RT5625_SPK_OUT_VOL             , 0x8080},      //default is 0db\r
+       {RT5625_DAC_AND_MIC_CTRL        , 0xee03},      //DAC to hpmixer\r
+       {RT5625_OUTPUT_MIXER_CTRL       , 0x0748},      //all output from hpmixer\r
+       {RT5625_MIC_CTRL                        , 0x0500},      //mic boost 20db\r
+       {RT5625_ADC_REC_MIXER           , 0x3f3f},      //record source from mic1\r
+       {RT5625_GEN_CTRL_REG1           , 0x0c0a},      //speaker vdd ratio is 1\r
+       {RT5625_ADC_REC_GAIN            , 0xd5d5},      //gain 15db of ADC by default\r
+\r
+};\r
+\r
+#define RT5625_INIT_REG_NUM ARRAY_SIZE(rt5625_init_list)\r
+\r
+#if (RT5625_EQ_FUNC_ENA==1)\r
+//*************************************************************************************************\r
+//eq table\r
+//*************************************************************************************************\r
+enum\r
+{\r
+       NORMAL=0,\r
+       CLUB,\r
+       DANCE,\r
+       LIVE,   \r
+       POP,\r
+       ROCK,\r
+       OPPO,\r
+       TREBLE,\r
+       BASS    \r
+};\r
+\r
+typedef struct  _HW_EQ_PRESET\r
+{\r
+       u16     HwEqType;\r
+       u16     EqValue[14];\r
+       u16  HwEQCtrl;\r
+\r
+}HW_EQ_PRESET;\r
+\r
+\r
+HW_EQ_PRESET HwEq_Preset[]={\r
+/*                     0x0             0x1             0x2       0x3   0x4             0x5             0x6             0x7     0x8             0x9             0xa     0xb             0xc             0x6e*/\r
+       {NORMAL,{0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000},0x0000},                   \r
+       {CLUB  ,{0x1C10,0x0000,0xC1CC,0x1E5D,0x0699,0xCD48,0x188D,0x0699,0xC3B6,0x1CD0,0x0699,0x0436,0x0000},0x800E},\r
+       {DANCE ,{0x1F2C,0x095B,0xC071,0x1F95,0x0616,0xC96E,0x1B11,0xFC91,0xDCF2,0x1194,0xFAF2,0x0436,0x0000},0x800F},\r
+       {LIVE  ,{0x1EB5,0xFCB6,0xC24A,0x1DF8,0x0E7C,0xC883,0x1C10,0x0699,0xDA41,0x1561,0x0295,0x0436,0x0000},0x800F},\r
+       {POP   ,{0x1EB5,0xFCB6,0xC1D4,0x1E5D,0x0E23,0xD92E,0x16E6,0xFCB6,0x0000,0x0969,0xF988,0x0436,0x0000},0x800F},\r
+       {ROCK  ,{0x1EB5,0xFCB6,0xC071,0x1F95,0x0424,0xC30A,0x1D27,0xF900,0x0C5D,0x0FC7,0x0E23,0x0436,0x0000},0x800F},\r
+       {OPPO  ,{0x0000,0x0000,0xCA4A,0x17F8,0x0FEC,0xCA4A,0x17F8,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000},0x800F},\r
+       {TREBLE,{0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x188D,0x1699},0x8010},\r
+       {BASS  ,{0x1A43,0x0C00,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000},0x8001},\r
+       \r
+};\r
+\r
+#endif\r
+//*************************************************************************************************\r
+//*************************************************************************************************\r
+\r
+/*\r
+ *     bit[0]  for linein playback switch\r
+ *     bit[1] phone\r
+ *     bit[2] mic1\r
+ *     bit[3] mic2\r
+ *     bit[4] vopcm\r
+ *     \r
+ */\r
+#define HPL_MIXER 0x80\r
+#define HPR_MIXER 0x82\r
+static unsigned int reg80 = 0, reg82 = 0;\r
+\r
+/*\r
+ *     bit[0][1][2] use for aec control\r
+ *  bit[3] for none  \r
+ *     bit[4] for SPKL pga\r
+ *     bit[5] for SPKR pga\r
+ *     bit[6] for hpl pga\r
+ *     bit[7] for hpr pga\r
+ *  bit[8] for dump dsp\r
+ *  bit[12~15] for eq function\r
+ */\r
+ #define VIRTUAL_REG_FOR_MISC_FUNC 0x84\r
+static unsigned int reg84 = 0;\r
+\r
+\r
+static const u16 rt5625_reg[] = {\r
+       0x59b4, 0x8080, 0x8080, 0x8080,         /*reg00-reg06*/\r
+       0xc800, 0xe808, 0x1010, 0x0808,         /*reg08-reg0e*/\r
+       0xe0ef, 0xcbcb, 0x7f7f, 0x0000,         /*reg10-reg16*/\r
+       0xe010, 0x0000, 0x8008, 0x2007,         /*reg18-reg1e*/\r
+       0x0000, 0x0000, 0x00c0, 0xef00,         /*reg20-reg26*/\r
+       0x0000, 0x0000, 0x0000, 0x0000,         /*reg28-reg2e*/\r
+       0x0000, 0x0000, 0x0000, 0x0000,         /*reg30-reg36*/\r
+       0x0000, 0x0000, 0x0000, 0x0000,         /*reg38-reg3e*/\r
+       0x0c0a, 0x0000, 0x0000, 0x0000,         /*reg40-reg46*/\r
+       0x0029, 0x0000, 0xbe3e, 0x3e3e,         /*reg48-reg4e*/\r
+       0x0000, 0x0000, 0x803a, 0x0000,         /*reg50-reg56*/\r
+       0x0000, 0x0009, 0x0000, 0x3000,         /*reg58-reg5e*/\r
+       0x3075, 0x1010, 0x3110, 0x0000,         /*reg60-reg66*/\r
+       0x0553, 0x0000, 0x0000, 0x0000,         /*reg68-reg6e*/\r
+       0x0000, 0x0000, 0x0000, 0x0000,         /*reg70-reg76*/\r
+       0x0000, 0x0000, 0x0000, 0x0000,     /*reg78-reg7e*/\r
+};\r
+\r
+\r
+Voice_DSP_Reg VODSP_AEC_Init_Value[]=\r
+{\r
+       {0x232C, 0x0025},\r
+       {0x230B, 0x0001},\r
+       {0x2308, 0x007F},\r
+       {0x23F8, 0x4003},\r
+       {0x2301, 0x0002},\r
+       {0x2328, 0x0001},\r
+       {0x2304, 0x00FA},\r
+       {0x2305, 0x0500},\r
+       {0x2306, 0x4000},\r
+       {0x230D, 0x0900},\r
+       {0x230E, 0x0280},\r
+       {0x2312, 0x00B1},\r
+       {0x2314, 0xC000},\r
+       {0x2316, 0x0041},\r
+       {0x2317, 0x2200},\r
+       {0x2318, 0x0C00},\r
+       {0x231D, 0x0050},\r
+       {0x231F, 0x4000},\r
+       {0x2330, 0x0008},\r
+       {0x2335, 0x000A},\r
+       {0x2336, 0x0004},\r
+       {0x2337, 0x5000},\r
+       {0x233A, 0x0300},\r
+       {0x233B, 0x0030},\r
+       {0x2341, 0x0008},\r
+       {0x2343, 0x0800},       \r
+       {0x2352, 0x7FFF},\r
+       {0x237F, 0x0400},\r
+       {0x23A7, 0x2800},\r
+       {0x22CE, 0x0400},\r
+       {0x22D3, 0x1500},\r
+       {0x22D4, 0x2800},\r
+       {0x22D5, 0x3000},\r
+       {0x2399, 0x2800},\r
+       {0x230C, 0x0000},       //to enable VODSP AEC function\r
+};\r
+\r
+\r
+#define SET_VODSP_REG_INIT_NUM ARRAY_SIZE(VODSP_AEC_Init_Value)\r
+static struct snd_soc_device *rt5625_socdev;\r
+\r
+static inline unsigned int rt5625_read_reg_cache(struct snd_soc_codec *codec, \r
+       unsigned int reg)\r
+{\r
+       u16 *cache = codec->reg_cache;\r
+\r
+       if (reg > 0x7e)\r
+               return 0;\r
+       return cache[reg / 2];\r
+}\r
+\r
+\r
+static unsigned int rt5625_read_hw_reg(struct snd_soc_codec *codec, unsigned int reg) \r
+{\r
+       u8 data[2] = {0};\r
+       unsigned int value = 0x0;\r
+       \r
+       data[0] = reg;\r
+       \r
+       i2c_master_reg8_recv(codec->control_data,reg,data,2,100 * 1000);        \r
+                     \r
+       value = (data[0]<<8) | data[1];\r
+\r
+       DBG(KERN_INFO "rt5625_read ok, reg = %x, value = %x\n", reg, value);\r
+\r
+       return value;   \r
+}\r
+\r
+\r
+static unsigned int rt5625_read(struct snd_soc_codec *codec, unsigned int reg)\r
+{\r
+       if ((reg == 0x80)\r
+               || (reg == 0x82)\r
+               || (reg == 0x84))\r
+               return (reg == 0x80) ? reg80 : ((reg == 0x82) ? reg82 : reg84);\r
+       \r
+               return rt5625_read_hw_reg(codec, reg);\r
+}\r
+\r
+\r
+static inline void rt5625_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 > 0x7E)\r
+               return;\r
+       cache[reg / 2] = value;\r
+}\r
+\r
+static int rt5625_write(struct snd_soc_codec *codec, unsigned int reg,\r
+       unsigned int value)\r
+{\r
+       u8 data[3];\r
+       unsigned int *regvalue = NULL;\r
+\r
+       data[0] = reg;\r
+       data[1] = (value & 0xff00) >> 8;\r
+       data[2] = value & 0x00ff;\r
+       \r
+       if ((reg == 0x80)\r
+               || (reg == 0x82)\r
+               || (reg == 0x84))\r
+       {               \r
+               regvalue = ((reg == 0x80) ? &reg80 : ((reg == 0x82) ? &reg82 : &reg84));\r
+               *regvalue = value;\r
+               DBG("rt5625_write ok, reg = %x, value = %x\n", reg, value);\r
+               return 0;\r
+       }\r
+       rt5625_write_reg_cache(codec, reg, value);\r
+\r
+       if (codec->hw_write(codec->control_data, data, 3) == 3)\r
+       {\r
+               DBG("rt5625_write ok, reg = %x, value = %x\n", reg, value);\r
+               return 0;\r
+       }\r
+       else \r
+       {\r
+               printk("rt5625_write fail\n");\r
+               return -EIO;\r
+       }\r
+}\r
+\r
+int rt5625_write_mask(struct snd_soc_codec *codec, unsigned int reg,unsigned int value,unsigned int mask)\r
+{\r
+       \r
+       unsigned char RetVal=0;\r
+       unsigned  int CodecData;\r
+\r
+       DBG("rt5625_write_mask ok, reg = %x, value = %x ,mask= %x\n", reg, value,mask);\r
+\r
+       if(!mask)\r
+               return 0; \r
+\r
+       if(mask!=0xffff)\r
+        {\r
+               CodecData=rt5625_read(codec,reg);               \r
+               CodecData&=~mask;\r
+               CodecData|=(value&mask);\r
+               RetVal=rt5625_write(codec,reg,CodecData);\r
+        }              \r
+       else\r
+       {\r
+               RetVal=rt5625_write(codec,reg,value);\r
+       }\r
+\r
+       return RetVal;\r
+}\r
+\r
+\r
+void rt5625_write_index(struct snd_soc_codec *codec, unsigned int reg,\r
+       unsigned int value)\r
+{\r
+       \r
+       rt5625_write(codec,0x6a,reg);\r
+       rt5625_write(codec,0x6c,value); \r
+}\r
+\r
+unsigned int rt5625_read_index(struct snd_soc_codec *codec, unsigned int reg)\r
+{\r
+       unsigned int value = 0x0;\r
+       rt5625_write(codec,0x6a,reg);\r
+       value=rt5625_read(codec,0x6c);  \r
+       \r
+       return value;\r
+}\r
+\r
+void rt5625_write_index_mask(struct snd_soc_codec *codec, unsigned int reg,unsigned int value,unsigned int mask)\r
+{\r
+       \r
+//     unsigned char RetVal=0;\r
+       unsigned  int CodecData;\r
+\r
+       DBG("rt5625_write_index_mask ok, reg = %x, value = %x ,mask= %x\n", reg, value,mask);\r
+\r
+       if(!mask)\r
+               return; \r
+\r
+       if(mask!=0xffff)\r
+        {\r
+               CodecData=rt5625_read_index(codec,reg);         \r
+               CodecData&=~mask;\r
+               CodecData|=(value&mask);\r
+               rt5625_write_index(codec,reg,CodecData);\r
+        }              \r
+       else\r
+       {\r
+               rt5625_write_index(codec,reg,value);\r
+       }\r
+}\r
+\r
+//#define rt5625_write_mask(c, reg, value, mask) snd_soc_update_bits(c, reg, mask, value)\r
+\r
+#define rt5625_reset(c) rt5625_write(c, RT5625_RESET, 0)\r
+\r
+/*read/write dsp reg*/\r
+static int rt5625_wait_vodsp_i2c_done(struct snd_soc_codec *codec)\r
+{\r
+       unsigned int checkcount = 0, vodsp_data;\r
+\r
+       vodsp_data = rt5625_read(codec, RT5625_VODSP_REG_CMD);\r
+       while(vodsp_data & VODSP_BUSY)\r
+       {\r
+               if(checkcount > 10)\r
+                       return -EBUSY;\r
+               vodsp_data = rt5625_read(codec, RT5625_VODSP_REG_CMD);\r
+               checkcount ++;          \r
+       }\r
+       return 0;\r
+}\r
+\r
+static int rt5625_write_vodsp_reg(struct snd_soc_codec *codec, unsigned int vodspreg, unsigned int value)\r
+{\r
+       int ret = 0;\r
+\r
+       if(ret != rt5625_wait_vodsp_i2c_done(codec))\r
+               return -EBUSY;\r
+\r
+       rt5625_write(codec, RT5625_VODSP_REG_ADDR, vodspreg);\r
+       rt5625_write(codec, RT5625_VODSP_REG_DATA, value);\r
+       rt5625_write(codec, RT5625_VODSP_REG_CMD, VODSP_WRITE_ENABLE | VODSP_CMD_MW);\r
+       mdelay(10);\r
+       return ret;\r
+       \r
+}\r
+\r
+static unsigned int rt5625_read_vodsp_reg(struct snd_soc_codec *codec, unsigned int vodspreg)\r
+{\r
+       int ret = 0;\r
+       unsigned int nDataH, nDataL;\r
+       unsigned int value;\r
+\r
+       if(ret != rt5625_wait_vodsp_i2c_done(codec))\r
+               return -EBUSY;\r
+       \r
+       rt5625_write(codec, RT5625_VODSP_REG_ADDR, vodspreg);\r
+       rt5625_write(codec, RT5625_VODSP_REG_CMD, VODSP_READ_ENABLE | VODSP_CMD_MR);\r
+\r
+       if (ret != rt5625_wait_vodsp_i2c_done(codec))\r
+               return -EBUSY;\r
+       rt5625_write(codec, RT5625_VODSP_REG_ADDR, 0x26);\r
+       rt5625_write(codec, RT5625_VODSP_REG_CMD, VODSP_READ_ENABLE | VODSP_CMD_RR);\r
+\r
+       if(ret != rt5625_wait_vodsp_i2c_done(codec))\r
+               return -EBUSY;\r
+       nDataH = rt5625_read(codec, RT5625_VODSP_REG_DATA);\r
+       rt5625_write(codec, RT5625_VODSP_REG_ADDR, 0x25);\r
+       rt5625_write(codec, RT5625_VODSP_REG_CMD, VODSP_READ_ENABLE | VODSP_CMD_RR);\r
+\r
+       if(ret != rt5625_wait_vodsp_i2c_done(codec))\r
+               return -EBUSY;\r
+       nDataL = rt5625_read(codec, RT5625_VODSP_REG_DATA);\r
+       value = ((nDataH & 0xff) << 8) |(nDataL & 0xff);\r
+       DBG("%s vodspreg=0x%x, value=0x%x\n", __func__, vodspreg, value);\r
+       return value;\r
+}\r
+\r
+static int rt5625_reg_init(struct snd_soc_codec *codec)\r
+{\r
+       int i;\r
+\r
+       for (i = 0; i < RT5625_INIT_REG_NUM; i++)\r
+               rt5625_write(codec, rt5625_init_list[i].reg_index, rt5625_init_list[i].reg_value);\r
+\r
+       return 0;\r
+}\r
+\r
+//*************************************************************************************************\r
+//*************************************************************************************************\r
+#if (RT5625_EQ_FUNC_ENA==1)    \r
+//eq function\r
+static void rt5625_update_eqmode(struct snd_soc_codec *codec, int mode)\r
+{\r
+       u16 HwEqIndex=0;\r
+\r
+       if(mode==NORMAL)\r
+       {\r
+               /*clear EQ parameter*/\r
+               for(HwEqIndex=0;HwEqIndex<=0x0C;HwEqIndex++)\r
+               {\r
+                       rt5625_write_index(codec, HwEqIndex, HwEq_Preset[mode].EqValue[HwEqIndex]);\r
+               }\r
+               \r
+               rt5625_write_mask(codec, 0x6e,0x0,EN_HW_EQ_BLK | EN_HW_EQ_HPF | EN_HW_EQ_BP3 | EN_HW_EQ_BP2 | EN_HW_EQ_BP1 | EN_HW_EQ_LPF);             /*disable EQ block*/\r
+       }\r
+       else\r
+       {               \r
+               /*Fill EQ parameter*/\r
+               for(HwEqIndex=0;HwEqIndex<=0x0C;HwEqIndex++)\r
+               {\r
+                       rt5625_write_index(codec, HwEqIndex, HwEq_Preset[mode].EqValue[HwEqIndex]); \r
+               }               \r
+\r
+               //enable EQ block\r
+               rt5625_write_mask(codec, 0x6e,HwEq_Preset[mode].HwEQCtrl,EN_HW_EQ_BLK | EN_HW_EQ_HPF | EN_HW_EQ_BP3 | EN_HW_EQ_BP2 | EN_HW_EQ_BP1 | EN_HW_EQ_LPF);              \r
+               \r
+               //update EQ parameter\r
+               rt5625_write_mask(codec, 0x6e,0x0080,0x0080);\r
+       }\r
+}\r
+\r
+\r
+static int rt5625_eq_sel_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)\r
+{\r
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);\r
+       u16 Virtual_reg = rt5625_read(codec, VIRTUAL_REG_FOR_MISC_FUNC);\r
+       int rt5625_mode=((Virtual_reg)&0xf000)>>12;\r
+       \r
+       if ( rt5625_mode == ucontrol->value.integer.value[0])\r
+               return 0;\r
+\r
+       rt5625_update_eqmode(codec, ucontrol->value.enumerated.item[0]);\r
+\r
+       Virtual_reg &= 0x0fff;\r
+       Virtual_reg |= (ucontrol->value.integer.value[0])<<12;\r
+       rt5625_write(codec, VIRTUAL_REG_FOR_MISC_FUNC, Virtual_reg);            \r
+       \r
+       return 0;\r
+}\r
+#endif\r
+//*************************************************************************************************\r
+//*************************************************************************************************\r
+static const char *rt5625_aec_path_sel[] = {"aec func disable","aec func for pcm in/out",\r
+                                            "aec func for iis in/out","aec func for analog in/out"};           /*0*/                   \r
+static const char *rt5625_spk_out_sel[] = {"Class AB", "Class D"};                                     /*1*/\r
+static const char *rt5625_spk_l_source_sel[] = {"LPRN", "LPRP", "LPLN", "MM"};         /*2*/   \r
+static const char *rt5625_spkmux_source_sel[] = {"VMID", "RK11", \r
+                                                       "RK12", "RK13"};                                                /*3*/\r
+static const char *rt5625_hplmux_source_sel[] = {"VMID","RK71"};                               /*4*/\r
+static const char *rt5625_hprmux_source_sel[] = {"VMID","RK81"};                               /*5*/\r
+static const char *rt5625_auxmux_source_sel[] = {"VMID", "RK11", \r
+                                                       "RK12", "RK13"};                                                        /*6*/\r
+static const char *rt5625_spkamp_ratio_sel[] = {"2.25 Vdd", "2.00 Vdd",\r
+                                       "1.75 Vdd", "1.50 Vdd", "1.25 Vdd", "1.00 Vdd"};                                /*7*/\r
+static const char *rt5625_mic1_boost_sel[] = {"Bypass", "+20db", "+30db", "+40db"};    /*8*/\r
+static const char *rt5625_mic2_boost_sel[] = {"Bypass", "+20db", "+30db", "+40db"};    /*9*/\r
+static const char *rt5625_dmic_boost_sel[] = {"Bypass", "+6db", "+12db", "+18db", \r
+                                       "+24db", "+30db", "+36db", "+42db"};                                            /*10*/\r
+static const char *rt5625_adcr_func_sel[] = {"Stereo ADC", "Voice ADC", \r
+                                       "VoDSP Interface", "PDM Slave Interface"};                                   /*11*/\r
+#if (RT5625_EQ_FUNC_ENA==1)                                    \r
+static const char *rt5625_eq_sel[] = {"NORMAL", "CLUB","DANCE", "LIVE","POP",                  /*12*/\r
+                                       "ROCK", "OPPO", "TREBLE", "BASS"};                                      \r
+#endif\r
+\r
+static const struct soc_enum rt5625_enum[] = {\r
+\r
+SOC_ENUM_SINGLE(VIRTUAL_REG_FOR_MISC_FUNC, 0, 4, rt5625_aec_path_sel),         /*0*/\r
+SOC_ENUM_SINGLE(RT5625_OUTPUT_MIXER_CTRL, 13, 2, rt5625_spk_out_sel),          /*1*/\r
+SOC_ENUM_SINGLE(RT5625_OUTPUT_MIXER_CTRL, 14, 4, rt5625_spk_l_source_sel),     /*2*/\r
+SOC_ENUM_SINGLE(RT5625_OUTPUT_MIXER_CTRL, 10, 4, rt5625_spkmux_source_sel),/*3*/\r
+SOC_ENUM_SINGLE(RT5625_OUTPUT_MIXER_CTRL, 9, 2, rt5625_hplmux_source_sel),     /*4*/\r
+SOC_ENUM_SINGLE(RT5625_OUTPUT_MIXER_CTRL, 8, 2, rt5625_hprmux_source_sel),/*5*/\r
+SOC_ENUM_SINGLE(RT5625_OUTPUT_MIXER_CTRL, 6, 4, rt5625_auxmux_source_sel),/*6*/\r
+SOC_ENUM_SINGLE(RT5625_GEN_CTRL_REG1, 1, 6, rt5625_spkamp_ratio_sel),          /*7*/\r
+SOC_ENUM_SINGLE(RT5625_MIC_CTRL, 10, 4,  rt5625_mic1_boost_sel),                       /*8*/\r
+SOC_ENUM_SINGLE(RT5625_MIC_CTRL, 8, 4, rt5625_mic2_boost_sel),                         /*9*/\r
+SOC_ENUM_SINGLE(RT5625_DMIC_CTRL, 0, 8, rt5625_dmic_boost_sel),                                /*10*/\r
+SOC_ENUM_SINGLE(RT5625_DAC_ADC_VODAC_FUN_SEL, 4, 4, rt5625_adcr_func_sel), /*11*/\r
+#if (RT5625_EQ_FUNC_ENA==1)\r
+SOC_ENUM_SINGLE(VIRTUAL_REG_FOR_MISC_FUNC, 12, 9, rt5625_eq_sel),    /*EQ mode select mode 12*/\r
+#endif\r
+};\r
+\r
+\r
+\r
+//*****************************************************************************\r
+//function:Enable the Voice PCM interface Path\r
+//*****************************************************************************\r
+static int ConfigPcmVoicePath(struct snd_soc_codec *codec,unsigned int bEnableVoicePath,unsigned int mode)\r
+{\r
+\r
+       if(bEnableVoicePath)\r
+        {\r
+                       //Power on DAC reference\r
+                       rt5625_write_mask(codec,RT5625_PWR_MANAG_ADD1,PWR_DAC_REF|PWR_VOICE_DF2SE,PWR_DAC_REF|PWR_VOICE_DF2SE);\r
+                       //Power on Voice DAC/ADC \r
+                       rt5625_write_mask(codec,RT5625_PWR_MANAG_ADD2,PWR_VOICE_CLOCK,PWR_VOICE_CLOCK);\r
+                       //routing voice to HPMixer\r
+                       rt5625_write_mask(codec,RT5625_VOICE_DAC_OUT_VOL,0,M_V_DAC_TO_HP_MIXER);\r
+                                       \r
+               switch(mode)            \r
+               {\r
+                       case PCM_SLAVE_MODE_B:  //8kHz sampling rate,16 bits PCM mode and Slave mode,PCM mode is B,MCLK=24.576MHz from Oscillator.\r
+                                                               //CSR PSKEY_PCM_CONFIG32 (HEX) = 0x08C00000,PSKEY_FORMAT=0x0060                         \r
+\r
+                               //Enable GPIO 1,3,4,5 to voice interface\r
+                               //Set I2S to Slave mode\r
+                               //Voice I2S SYSCLK Source select Main SYSCLK\r
+                               //Set voice I2S VBCLK Polarity to Invert\r
+                               //Set Data length to 16 bit\r
+                               //set Data Fomrat to PCM mode B\r
+                               //the register 0x36 value's should is 0xC083\r
+                               rt5625_write(codec,RT5625_EXTEND_SDP_CTRL,0xC083);\r
+\r
+                               //Set LRCK voice select divide 32\r
+                               //set voice blck select divide 6 and 8 \r
+                               //voice filter clock divide 3 and 16\r
+                               //the register 0x64 value's should is 0x5524\r
+                               rt5625_write(codec,RT5625_VOICE_DAC_PCMCLK_CTRL1,0x5524);\r
+               \r
+                               break;\r
+\r
+                       case PCM_SLAVE_MODE_A:  //8kHz sampling rate,16 bits PCM and Slave mode,PCM mode is A,MCLK=24.576MHz from Oscillator.\r
+                                                               //CSR PSKEY_PCM_CONFIG32 (HEX) = 0x08C00004,PSKEY_FORMAT=0x0060                         \r
+\r
+                               //Enable GPIO 1,3,4,5 to voice interface\r
+                               //Set I2S to Slave mode\r
+                               //Voice I2S SYSCLK Source select Main SYSCLK\r
+                               //Set voice i2s VBCLK Polarity to Invert\r
+                               //Set Data length to 16 bit\r
+                               //set Data Fomrat to PCM mode A\r
+                               //the register 0x36 value's should is 0xC082\r
+                               rt5625_write(codec,RT5625_EXTEND_SDP_CTRL,0xC082);\r
+\r
+                               //Set LRCK voice select divide 64\r
+                               //set voice blck select divide 6 and 8 \r
+                               //voice filter clock divide 3 and 16\r
+                               //the register 0x64 value's should is 0x5524\r
+                               rt5625_write(codec,RT5625_VOICE_DAC_PCMCLK_CTRL1,0x5524);\r
+               \r
+                               break;\r
+\r
+                       case PCM_MASTER_MODE_B: //8kHz sampling rate,16 bits PCM and Master mode,PCM mode is B,Clock from PLL OUT\r
+                                                               //CSR PSKEY_PCM_CONFIG32 (HEX) = 0x08000002,PSKEY_FORMAT=0x0060 \r
+\r
+                               //Enable GPIO 1,3,4,5 to voice interface\r
+                               //Set I2S to master mode\r
+                               //Set voice i2s VBCLK Polarity to Invert\r
+                               //Set Data length to 16 bit\r
+                               //set Data Fomrat to PCM mode B\r
+                               //the register 0x36 value's should is 0x8083\r
+                               rt5625_write(codec,RT5625_EXTEND_SDP_CTRL,0x8083);\r
+\r
+                               //Set LRCK voice select divide 64\r
+                               //set voice blck select divide 6 and 8 \r
+                               //voice filter clock divide 3 and 16\r
+                               //the register 0x64 value's should is 0x5524\r
+                               rt5625_write(codec,RT5625_VOICE_DAC_PCMCLK_CTRL1,0x5524);\r
+               \r
+                               break;\r
+\r
+                       default:\r
+                               //do nothing            \r
+                               break;\r
+\r
+                       }\r
+               }\r
+               else\r
+               {       \r
+                       //Power down Voice Different to sing-end power\r
+                       rt5625_write_mask(codec,RT5625_PWR_MANAG_ADD1,0,PWR_VOICE_DF2SE);\r
+                       //Power down Voice DAC/ADC \r
+                       rt5625_write_mask(codec,RT5625_PWR_MANAG_ADD2,0,PWR_VOICE_CLOCK);\r
+                       //Disable Voice PCM interface   \r
+                       rt5625_write_mask(codec,RT5625_EXTEND_SDP_CTRL,0,EXT_I2S_FUNC_ENABLE);                  \r
+               }\r
+       \r
+       return 0;\r
+}\r
+\r
+static int init_vodsp_aec(struct snd_soc_codec *codec)\r
+{\r
+       int i;\r
+       int ret = 0;\r
+\r
+       /*disable LDO power*/\r
+       rt5625_write_mask(codec, RT5625_LDO_CTRL,0,LDO_ENABLE);\r
+       mdelay(20);     \r
+       rt5625_write_mask(codec, RT5625_VODSP_CTL,VODSP_NO_PD_MODE_ENA,VODSP_NO_PD_MODE_ENA);\r
+       /*enable LDO power and set output voltage to 1.2V*/\r
+       rt5625_write_mask(codec, RT5625_LDO_CTRL,LDO_ENABLE|LDO_OUT_VOL_CTRL_1_20V,LDO_ENABLE|LDO_OUT_VOL_CTRL_MASK);\r
+       mdelay(20);\r
+       /*enable power of VODSP I2C interface*/ \r
+       rt5625_write_mask(codec, RT5625_PWR_MANAG_ADD3,PWR_VODSP_INTERFACE|PWR_I2C_FOR_VODSP,PWR_VODSP_INTERFACE|PWR_I2C_FOR_VODSP);\r
+       mdelay(1);\r
+       rt5625_write_mask(codec, RT5625_VODSP_CTL,0,VODSP_NO_RST_MODE_ENA);     /*Reset VODSP*/\r
+       mdelay(1);\r
+       rt5625_write_mask(codec, RT5625_VODSP_CTL,VODSP_NO_RST_MODE_ENA,VODSP_NO_RST_MODE_ENA); /*set VODSP to non-reset status*/               \r
+       mdelay(20);\r
+\r
+       /*initize AEC paramter*/\r
+       for(i = 0; i < SET_VODSP_REG_INIT_NUM; i++)\r
+       {\r
+               ret = rt5625_write_vodsp_reg(codec, VODSP_AEC_Init_Value[i].VoiceDSPIndex,VODSP_AEC_Init_Value[i].VoiceDSPValue);\r
+               if(ret)\r
+                       return -EIO;\r
+       }               \r
+\r
+       schedule_timeout_uninterruptible(msecs_to_jiffies(10)); \r
+\r
+       return 0;\r
+}\r
+\r
+//***********************************************************************************************\r
+//function:Enable/Disable the vodsp interface Path\r
+//For system clock only suport specific clock,realtek suggest customer to use 24.576Mhz or 22.5792Mhz\r
+//clock fro MCLK(MCLK=48k*512 or 44.1k*512Mhz)\r
+//***********************************************************************************************\r
+static int set_vodsp_aec_path(struct snd_soc_codec *codec, unsigned int mode)\r
+{\r
+\r
+               switch(mode)\r
+               {\r
+\r
+                       case PCM_IN_PCM_OUT:\r
+                               //set PCM format\r
+                               ConfigPcmVoicePath(codec,1,PCM_MASTER_MODE_B);\r
+                               //set AEC path\r
+                               rt5625_write_mask(codec, 0x26,0x0300,0x0300);\r
+                               rt5625_write_mask(codec, RT5625_VODSP_PDM_CTL,VODSP_RXDP_PWR|VODSP_RXDP_S_SEL_VOICE|VOICE_PCM_S_SEL_AEC_TXDP\r
+                                                                                                                        ,VODSP_RXDP_PWR|VODSP_RXDP_S_SEL_MASK|VOICE_PCM_S_SEL_MASK);\r
+                               rt5625_write_mask(codec, RT5625_DAC_ADC_VODAC_FUN_SEL,ADCR_FUNC_SEL_PDM|VODAC_SOUR_SEL_VODSP_TXDC\r
+                                                                                                                                       ,ADCR_FUNC_SEL_MASK|VODAC_SOUR_SEL_MASK);\r
+                               rt5625_write_mask(codec, RT5625_VODSP_CTL,VODSP_LRCK_SEL_8K,VODSP_LRCK_SEL_MASK);                                               \r
+                               rt5625_write_mask(codec, 0x26,0x0000,0x0300);\r
+                               //set input&output path and power\r
+                               rt5625_write_mask(codec, 0x3a,0x0c8f,0x0c8f);//power on related bit\r
+                               rt5625_write_mask(codec, 0x3c,0xa4cb,0xa4cb);//power on related bit\r
+                               rt5625_write_mask(codec, 0x3e,0x3302,0xf302);//power on related bit\r
+                                               \r
+                               rt5625_write(codec, 0x10, 0xee0f);//mute DAC to hpmixer\r
+                               rt5625_write(codec, 0x0e, 0x8808);//set Mic1 to differential mode\r
+                               rt5625_write(codec, 0x22, 0x0000);//Mic boost 0db\r
+                               rt5625_write(codec, 0x12, 0xCBD3);//ADC_Mixer_R boost 10.5 db\r
+                               rt5625_write(codec, 0x14, 0x7f3f);//Mic1->ADCMixer_R\r
+                               rt5625_write(codec, 0x18, 0xa010);//VoDAC to speakerMixer,0db\r
+                               rt5625_write(codec, 0x1c, 0x8808);//speaker source from speakermixer\r
+                                                       \r
+                               rt5625_write_mask(codec, 0x02,0x0000,0x8080);   //unmute speaker \r
+\r
+                               break;\r
+                       \r
+                       \r
+                       case ANALOG_IN_ANALOG_OUT:      \r
+                               rt5625_write_mask(codec, 0x26,0x0300,0x0300);\r
+                               rt5625_write_mask(codec, RT5625_VODSP_PDM_CTL,VODSP_RXDP_PWR|VODSP_RXDP_S_SEL_ADCL|VOICE_PCM_S_SEL_AEC_TXDP\r
+                                                                                                                        ,VODSP_RXDP_PWR|VODSP_RXDP_S_SEL_MASK|VOICE_PCM_S_SEL_MASK);\r
+                               rt5625_write_mask(codec, RT5625_DAC_ADC_VODAC_FUN_SEL,ADCR_FUNC_SEL_PDM|VODAC_SOUR_SEL_VODSP_TXDC|DAC_FUNC_SEL_VODSP_TXDP|ADCL_FUNC_SEL_VODSP\r
+                                                                                                                                       ,ADCR_FUNC_SEL_MASK|VODAC_SOUR_SEL_MASK|DAC_FUNC_SEL_MASK|ADCL_FUNC_SEL_MASK);\r
+                               rt5625_write_mask(codec, RT5625_VODSP_CTL,VODSP_LRCK_SEL_16K,VODSP_LRCK_SEL_MASK);      \r
+                               rt5625_write_mask(codec, 0x26,0x0000,0x0300);\r
+                               //set input&output path and power\r
+                               rt5625_write_mask(codec, 0x3a,0xcc8f,0xcc8f);//power on related bit\r
+                               rt5625_write_mask(codec, 0x3c,0xa7cf,0xa7cf);//power on related bit\r
+                               rt5625_write_mask(codec, 0x3e,0xf312,0xf312);//power on related bit\r
+                               \r
+                               rt5625_write(codec, 0x0e, 0x8808);//set Mic1 to differential mode\r
+                               rt5625_write(codec, 0x08, 0xe800);//set phone in to differential mode\r
+                               rt5625_write(codec, 0x22, 0x0000);//Mic boost 0db\r
+                               rt5625_write(codec, 0x14, 0x773f);//Mic1->ADCMixer_R,phone in-->ADCMixer_L\r
+                               rt5625_write(codec, 0x12, 0xCBD3);//ADC_Mixer_R boost 10.5 db\r
+                               rt5625_write(codec, 0x1c, 0x88c8);//speaker from spkmixer,monoOut from monoMixer\r
+                               rt5625_write(codec, 0x18, 0xA010);//unmute VoDAC to spkmixer\r
+                               rt5625_write(codec, 0x10, 0xee0e);//unmute DAC to monoMixer     \r
+                               rt5625_write(codec, 0x62, 0x2222);\r
+                               rt5625_write(codec, 0x64, 0x3122);\r
+                               rt5625_write_mask(codec, 0x02,0x0000,0x8080);   //unmute speaker \r
+                               rt5625_write_mask(codec, 0x06,0x0000,0x8080);   //unmute auxout \r
+                               break;\r
+\r
+                       case DAC_IN_ADC_OUT:    \r
+                               rt5625_write_mask(codec, 0x26,0x0300,0x0300);\r
+                               rt5625_write_mask(codec,RT5625_DAC_ADC_VODAC_FUN_SEL,ADCR_FUNC_SEL_PDM|DAC_FUNC_SEL_VODSP_TXDC\r
+                                                                                                                                       ,ADCR_FUNC_SEL_MASK|DAC_FUNC_SEL_MASK);\r
+                               rt5625_write_mask(codec,RT5625_VODSP_PDM_CTL,VODSP_SRC1_PWR|VODSP_SRC2_PWR|VODSP_RXDP_PWR|VODSP_RXDP_S_SEL_SRC1|REC_S_SEL_SRC2,\r
+                                                                                                                        VODSP_SRC1_PWR|VODSP_SRC2_PWR|VODSP_RXDP_PWR|VODSP_RXDP_S_SEL_MASK|REC_S_SEL_MASK);                                    \r
+                               rt5625_write_mask(codec,RT5625_VODSP_CTL,VODSP_LRCK_SEL_16K,VODSP_LRCK_SEL_MASK);\r
+                               rt5625_write_mask(codec, 0x26,0x0000,0x0300);\r
+                               //set input&output path and power       \r
+                               rt5625_write_mask(codec, 0x3a,0xcc0f,0xcc0f);//power on related bit\r
+                               rt5625_write_mask(codec, 0x3c,0xa7cb,0xa7cb);//power on related bit\r
+                               rt5625_write_mask(codec, 0x3e,0x3302,0x3302);//power on related bit\r
+                               \r
+                               rt5625_write(codec, 0x0e, 0x8808);//set Mic1 to differential mode\r
+                               rt5625_write(codec, 0x22, 0x0000);//Mic boost 0db\r
+                               rt5625_write(codec, 0x14, 0x7f3f);//Mic1->ADCMixer_R\r
+                               rt5625_write(codec, 0x12, 0xCBD3);//ADC_Mixer_R boost 10.5 db\r
+                               rt5625_write(codec, 0x1c, 0x8808);//speaker out from spkMixer\r
+                               rt5625_write(codec, 0x10, 0xee0d);//unmute DAC to spkMixer      \r
+                               rt5625_write(codec, 0x60, 0x3075);\r
+                               rt5625_write(codec, 0x62, 0x1010);                                      \r
+                               rt5625_write_mask(codec, 0x02,0x0000,0x8080);   //unmute speaker \r
+\r
+                               break;\r
+\r
+                       case VODSP_AEC_DISABLE:\r
+                       default:\r
+                               rt5625_write_mask(codec, 0x02,0x8080,0x8080);//mute speaker out\r
+                               rt5625_write_mask(codec, 0x06,0x8080,0x8080);//mute auxout              \r
+                               rt5625_write(codec, 0x22, 0x0500);//Mic boost 20db by default\r
+                               rt5625_write(codec, 0x14, 0x3f3f);//record from Mic1 by default\r
+                               rt5625_write(codec, 0x12, 0xD5D5);//ADC_Mixer_R boost 15 db by default\r
+                               rt5625_write(codec, 0x1c, 0x0748);//all output from HPmixer by default\r
+                               rt5625_write(codec, 0x10, 0xee03);//DAC to HPmixer by default\r
+                               rt5625_write(codec, 0x18, 0xe010);//mute VoDAC to mixer by default\r
+                               rt5625_write_mask(codec, 0x26,0x0300,0x0300);\r
+                               /*set stereo DAC&Voice DAC&Stereo ADC function select to default*/ \r
+                               rt5625_write(codec, RT5625_DAC_ADC_VODAC_FUN_SEL,0);            \r
+                               /*set VODSP&PDM Control to default*/ \r
+                               rt5625_write(codec, RT5625_VODSP_PDM_CTL,0);\r
+                               rt5625_write_mask(codec, 0x26,0x0000,0x0300);           \r
+                               rt5625_write_mask(codec, 0x3e,0x0000,0xf312);//power down related bit\r
+                               rt5625_write_mask(codec, 0x3a,0x0000,0xcc8d);//power down related bit\r
+                               rt5625_write_mask(codec, 0x3c,0x0000,0x07cf);//power down related bit\r
+                               \r
+                       \r
+                               break;\r
+               }               \r
+\r
+       return 0;\r
+}\r
+\r
+static int enable_vodsp_aec(struct snd_soc_codec *codec, unsigned int VodspAEC_En, unsigned int AEC_mode)\r
+{\r
+       int  ret = 0;\r
+\r
+       \r
+       if (VodspAEC_En != 0)\r
+       {       \r
+\r
+               //enable power of VODSP I2C interface & VODSP interface\r
+               rt5625_write_mask(codec, RT5625_PWR_MANAG_ADD3,PWR_VODSP_INTERFACE|PWR_I2C_FOR_VODSP,PWR_VODSP_INTERFACE|PWR_I2C_FOR_VODSP);\r
+               //enable power of VODSP I2S interface \r
+               rt5625_write_mask(codec, RT5625_PWR_MANAG_ADD1,PWR_I2S_INTERFACE,PWR_I2S_INTERFACE);    \r
+               //select input/output of VODSP AEC\r
+               set_vodsp_aec_path(codec, AEC_mode);            \r
+\r
+       }\r
+       else\r
+       {\r
+               //disable VODSP AEC path\r
+               set_vodsp_aec_path(codec, VODSP_AEC_DISABLE);\r
+               //set VODSP AEC to power down mode                      \r
+               rt5625_write_mask(codec, RT5625_VODSP_CTL,0,VODSP_NO_PD_MODE_ENA);\r
+               //disable power of VODSP I2C interface & VODSP interface\r
+               rt5625_write_mask(codec, RT5625_PWR_MANAG_ADD3,0,PWR_VODSP_INTERFACE|PWR_I2C_FOR_VODSP);                                \r
+       }\r
+\r
+       return ret;\r
+}\r
+\r
+static void rt5625_aec_config(struct snd_soc_codec *codec, unsigned int mode)\r
+{\r
+       DBG("rt5625_aec_config %d\n",mode);\r
+\r
+       if (mode == VODSP_AEC_DISABLE)\r
+       {\r
+               enable_vodsp_aec(codec,0, mode);        \r
+               /*disable LDO power*/\r
+               rt5625_write_mask(codec, RT5625_LDO_CTRL,0,LDO_ENABLE);\r
+       }\r
+       else\r
+       {\r
+               init_vodsp_aec(codec);\r
+       \r
+               enable_vodsp_aec(codec,1, mode);                \r
+       }\r
+}\r
+//****************************************************************************************************************\r
+//*\r
+//*function:disable rt5625's function.\r
+//*\r
+//*\r
+//****************************************************************************************************************\r
+static int rt5625_func_aec_disable(struct snd_soc_codec *codec,int mode)\r
+{\r
+\r
+       switch(mode)\r
+       {\r
+               case RT5625_AEC_PCM_IN_OUT:\r
+               case RT5625_AEC_IIS_IN_OUT:\r
+               case RT5625_AEC_ANALOG_IN_OUT:\r
+                       \r
+                       rt5625_aec_config(codec,VODSP_AEC_DISABLE);     //disable AEC function and path\r
+                       \r
+               break;\r
+               \r
+               default:\r
+\r
+               break;\r
+       }\r
+\r
+       return 0;\r
+}\r
+\r
+\r
+static int rt5625_get_dsp_mode(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)\r
+{\r
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);\r
+        /*cause we choose bit[0][1] to store the mode type*/\r
+       int mode = (rt5625_read(codec, VIRTUAL_REG_FOR_MISC_FUNC)) & 0x03;  \r
+\r
+       ucontrol->value.integer.value[0] = mode;\r
+       return 0;\r
+}\r
+\r
+\r
+static int rt5625_set_dsp_mode(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)\r
+{\r
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);\r
+       u16 Virtual_reg = rt5625_read(codec, VIRTUAL_REG_FOR_MISC_FUNC);\r
+       int rt5625_mode=(Virtual_reg)&0x03;\r
+\r
+       DBG("rt5625_mode=%d,value[0]=%ld,Virtual_reg=%x\n",rt5625_mode,ucontrol->value.integer.value[0],Virtual_reg);\r
+\r
+       if ( rt5625_mode == ucontrol->value.integer.value[0])\r
+               return 0;\r
+\r
+       switch(ucontrol->value.integer.value[0])\r
+       {\r
+               case RT5625_AEC_PCM_IN_OUT:\r
+\r
+                       rt5625_aec_config(codec,PCM_IN_PCM_OUT);//enable AEC PCM in/out function and path\r
+\r
+               break;\r
+\r
+               case RT5625_AEC_IIS_IN_OUT:\r
+\r
+                       rt5625_aec_config(codec,DAC_IN_ADC_OUT);//enable AEC IIS in/out function and path\r
+\r
+               break;\r
+\r
+               case RT5625_AEC_ANALOG_IN_OUT:\r
+                       \r
+                       rt5625_aec_config(codec,ANALOG_IN_ANALOG_OUT);//enable AEC analog in/out function and path\r
+                       \r
+               break;\r
+\r
+               case RT5625_AEC_DISABLE:\r
+       \r
+                       rt5625_func_aec_disable(codec,rt5625_mode);             //disable previous select function.     \r
+       \r
+               break;  \r
+\r
+               default:\r
+\r
+               break;\r
+       }\r
+\r
+       Virtual_reg &= 0xfffc;\r
+       Virtual_reg |= (ucontrol->value.integer.value[0]);\r
+       rt5625_write(codec, VIRTUAL_REG_FOR_MISC_FUNC, Virtual_reg);\r
+\r
+       DBG("2rt5625_mode=%d,value[0]=%ld,Virtual_reg=%x\n",rt5625_mode,ucontrol->value.integer.value[0],Virtual_reg);\r
+       return 0;\r
+}\r
+\r
+static int rt5625_dump_dsp_reg(struct snd_soc_codec *codec)\r
+{\r
+       int i;\r
+\r
+       rt5625_write_mask(codec, RT5625_VODSP_CTL, VODSP_NO_PD_MODE_ENA,VODSP_NO_PD_MODE_ENA);\r
+       for (i = 0; i < SET_VODSP_REG_INIT_NUM; i++) {\r
+               rt5625_read_vodsp_reg(codec, VODSP_AEC_Init_Value[i].VoiceDSPIndex);\r
+       }\r
+       return 0;\r
+}\r
+\r
+\r
+static int rt5625_dump_dsp_put(struct snd_kcontrol *kcontrol, \r
+               struct snd_ctl_elem_value *ucontrol)\r
+{\r
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);\r
+       int mode = rt5625_read(codec, VIRTUAL_REG_FOR_MISC_FUNC);\r
+\r
+       mode &= ~(0x01 << 8);\r
+       mode |= (ucontrol->value.integer.value[0] << 8);\r
+       rt5625_write(codec, VIRTUAL_REG_FOR_MISC_FUNC, mode);\r
+       rt5625_dump_dsp_reg(codec);\r
+       \r
+       return 0;\r
+}\r
+\r
+static const struct snd_kcontrol_new rt5625_snd_controls[] = {\r
+SOC_ENUM_EXT("rt5625 aec mode sel", rt5625_enum[0], rt5625_get_dsp_mode, rt5625_set_dsp_mode),\r
+SOC_ENUM("SPK Amp Type", rt5625_enum[1]),\r
+SOC_ENUM("Left SPK Source", rt5625_enum[2]),\r
+SOC_ENUM("SPK Amp Ratio", rt5625_enum[7]),\r
+SOC_ENUM("Mic1 Boost", rt5625_enum[8]),\r
+SOC_ENUM("Mic2 Boost", rt5625_enum[9]),\r
+SOC_ENUM("Dmic Boost", rt5625_enum[10]),\r
+SOC_ENUM("ADCR Func", rt5625_enum[11]),\r
+SOC_DOUBLE("RK4", RT5625_STEREO_DAC_VOL, 8, 0, 63, 1),\r
+SOC_DOUBLE("LineIn Playback Volume", RT5625_LINE_IN_VOL, 8, 0, 31, 1),\r
+SOC_SINGLE("Phone Playback Volume", RT5625_PHONEIN_VOL, 8, 31, 1),\r
+SOC_SINGLE("Mic1 Playback Volume", RT5625_MIC_VOL, 8, 31, 1),\r
+SOC_SINGLE("Mic2 Playback Volume", RT5625_MIC_VOL, 0, 31, 1),\r
+SOC_DOUBLE("PCM Capture Volume", RT5625_ADC_REC_GAIN, 8, 0, 31, 1),\r
+SOC_DOUBLE("RK3", RT5625_SPK_OUT_VOL, 8, 0, 31, 1),\r
+SOC_DOUBLE("RK2", RT5625_SPK_OUT_VOL, 15, 7, 1, 1),\r
+SOC_DOUBLE("RKA", RT5625_HP_OUT_VOL, 8, 0, 31, 1),\r
+SOC_DOUBLE("RK9", RT5625_HP_OUT_VOL, 15, 7, 1, 1),\r
+SOC_DOUBLE("RKD", RT5625_AUX_OUT_VOL, 8, 0, 31, 1),\r
+SOC_DOUBLE("RKC", RT5625_AUX_OUT_VOL, 15, 7, 1, 1),\r
+SOC_DOUBLE("ADC Record Gain", RT5625_ADC_REC_GAIN, 8, 0, 31, 0),\r
+SOC_SINGLE_EXT("VoDSP Dump", VIRTUAL_REG_FOR_MISC_FUNC, 8, 1, 0,\r
+                       snd_soc_get_volsw, rt5625_dump_dsp_put),\r
+#if (RT5625_EQ_FUNC_ENA==1)                    \r
+SOC_ENUM_EXT("EQ Mode", rt5625_enum[12], snd_soc_get_enum_double, rt5625_eq_sel_put),                          \r
+#endif\r
+};\r
+\r
+static int rt5625_add_controls(struct snd_soc_codec *codec)\r
+{\r
+       int err, i;\r
+\r
+       for (i = 0; i < ARRAY_SIZE(rt5625_snd_controls); i++){\r
+               err = snd_ctl_add(codec->card, \r
+                               snd_soc_cnew(&rt5625_snd_controls[i],\r
+                                               codec, NULL));\r
+               if (err < 0)\r
+                       return err;\r
+       }\r
+       return 0;\r
+}\r
+\r
+static void hp_depop_mode2(struct snd_soc_codec *codec)\r
+{\r
+        rt5625_write_mask(codec, RT5625_PWR_MANAG_ADD1, PWR_SOFTGEN_EN, PWR_SOFTGEN_EN);\r
+        rt5625_write_mask(codec, RT5625_PWR_MANAG_ADD3, PWR_HP_R_OUT_VOL|PWR_HP_L_OUT_VOL,\r
+                         PWR_HP_R_OUT_VOL|PWR_HP_L_OUT_VOL);\r
+        rt5625_write(codec, RT5625_MISC_CTRL,HP_DEPOP_MODE2_EN);\r
+\r
+       DBG("delay 500 msec\n");\r
+\r
+        schedule_timeout_uninterruptible(msecs_to_jiffies(500));\r
+               \r
+\r
+        rt5625_write_mask(codec, RT5625_PWR_MANAG_ADD1, PWR_HP_OUT_AMP|PWR_HP_OUT_ENH_AMP,\r
+                         PWR_HP_OUT_AMP|PWR_HP_OUT_ENH_AMP);\r
+       //rt5625_write_mask(codec, RT5625_MISC_CTRL, 0, HP_DEPOP_MODE2_EN);\r
+\r
+}\r
+\r
+//enable depop function for mute/unmute\r
+static void hp_mute_unmute_depop(struct snd_soc_codec *codec,int mute)\r
+{\r
+       if(mute)\r
+       {\r
+               rt5625_write_mask(codec, RT5625_PWR_MANAG_ADD1, PWR_SOFTGEN_EN, PWR_SOFTGEN_EN);\r
+               rt5625_write(codec, RT5625_MISC_CTRL,M_UM_DEPOP_EN|HP_R_M_UM_DEPOP_EN|HP_L_M_UM_DEPOP_EN);\r
+               //Mute headphone right/left channel\r
+               rt5625_write_mask(codec,RT5625_HP_OUT_VOL,RT_L_MUTE|RT_R_MUTE,RT_L_MUTE|RT_R_MUTE);     \r
+               mdelay(50);\r
+       }\r
+       else\r
+       {\r
+               rt5625_write_mask(codec, RT5625_PWR_MANAG_ADD1, PWR_SOFTGEN_EN, PWR_SOFTGEN_EN);\r
+               rt5625_write(codec, RT5625_MISC_CTRL, M_UM_DEPOP_EN|HP_R_M_UM_DEPOP_EN|HP_L_M_UM_DEPOP_EN);\r
+               //unMute headphone right/left channel\r
+               rt5625_write_mask(codec,RT5625_HP_OUT_VOL,0,RT_L_MUTE|RT_R_MUTE);       \r
+               mdelay(50);\r
+       }\r
+\r
+}\r
+\r
+\r
+/*\r
+ * _DAPM_ Controls\r
+ */\r
+ /*Left ADC Rec mixer*/\r
+ /*Left ADC Rec mixer*/\r
+static const struct snd_kcontrol_new rt5625_left_adc_rec_mixer_controls[] = {\r
+SOC_DAPM_SINGLE("RKK", RT5625_ADC_REC_MIXER, 14, 1, 1),\r
+SOC_DAPM_SINGLE("Mic2 Capture Switch", RT5625_ADC_REC_MIXER, 13, 1, 1),\r
+SOC_DAPM_SINGLE("LineIn Capture Switch", RT5625_ADC_REC_MIXER, 12, 1, 1),\r
+SOC_DAPM_SINGLE("RKL", RT5625_ADC_REC_MIXER, 11, 1, 1),\r
+SOC_DAPM_SINGLE("HP Mixer Capture Switch", RT5625_ADC_REC_MIXER, 10, 1, 1),\r
+SOC_DAPM_SINGLE("SPK Mixer Capture Switch", RT5625_ADC_REC_MIXER, 9, 1, 1),\r
+SOC_DAPM_SINGLE("MoNo Mixer Capture Switch", RT5625_ADC_REC_MIXER, 8, 1, 1),\r
+\r
+};\r
+\r
+/*Left ADC Rec mixer*/\r
+static const struct snd_kcontrol_new rt5625_right_adc_rec_mixer_controls[] = {\r
+SOC_DAPM_SINGLE("RKK", RT5625_ADC_REC_MIXER, 6, 1, 1),\r
+SOC_DAPM_SINGLE("Mic2 Capture Switch", RT5625_ADC_REC_MIXER, 5, 1, 1),\r
+SOC_DAPM_SINGLE("LineIn Capture Switch", RT5625_ADC_REC_MIXER, 4, 1, 1),\r
+SOC_DAPM_SINGLE("RKL", RT5625_ADC_REC_MIXER, 3, 1, 1),\r
+SOC_DAPM_SINGLE("HP Mixer Capture Switch", RT5625_ADC_REC_MIXER, 2, 1, 1),\r
+SOC_DAPM_SINGLE("SPK Mixer Capture Switch", RT5625_ADC_REC_MIXER, 1, 1, 1),\r
+SOC_DAPM_SINGLE("MoNo Mixer Capture Switch", RT5625_ADC_REC_MIXER, 0, 1, 1),\r
+};\r
+\r
+/*Left hpmixer mixer*/\r
+static const struct snd_kcontrol_new rt5625_left_hp_mixer_controls[] = {\r
+SOC_DAPM_SINGLE("ADC Playback Switch", RT5625_ADC_REC_GAIN, 15, 1, 1),\r
+SOC_DAPM_SINGLE("LineIn Playback Switch", HPL_MIXER, 0, 1, 0),\r
+SOC_DAPM_SINGLE("RKJ", HPL_MIXER, 1, 1, 0),\r
+SOC_DAPM_SINGLE("RKI", HPL_MIXER, 2, 1, 0),\r
+SOC_DAPM_SINGLE("Mic2 Playback Switch", HPL_MIXER, 3, 1, 0),\r
+SOC_DAPM_SINGLE("RKM", HPL_MIXER, 4, 1, 0),\r
+SOC_DAPM_SINGLE("RKH", RT5625_DAC_AND_MIC_CTRL, 3, 1, 1),\r
+\r
+};\r
+\r
+/*Right hpmixer mixer*/\r
+static const struct snd_kcontrol_new rt5625_right_hp_mixer_controls[] = {\r
+SOC_DAPM_SINGLE("ADC Playback Switch", RT5625_ADC_REC_GAIN, 7, 1, 1),\r
+SOC_DAPM_SINGLE("LineIn Playback Switch", HPR_MIXER, 0, 1, 0),\r
+SOC_DAPM_SINGLE("RKJ", HPR_MIXER, 1, 1, 0),\r
+SOC_DAPM_SINGLE("RKI", HPR_MIXER, 2, 1, 0),\r
+SOC_DAPM_SINGLE("Mic2 Playback Switch", HPR_MIXER, 3, 1, 0),\r
+SOC_DAPM_SINGLE("RKM", HPR_MIXER, 4, 1, 0),\r
+SOC_DAPM_SINGLE("RKH", RT5625_DAC_AND_MIC_CTRL, 2, 1, 1),\r
+\r
+};\r
+\r
+/*mono mixer*/\r
+static const struct snd_kcontrol_new rt5625_mono_mixer_controls[] = {\r
+SOC_DAPM_SINGLE("ADCL Playback Switch", RT5625_ADC_REC_GAIN, 14, 1, 1),\r
+SOC_DAPM_SINGLE("ADCR Playback Switch", RT5625_ADC_REC_GAIN, 6, 1, 1),\r
+SOC_DAPM_SINGLE("Line Mixer Playback Switch", RT5625_LINE_IN_VOL, 13, 1, 1),\r
+SOC_DAPM_SINGLE("RKI", RT5625_DAC_AND_MIC_CTRL, 13, 1, 1),\r
+SOC_DAPM_SINGLE("Mic2 Playback Switch", RT5625_DAC_AND_MIC_CTRL, 9, 1, 1),\r
+SOC_DAPM_SINGLE("RKG", RT5625_DAC_AND_MIC_CTRL, 0, 1, 1),\r
+SOC_DAPM_SINGLE("RKM", RT5625_VOICE_DAC_OUT_VOL, 13, 1, 1),\r
+};\r
+\r
+/*speaker mixer*/\r
+static const struct snd_kcontrol_new rt5625_spk_mixer_controls[] = {\r
+SOC_DAPM_SINGLE("Line Mixer Playback Switch", RT5625_LINE_IN_VOL, 14, 1, 1),   \r
+SOC_DAPM_SINGLE("RKJ", RT5625_PHONEIN_VOL, 14, 1, 1),\r
+SOC_DAPM_SINGLE("RKI", RT5625_DAC_AND_MIC_CTRL, 14, 1, 1),\r
+SOC_DAPM_SINGLE("Mic2 Playback Switch", RT5625_DAC_AND_MIC_CTRL, 10, 1, 1),\r
+SOC_DAPM_SINGLE("RKG", RT5625_DAC_AND_MIC_CTRL, 1, 1, 1),\r
+SOC_DAPM_SINGLE("RKM", RT5625_VOICE_DAC_OUT_VOL, 14, 1, 1),\r
+};\r
+\r
+static int mixer_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *k, int event)\r
+{\r
+       struct snd_soc_codec *codec = w->codec;\r
+       unsigned int l, r;\r
+\r
+       DBG("enter %s\n", __func__);\r
+\r
+       l= rt5625_read(codec, HPL_MIXER);\r
+       r = rt5625_read(codec, HPR_MIXER);\r
+       \r
+       if ((l & 0x1) || (r & 0x1))\r
+               rt5625_write_mask(codec, 0x0a, 0x0000, 0x8000);\r
+       else\r
+               rt5625_write_mask(codec, 0x0a, 0x8000, 0x8000);\r
+\r
+       if ((l & 0x2) || (r & 0x2))\r
+               rt5625_write_mask(codec, 0x08, 0x0000, 0x8000);\r
+       else\r
+               rt5625_write_mask(codec, 0x08, 0x8000, 0x8000);\r
+\r
+       if ((l & 0x4) || (r & 0x4))\r
+               rt5625_write_mask(codec, 0x10, 0x0000, 0x8000);\r
+       else\r
+               rt5625_write_mask(codec, 0x10, 0x8000, 0x8000);\r
+\r
+       if ((l & 0x8) || (r & 0x8))\r
+               rt5625_write_mask(codec, 0x10, 0x0000, 0x0800);\r
+       else\r
+               rt5625_write_mask(codec, 0x10, 0x0800, 0x0800);\r
+\r
+       if ((l & 0x10) || (r & 0x10))\r
+               rt5625_write_mask(codec, 0x18, 0x0000, 0x8000);\r
+       else\r
+               rt5625_write_mask(codec, 0x18, 0x8000, 0x8000);\r
+\r
+       return 0;\r
+}\r
+\r
+\r
+/*\r
+ *     bit[0][1] use for aec control\r
+ *     bit[2][3] for ADCR func\r
+ *     bit[4] for SPKL pga\r
+ *     bit[5] for SPKR pga\r
+ *     bit[6] for hpl pga\r
+ *     bit[7] for hpr pga\r
+ */\r
+static int spk_pga_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *k, int event)\r
+ {\r
+       struct snd_soc_codec *codec = w->codec;\r
+       int reg;\r
+       \r
+       DBG("enter %s\n", __func__);\r
+       reg = rt5625_read(codec, VIRTUAL_REG_FOR_MISC_FUNC) & (0x3 << 4);\r
+       if ((reg >> 4) != 0x3 && reg != 0)\r
+               return 0;\r
+\r
+       switch (event)\r
+       {\r
+               case SND_SOC_DAPM_POST_PMU:\r
+                       DBG("after virtual spk power up!\n");\r
+                       rt5625_write_mask(codec, 0x3e, 0x3000, 0x3000);\r
+                       rt5625_write_mask(codec, 0x02, 0x0000, 0x8080);\r
+                       rt5625_write_mask(codec, 0x3a, 0x0400, 0x0400);//power on spk amp\r
+                       break;\r
+               case SND_SOC_DAPM_POST_PMD:\r
+                       DBG("aftet virtual spk power down!\n");\r
+                       rt5625_write_mask(codec, 0x3a, 0x0000, 0x0400);//power off spk amp\r
+                       rt5625_write_mask(codec, 0x02, 0x8080, 0x8080);\r
+                       rt5625_write_mask(codec, 0x3e, 0x0000, 0x3000);                 \r
+                       break;\r
+               default:\r
+                       return 0;\r
+       }\r
+       return 0;\r
+}\r
+\r
+\r
+\r
+\r
+static int hp_pga_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *k, int event)\r
+{\r
+       struct snd_soc_codec *codec = w->codec;\r
+       int reg;\r
+\r
+       DBG("enter %s\n", __func__);\r
+\r
+       reg = rt5625_read(codec, VIRTUAL_REG_FOR_MISC_FUNC) & (0x3 << 6);\r
+       if ((reg >> 6) != 0x3 && reg != 0)\r
+               return 0;\r
+       \r
+       switch (event)\r
+       {\r
+               case SND_SOC_DAPM_POST_PMD:\r
+\r
+                       DBG("aftet virtual hp power down!\n");\r
+\r
+                       hp_mute_unmute_depop(codec,1);//mute hp\r
+                       rt5625_write_mask(codec, 0x3a, 0x0000, 0x0300);\r
+                       rt5625_write_mask(codec, 0x3e, 0x0000, 0x0c00);                 \r
+                       break;\r
+\r
+               case SND_SOC_DAPM_POST_PMU:     \r
+\r
+                       DBG("after virtual hp power up!\n");\r
+                       hp_depop_mode2(codec);\r
+                       hp_mute_unmute_depop(codec,0);//unmute hp\r
+                       break;\r
+\r
+               default:\r
+                       return 0;\r
+       }       \r
+\r
+       return 0;\r
+}\r
+\r
+\r
+\r
+static int aux_pga_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *k, int event)\r
+{\r
+       return 0;\r
+}\r
+\r
+/*SPKOUT Mux*/\r
+static const struct snd_kcontrol_new rt5625_spkout_mux_out_controls = \r
+SOC_DAPM_ENUM("Route", rt5625_enum[3]);\r
+\r
+/*HPLOUT MUX*/\r
+static const struct snd_kcontrol_new rt5625_hplout_mux_out_controls = \r
+SOC_DAPM_ENUM("Route", rt5625_enum[4]);\r
+\r
+/*HPROUT MUX*/\r
+static const struct snd_kcontrol_new rt5625_hprout_mux_out_controls = \r
+SOC_DAPM_ENUM("Route", rt5625_enum[5]);\r
+/*AUXOUT MUX*/\r
+static const struct snd_kcontrol_new rt5625_auxout_mux_out_controls = \r
+SOC_DAPM_ENUM("Route", rt5625_enum[6]);\r
+\r
+static const struct snd_soc_dapm_widget rt5625_dapm_widgets[] = {\r
+SND_SOC_DAPM_INPUT("Left LineIn"),\r
+SND_SOC_DAPM_INPUT("Right LineIn"),\r
+SND_SOC_DAPM_INPUT("Phone"),\r
+SND_SOC_DAPM_INPUT("Mic1"),\r
+SND_SOC_DAPM_INPUT("Mic2"),\r
+\r
+SND_SOC_DAPM_PGA("Mic1 Boost", RT5625_PWR_MANAG_ADD3, 1, 0, NULL, 0),\r
+SND_SOC_DAPM_PGA("Mic2 Boost", RT5625_PWR_MANAG_ADD3, 0, 0, NULL, 0),\r
+\r
+SND_SOC_DAPM_DAC("Left DAC", "Left HiFi Playback DAC", RT5625_PWR_MANAG_ADD2, 9, 0),\r
+SND_SOC_DAPM_DAC("Right DAC", "Right HiFi Playback DAC", RT5625_PWR_MANAG_ADD2, 8, 0),\r
+SND_SOC_DAPM_DAC("Voice DAC", "Voice Playback DAC", RT5625_PWR_MANAG_ADD2, 10, 0),\r
+\r
+SND_SOC_DAPM_PGA("Left LineIn PGA", RT5625_PWR_MANAG_ADD3, 7, 0, NULL, 0),\r
+SND_SOC_DAPM_PGA("Right LineIn PGA", RT5625_PWR_MANAG_ADD3, 6, 0, NULL, 0),\r
+SND_SOC_DAPM_PGA("Phone PGA", RT5625_PWR_MANAG_ADD3, 5, 0, NULL, 0),\r
+SND_SOC_DAPM_PGA("Mic1 PGA", RT5625_PWR_MANAG_ADD3, 3, 0, NULL, 0),\r
+SND_SOC_DAPM_PGA("Mic2 PGA", RT5625_PWR_MANAG_ADD3, 2, 0, NULL, 0),\r
+SND_SOC_DAPM_PGA("VoDAC PGA", RT5625_PWR_MANAG_ADD1, 7, 0, NULL, 0),\r
+SND_SOC_DAPM_MIXER("RKE", RT5625_PWR_MANAG_ADD2, 1, 0,\r
+       &rt5625_left_adc_rec_mixer_controls[0], ARRAY_SIZE(rt5625_left_adc_rec_mixer_controls)),\r
+SND_SOC_DAPM_MIXER("RKF", RT5625_PWR_MANAG_ADD2, 0, 0,\r
+       &rt5625_right_adc_rec_mixer_controls[0], ARRAY_SIZE(rt5625_right_adc_rec_mixer_controls)),\r
+SND_SOC_DAPM_MIXER_E("RK5", RT5625_PWR_MANAG_ADD2, 5, 0,\r
+       &rt5625_left_hp_mixer_controls[0], ARRAY_SIZE(rt5625_left_hp_mixer_controls),\r
+       mixer_event, SND_SOC_DAPM_POST_REG),\r
+SND_SOC_DAPM_MIXER_E("RK6", RT5625_PWR_MANAG_ADD2, 4, 0,\r
+       &rt5625_right_hp_mixer_controls[0], ARRAY_SIZE(rt5625_right_hp_mixer_controls),\r
+       mixer_event, SND_SOC_DAPM_POST_REG),\r
+SND_SOC_DAPM_MIXER("RK13", RT5625_PWR_MANAG_ADD2, 2, 0, \r
+       &rt5625_mono_mixer_controls[0], ARRAY_SIZE(rt5625_mono_mixer_controls)),\r
+SND_SOC_DAPM_MIXER("RK12", RT5625_PWR_MANAG_ADD2, 3, 0,\r
+       &rt5625_spk_mixer_controls[0], ARRAY_SIZE(rt5625_spk_mixer_controls)),  \r
+SND_SOC_DAPM_MIXER("RK11", SND_SOC_NOPM, 0, 0, NULL, 0),\r
+SND_SOC_DAPM_MIXER("DAC Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),\r
+SND_SOC_DAPM_MIXER("Line Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),\r
+\r
+SND_SOC_DAPM_MUX("RK1", SND_SOC_NOPM, 0, 0, &rt5625_spkout_mux_out_controls),\r
+SND_SOC_DAPM_MUX("RK7", SND_SOC_NOPM, 0, 0, &rt5625_hplout_mux_out_controls),\r
+SND_SOC_DAPM_MUX("RK8", SND_SOC_NOPM, 0, 0, &rt5625_hprout_mux_out_controls),\r
+SND_SOC_DAPM_MUX("RKB", SND_SOC_NOPM, 0, 0, &rt5625_auxout_mux_out_controls),\r
+\r
+SND_SOC_DAPM_PGA_E("SPKL Out PGA", VIRTUAL_REG_FOR_MISC_FUNC, 4, 0, NULL, 0,\r
+                               spk_pga_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),\r
+SND_SOC_DAPM_PGA_E("SPKR Out PGA", VIRTUAL_REG_FOR_MISC_FUNC, 5, 0, NULL, 0,\r
+                               spk_pga_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),\r
+SND_SOC_DAPM_PGA_E("HPL Out PGA",VIRTUAL_REG_FOR_MISC_FUNC, 6, 0, NULL, 0, \r
+                               hp_pga_event, SND_SOC_DAPM_POST_PMD | SND_SOC_DAPM_POST_PMU),\r
+SND_SOC_DAPM_PGA_E("HPR Out PGA",VIRTUAL_REG_FOR_MISC_FUNC, 7, 0, NULL, 0, \r
+                               hp_pga_event, SND_SOC_DAPM_POST_PMD | SND_SOC_DAPM_POST_PMU),\r
+SND_SOC_DAPM_PGA_E("AUX Out PGA",RT5625_PWR_MANAG_ADD3, 14, 0, NULL, 0, \r
+                               aux_pga_event, SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),\r
+                               \r
+SND_SOC_DAPM_ADC("Left ADC", "Left ADC HiFi Capture", RT5625_PWR_MANAG_ADD2, 7, 0),\r
+SND_SOC_DAPM_ADC("Right ADC", "Right ADC HiFi Capture", RT5625_PWR_MANAG_ADD2, 6, 0),\r
+SND_SOC_DAPM_OUTPUT("SPKL"),\r
+SND_SOC_DAPM_OUTPUT("SPKR"),\r
+SND_SOC_DAPM_OUTPUT("HPL"),\r
+SND_SOC_DAPM_OUTPUT("HPR"),\r
+SND_SOC_DAPM_OUTPUT("AUX"),\r
+SND_SOC_DAPM_MICBIAS("Mic1 Bias", RT5625_PWR_MANAG_ADD1, 3, 0),\r
+SND_SOC_DAPM_MICBIAS("Mic2 Bias", RT5625_PWR_MANAG_ADD1, 2, 0),\r
+};\r
+\r
+static const struct snd_soc_dapm_route audio_map[] = {\r
+               /*output*/\r
+               {"SPKL", NULL, "SPKL Out PGA"},\r
+               {"SPKR", NULL, "SPKR Out PGA"},\r
+               {"HPL", NULL, "HPL Out PGA"},\r
+               {"HPR", NULL, "HPR Out PGA"},\r
+               {"AUX", NULL, "AUX Out PGA"},\r
+\r
+               /*Input PGA*/\r
+               {"Left LineIn PGA", NULL, "Left LineIn"},\r
+               {"Right LineIn PGA", NULL, "Right LineIn"},\r
+               {"Phone PGA", NULL, "Phone"},\r
+               {"Mic1 Boost", NULL, "Mic1"},\r
+               {"Mic2 Boost", NULL, "Mic2"},\r
+               {"Mic1 PGA", NULL, "Mic1"},\r
+               {"Mic2 PGA", NULL, "Mic2"},\r
+               {"VoDAC PGA", NULL, "Voice DAC"},\r
+               \r
+               /*Left ADC mixer*/\r
+               {"RKE", "LineIn Capture Switch", "Left LineIn"},\r
+               {"RKE", "RKL", "Phone"},\r
+               {"RKE", "RKK", "Mic1 Boost"},\r
+               {"RKE", "Mic2 Capture Switch", "Mic2 Boost"},\r
+               {"RKE", "HP Mixer Capture Switch", "RK5"},\r
+               {"RKE", "SPK Mixer Capture Switch", "RK12"},\r
+               {"RKE", "MoNo Mixer Capture Switch", "RK13"},\r
+\r
+               /*Right ADC Mixer*/\r
+               {"RKF", "LineIn Capture Switch", "Right LineIn"},\r
+               {"RKF", "RKL", "Phone"},\r
+               {"RKF", "RKK", "Mic1 Boost"},\r
+               {"RKF", "Mic2 Capture Switch", "Mic2 Boost"},\r
+               {"RKF", "HP Mixer Capture Switch", "RK6"},\r
+               {"RKF", "SPK Mixer Capture Switch", "RK12"},\r
+               {"RKF", "MoNo Mixer Capture Switch", "RK13"},\r
+               \r
+               /*HPL mixer*/\r
+               {"RK5", "ADC Playback Switch", "RKE"},\r
+               {"RK5", "LineIn Playback Switch", "Left LineIn PGA"},\r
+               {"RK5", "RKJ", "Phone PGA"},\r
+               {"RK5", "RKI", "Mic1 PGA"},\r
+               {"RK5", "Mic2 Playback Switch", "Mic2 PGA"},\r
+               {"RK5", "RKH", "Left DAC"},\r
+               {"RK5", "RKM", "VoDAC PGA"},\r
+\r
+               /*DAC Mixer*/\r
+               {"DAC Mixer", NULL, "Left DAC"},\r
+               {"DAC Mixer", NULL, "Right DAC"},\r
+\r
+               /*line mixer*/\r
+               {"Line Mixer", NULL, "Left LineIn PGA"},\r
+               {"Line Mixer", NULL, "Right LineIn PGA"},\r
+\r
+               /*HPR mixer*/\r
+               {"RK6", "ADC Playback Switch", "RKF"},\r
+               {"RK6", "LineIn Playback Switch", "Right LineIn PGA"},\r
+               {"RK6", "RKH", "Right DAC"},\r
+               {"RK6", "RKJ", "Phone PGA"},\r
+               {"RK6", "RKI", "Mic1 PGA"},\r
+               {"RK6", "Mic2 Playback Switch", "Mic2 PGA"},\r
+               {"RK6", "RKM", "VoDAC PGA"},\r
+\r
+               /*spk mixer*/\r
+               {"RK12", "Line Mixer Playback Switch", "Line Mixer"},\r
+               {"RK12", "RKJ", "Phone PGA"},\r
+               {"RK12", "RKI", "Mic1 PGA"},\r
+               {"RK12", "Mic2 Playback Switch", "Mic2 PGA"},\r
+               {"RK12", "RKG", "DAC Mixer"},\r
+               {"RK12", "RKM", "VoDAC PGA"},\r
+\r
+               /*mono mixer*/\r
+               {"RK13", "Line Mixer Playback Switch", "Line Mixer"},\r
+               {"RK13", "ADCL Playback Switch","RKE"},\r
+               {"RK13", "ADCR Playback Switch","RKF"},\r
+               {"RK13", "RKI", "Mic1 PGA"},\r
+               {"RK13", "Mic2 Playback Switch", "Mic2 PGA"},\r
+               {"RK13", "RKG", "DAC Mixer"},\r
+               {"RK13", "RKM", "VoDAC PGA"},\r
+               \r
+               /*hp mixer*/\r
+               {"RK11", NULL, "RK5"},\r
+               {"RK11", NULL, "RK6"},\r
+\r
+               /*spkout mux*/\r
+               {"RK1", "RK11", "RK11"},\r
+               {"RK1", "RK12", "RK12"},\r
+               {"RK1", "RK13", "RK13"},\r
+               \r
+               /*hpl out mux*/\r
+               {"RK7", "RK71", "RK5"},\r
+               \r
+               /*hpr out mux*/\r
+               {"RK8", "RK81", "RK6"},\r
+\r
+               /*aux out mux*/\r
+               {"RKB", "RK11", "RK11"},\r
+               {"RKB", "RK12", "RK12"},\r
+               {"RKB", "RK13", "RK13"},\r
+\r
+               /*spkl out pga*/\r
+               {"SPKL Out PGA", NULL, "RK1"},\r
+\r
+               /*spkr out pga*/\r
+               {"SPKR Out PGA", NULL, "RK1"},\r
+               \r
+               /*hpl out pga*/\r
+               {"HPL Out PGA", NULL, "RK7"},\r
+\r
+               /*hpr out pga*/\r
+               {"HPR Out PGA", NULL, "RK8"},\r
+\r
+               /*aux out pga*/\r
+               {"AUX Out PGA", NULL, "RKB"}, \r
+               \r
+               /*left adc*/\r
+               {"Left ADC", NULL, "RKE"},\r
+               \r
+               /*right adc*/\r
+               {"Right ADC", NULL, "RKF"},\r
+               \r
+\r
+};\r
+\r
+\r
+static int rt5625_add_widgets(struct snd_soc_codec *codec)\r
+{\r
+       snd_soc_dapm_new_controls(codec, rt5625_dapm_widgets, \r
+                               ARRAY_SIZE(rt5625_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
+struct _pll_div{\r
+       u32 pll_in;\r
+       u32 pll_out;\r
+       u16 regvalue;\r
+};\r
+\r
+\r
+/**************************************************************\r
+  *    watch out!\r
+  *    our codec support you to select different source as pll input, but if you \r
+  *    use both of the I2S audio interface and pcm interface instantially. \r
+  *    The two DAI must have the same pll setting params, so you have to offer\r
+  *    the same pll input, and set our codec's sysclk the same one, we suggest \r
+  *    24576000.\r
+  **************************************************************/\r
+static const struct _pll_div codec_master_pll1_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
+       {  11289600,  24576000,  0x950F},\r
+       {  12000000,  24576000,  0x2915},\r
+       {  12288000,  24576000,  0x0600},\r
+       {  13000000,  24576000,  0x772e},\r
+       {  13100000,  24576000,  0x0d20},\r
+       {  26000000,  24576000,  0x2027},\r
+       {  26000000,  22579200,  0x392f},\r
+       {  24576000,  22579200,  0x0921},\r
+       {  24576000,  24576000,  0x02a0},\r
+};\r
+\r
+static const struct _pll_div codec_bclk_pll1_div[] = {\r
+\r
+       {   256000,   4096000,  0x3ea0},\r
+       {   352800,   5644800,  0x3ea0},\r
+       {   512000,   8192000,  0x3ea0},\r
+       {   705600,  11289600,  0x3ea0},\r
+       {  1024000,  16384000,  0x3ea0},        \r
+       {  1411200,  22579200,  0x3ea0},\r
+       {  1536000,  24576000,  0x3ea0},        \r
+       {  2048000,  16384000,  0x1ea0},        \r
+       {  2822400,  22579200,  0x1ea0},\r
+       {  3072000,  24576000,  0x1ea0},\r
+       {   705600,  11289600,  0x3ea0},\r
+       {   705600,   8467200,  0x3ab0},\r
+       {  2822400,  11289600,  0x1ee0},\r
+       {  3072000,  12288000,  0x1ee0},                        \r
+};\r
+\r
+static const struct _pll_div codec_vbclk_pll1_div[] = {\r
+\r
+       {   256000,   4096000,  0x3ea0},\r
+       {   352800,   5644800,  0x3ea0},\r
+       {   512000,   8192000,  0x3ea0},\r
+       {   705600,  11289600,  0x3ea0},\r
+       {  1024000,  16384000,  0x3ea0},        \r
+       {  1411200,  22579200,  0x3ea0},\r
+       {  1536000,  24576000,  0x3ea0},        \r
+       {  2048000,  16384000,  0x1ea0},        \r
+       {  2822400,  22579200,  0x1ea0},\r
+       {  3072000,  24576000,  0x1ea0},\r
+       {   705600,  11289600,  0x3ea0},\r
+       {   705600,   8467200,  0x3ab0},\r
+};\r
+\r
+\r
+struct _coeff_div_stereo {\r
+       unsigned int mclk;\r
+       unsigned int rate;\r
+       unsigned int reg60;\r
+       unsigned int reg62;\r
+};\r
+\r
+struct _coeff_div_voice {\r
+       unsigned int mclk;\r
+       unsigned int rate;\r
+       unsigned int reg64;\r
+};\r
+\r
+static const struct _coeff_div_stereo coeff_div_stereo[] = {\r
+\r
+       /*bclk is config to 32fs, if codec is choose to be slave mode , input bclk should be 32*fs */\r
+       {24576000,  48000,  0x3174,  0x1010},      \r
+       {12288000,  48000,  0x1174,  0x0000},\r
+       {18432000,  48000,  0x2174,  0x1111},\r
+       {36864000,  48000,  0x2274,  0x2020},\r
+       {49152000,  48000,  0xf074,  0x3030},\r
+       {24576000,  48000,  0x3172,  0x1010},\r
+       {24576000,   8000,  0xB274,  0x2424},\r
+       {24576000,  16000,  0xB174,  0x2222},\r
+       {24576000,  32000,  0xB074,  0x2121},\r
+       {22579200,  11025,  0X3374,  0x1414},\r
+       {22579200,  22050,  0X3274,  0x1212},\r
+       {22579200,  44100,  0X3174,  0x1010},\r
+       {0, 0, 0, 0},\r
+};\r
+\r
+static const struct _coeff_div_voice coeff_div_voice[] = {\r
+\r
+       /*bclk is config to 32fs, if codec is choose to be slave mode , input bclk should be 32*fs */\r
+       {24576000,  16000,  0x2622}, \r
+       {24576000,   8000,  0x2824},\r
+       {0, 0, 0},\r
+};\r
+\r
+static int get_coeff(unsigned int mclk, unsigned int rate, int mode)\r
+{\r
+       int i;\r
+\r
+       DBG("get_coeff mclk = %d, rate = %d, mode = %d\n", mclk, rate, mode);\r
+\r
+       if (!mode) {\r
+               for (i = 0; i < ARRAY_SIZE(coeff_div_stereo); i++) {\r
+                       if ((coeff_div_stereo[i].rate == rate) && (coeff_div_stereo[i].mclk == mclk))\r
+                               return i;\r
+               }\r
+       } else {\r
+               for (i = 0; i< ARRAY_SIZE(coeff_div_voice); i++) {\r
+                       if ((coeff_div_voice[i].rate == rate) && (coeff_div_voice[i].mclk == mclk))\r
+                               return i;\r
+               }\r
+       }\r
+\r
+       printk("can't find a matched mclk and rate in %s\n", \r
+              (mode ? "coeff_div_voice[]" : "coeff_div_audio[]"));\r
+\r
+       return -EINVAL;\r
+}\r
+\r
+\r
+static int rt5625_codec_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
+       DBG("enter %s pll_id = %d freq_in = %d freq_out = %d\n",\r
+              __func__, pll_id, freq_in, freq_out);\r
+\r
+       if (pll_id < RT5625_PLL1_FROM_MCLK || pll_id > RT5625_PLL1_FROM_VBCLK)\r
+               return -EINVAL;\r
+\r
+       if (!freq_in || !freq_out)\r
+               return 0;\r
+\r
+       if (RT5625_PLL1_FROM_MCLK == pll_id) {\r
+\r
+               for (i = 0; i < ARRAY_SIZE(codec_master_pll1_div); i ++)\r
+               {\r
+                       if ((freq_in == codec_master_pll1_div[i].pll_in) && (freq_out == codec_master_pll1_div[i].pll_out))\r
+                       {\r
+                               rt5625_write(codec, RT5625_GEN_CTRL_REG2, 0x0000);  /*PLL source from MCLK*/\r
+                               rt5625_write(codec, RT5625_PLL_CTRL, codec_master_pll1_div[i].regvalue);  /*set pll code*/\r
+                               rt5625_write_mask(codec, RT5625_PWR_MANAG_ADD2, 0x8000, 0x8000);  /*enable pll1 power*/\r
+                               rt5625_write_mask(codec, RT5625_GEN_CTRL_REG1, 0x8000, 0x8000);\r
+                               ret = 0;\r
+                       }\r
+               }\r
+       } else if (RT5625_PLL1_FROM_BCLK == pll_id) {\r
+\r
+               for (i = 0; i < ARRAY_SIZE(codec_bclk_pll1_div); i ++)\r
+               {\r
+                       if ((freq_in == codec_bclk_pll1_div[i].pll_in) && (freq_out == codec_bclk_pll1_div[i].pll_out))\r
+                       {\r
+                               rt5625_write(codec, RT5625_GEN_CTRL_REG2, 0x2000);  /*PLL source from BCLK*/\r
+                               rt5625_write(codec, RT5625_PLL_CTRL, codec_bclk_pll1_div[i].regvalue);  /*set pll1 code*/\r
+                               rt5625_write_mask(codec, RT5625_PWR_MANAG_ADD2, 0x8000, 0x8000);  /*enable pll1 power*/\r
+                               rt5625_write_mask(codec, RT5625_GEN_CTRL_REG1, 0x8000, 0x8000);\r
+                               ret = 0;\r
+                       }\r
+               }\r
+       } else if (RT5625_PLL1_FROM_VBCLK == pll_id) {\r
+\r
+               for (i = 0; i < ARRAY_SIZE(codec_vbclk_pll1_div); i ++)\r
+               {\r
+                       if ((freq_in == codec_vbclk_pll1_div[i].pll_in) && (freq_out == codec_vbclk_pll1_div[i].pll_out))\r
+                       {\r
+                               rt5625_write(codec, RT5625_GEN_CTRL_REG2, 0x3000);  /*PLL source from VBCLK*/\r
+                               rt5625_write(codec, RT5625_PLL_CTRL, codec_vbclk_pll1_div[i].regvalue);  /*set pll1 code*/\r
+                               rt5625_write_mask(codec, RT5625_PWR_MANAG_ADD2, 0x8000, 0x8000);  /*enable pll1 power*/\r
+                               rt5625_write_mask(codec, RT5625_GEN_CTRL_REG1, 0x8000, 0x8000);\r
+                               ret = 0;\r
+                       }\r
+               }\r
+       }\r
+       return 0;\r
+}\r
+\r
+\r
+static int rt5625_hifi_codec_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 rt5625_priv * rt5625 = codec->private_data;\r
+\r
+       DBG("sysclk freq %u for audio i2s\n", freq);\r
+       \r
+       if ((freq >= (256 * 8000)) && (freq <= (512 * 48000))) {\r
+               rt5625->stereo_sysclk = freq;\r
+               return 0;\r
+       }\r
+       \r
+       printk("unsupported sysclk freq %u for audio i2s\n", freq);\r
+              rt5625->stereo_sysclk=24576000;\r
+       \r
+       return 0;\r
+}\r
+\r
+static int rt5625_voice_codec_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 rt5625_priv * rt5625 = codec->private_data;\r
+\r
+       DBG("sysclk freq %u for voice pcm\n", freq);\r
+\r
+       if ((freq >= (256 * 8000)) && (freq <= (512 * 48000))) {\r
+               rt5625->voice_sysclk = freq;\r
+               return 0;\r
+       }                       \r
+\r
+       printk("unsupported sysclk freq %u for voice pcm\n", freq);\r
+              rt5625->voice_sysclk = 24576000;\r
+       \r
+       return 0;\r
+}\r
+\r
+\r
+static int rt5625_hifi_pcm_hw_params(struct snd_pcm_substream *substream, \r
+                       struct snd_pcm_hw_params *params,\r
+                       struct snd_soc_dai *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 rt5625_priv *rt5625 = codec->private_data;\r
+\r
+       unsigned int iface = rt5625_read(codec, RT5625_MAIN_SDP_CTRL) & 0xfff3;\r
+       int rate = params_rate(params);\r
+       int coeff = get_coeff(rt5625->stereo_sysclk, rate, 0);\r
+       \r
+       DBG("enter %s rate = %d \n", __func__, rate);\r
+\r
+       switch (params_format(params))\r
+       {\r
+               case SNDRV_PCM_FORMAT_S16_LE:\r
+                       break;\r
+               case SNDRV_PCM_FORMAT_S20_3LE:\r
+                       iface |= 0x0004;\r
+               case SNDRV_PCM_FORMAT_S24_LE:\r
+                       iface |= 0x0008;\r
+               case SNDRV_PCM_FORMAT_S8:\r
+                       iface |= 0x000c;\r
+       }\r
+\r
+       rt5625_write(codec, RT5625_MAIN_SDP_CTRL, iface);\r
+       rt5625_write_mask(codec, 0x3a, 0xc801, 0xc801);   /*power i2s and dac ref*/\r
+       if (coeff >= 0) {\r
+               rt5625_write(codec, RT5625_STEREO_DAC_CLK_CTRL1, coeff_div_stereo[coeff].reg60);\r
+               rt5625_write(codec, RT5625_STEREO_DAC_CLK_CTRL2, coeff_div_stereo[coeff].reg62);\r
+       }\r
+       \r
+       return 0;\r
+}\r
+\r
+static int rt5625_voice_pcm_hw_params(struct snd_pcm_substream *substream, \r
+                       struct snd_pcm_hw_params *params,\r
+                       struct snd_soc_dai *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 rt5625_priv *rt5625 = codec->private_data;\r
+       struct snd_soc_dapm_widget *w;\r
+       unsigned int iface = rt5625_read(codec, RT5625_EXTEND_SDP_CTRL) & 0xfff3;\r
+       int rate = params_rate(params);\r
+       int coeff = get_coeff(rt5625->voice_sysclk, rate, 1);\r
+\r
+       DBG("enter %s rate = %d \n", __func__, rate);\r
+\r
+       list_for_each_entry(w, &codec->dapm_widgets, list)\r
+       {\r
+               if (!w->sname)\r
+                       continue;\r
+               if (!strcmp(w->name, "Right ADC"))\r
+                       strcpy(w->sname, "Right ADC Voice Capture");\r
+       }\r
+       \r
+       switch (params_format(params))\r
+       {\r
+               case SNDRV_PCM_FORMAT_S16_LE:\r
+                       break;\r
+               case SNDRV_PCM_FORMAT_S20_3LE:\r
+                       iface |= 0x0004;\r
+               case SNDRV_PCM_FORMAT_S24_LE:\r
+                       iface |= 0x0008;\r
+               case SNDRV_PCM_FORMAT_S8:\r
+                       iface |= 0x000c;\r
+       }\r
+       rt5625_write_mask(codec, 0x3a, 0x0801, 0x0801);   /*power i2s and dac ref*/\r
+       rt5625_write(codec, RT5625_EXTEND_SDP_CTRL, iface);\r
+       if (coeff >= 0)\r
+               rt5625_write(codec, RT5625_VOICE_DAC_PCMCLK_CTRL1, coeff_div_voice[coeff].reg64);\r
+\r
+       return 0;\r
+}\r
+\r
+\r
+static int rt5625_hifi_codec_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)\r
+{\r
+\r
+       struct snd_soc_codec *codec = codec_dai->codec;\r
+       u16 iface = 0;\r
+\r
+       DBG("enter %s fmt = %d\n", __func__, fmt);\r
+\r
+       /*set master/slave interface*/\r
+       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK)\r
+       {\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
+       {\r
+               case SND_SOC_DAIFMT_I2S:\r
+                       iface |= 0x0000;\r
+                       break;\r
+               case SND_SOC_DAIFMT_LEFT_J:\r
+                       iface |= 0x0001;\r
+                       break;\r
+               case SND_SOC_DAIFMT_DSP_A:\r
+                       iface |= 0x0002;\r
+                       break;\r
+               case SND_SOC_DAIFMT_DSP_B:\r
+                       iface |= 0x0003;\r
+                       break;\r
+               default:\r
+                       return -EINVAL;                 \r
+       }\r
+\r
+       /*clock inversion*/\r
+       switch (fmt & SND_SOC_DAIFMT_INV_MASK)\r
+       {\r
+               case SND_SOC_DAIFMT_NB_NF:\r
+                       iface |= 0x0000;\r
+                       break;\r
+               case SND_SOC_DAIFMT_IB_NF:\r
+                       iface |= 0x0080;\r
+                       break;\r
+               default:\r
+                       return -EINVAL;\r
+       }\r
+\r
+       rt5625_write(codec, RT5625_MAIN_SDP_CTRL, iface);\r
+       return 0;\r
+}\r
+\r
+static int rt5625_voice_codec_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)\r
+{\r
+       struct snd_soc_codec *codec = codec_dai->codec;\r
+       int iface;\r
+\r
+       DBG("enter %s\n", __func__);\r
+       /*set slave/master mode*/\r
+       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK)\r
+       {\r
+               case SND_SOC_DAIFMT_CBM_CFM:\r
+                       iface = 0x0000;\r
+                       break;\r
+               case SND_SOC_DAIFMT_CBS_CFS:\r
+                       iface = 0x4000;\r
+                       break;\r
+               default:\r
+                       return -EINVAL;                 \r
+       }\r
+\r
+       switch(fmt & SND_SOC_DAIFMT_FORMAT_MASK)\r
+       {\r
+               case SND_SOC_DAIFMT_I2S:\r
+                       iface |= 0x0000;\r
+                       break;\r
+               case SND_SOC_DAIFMT_LEFT_J:\r
+                       iface |= 0x0001;\r
+                       break;\r
+               case SND_SOC_DAIFMT_DSP_A:\r
+                       iface |= 0x0002;\r
+                       break;\r
+               case SND_SOC_DAIFMT_DSP_B:\r
+                       iface |= 0x0003;\r
+                       break;\r
+               default:\r
+                       return -EINVAL;         \r
+       }\r
+\r
+       /*clock inversion*/\r
+       switch (fmt & SND_SOC_DAIFMT_INV_MASK)\r
+       {\r
+               case SND_SOC_DAIFMT_NB_NF:\r
+                       iface |= 0x0000;\r
+                       break;\r
+               case SND_SOC_DAIFMT_IB_NF:\r
+                       iface |= 0x0080;\r
+                       break;\r
+               default:\r
+                       return -EINVAL;                 \r
+       }\r
+\r
+       iface |= 0x8000;      /*enable vopcm*/\r
+       rt5625_write(codec, RT5625_EXTEND_SDP_CTRL, iface);     \r
+       return 0;\r
+}\r
+\r
+\r
+static int rt5625_hifi_codec_mute(struct snd_soc_dai *dai, int mute)\r
+{\r
+       struct snd_soc_codec *codec = dai->codec;\r
+\r
+       if (mute) \r
+               rt5625_write_mask(codec, RT5625_STEREO_DAC_VOL, 0x8080, 0x8080);\r
+       else\r
+               rt5625_write_mask(codec, RT5625_STEREO_DAC_VOL, 0x0000, 0x8080);\r
+       return 0;\r
+}\r
+\r
+static int rt5625_voice_codec_mute(struct snd_soc_dai *dai, int mute)\r
+{\r
+       struct snd_soc_codec *codec = dai->codec;\r
+\r
+       if (mute)\r
+               rt5625_write_mask(codec, RT5625_VOICE_DAC_OUT_VOL, 0x1000, 0x1000);\r
+       else \r
+               rt5625_write_mask(codec, RT5625_VOICE_DAC_OUT_VOL, 0x0000, 0x1000);\r
+       return 0;\r
+}\r
+\r
+\r
+static int rt5625_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
+               rt5625_write(codec, 0x26, 0x0000);\r
+               rt5625_write_mask(codec, 0x3c, 0x2000, 0x2000);     \r
+               rt5625_write_mask(codec, 0x3a, 0x000e, 0x000e);         \r
+               break;\r
+       case SND_SOC_BIAS_STANDBY:\r
+               break;\r
+       case SND_SOC_BIAS_OFF:\r
+               rt5625_write_mask(codec, 0x04, 0x8080, 0x8080);        /*mute hp*/\r
+               rt5625_write_mask(codec, 0x02, 0x8080, 0x8080);        /*mute spk*/\r
+               rt5625_write(codec, 0x3e, 0x0000);                                      //power off all bit\r
+               rt5625_write(codec, 0x3a, 0x0000);                                      //power off all bit\r
+               rt5625_write(codec, 0x3c, 0x0000);                                      //power off all bit\r
+               \r
+               break;\r
+       }\r
+       codec->bias_level = level;\r
+       return 0;\r
+}\r
+\r
+\r
+#define RT5625_STEREO_RATES    SNDRV_PCM_RATE_8000_48000\r
+\r
+#define RT5626_VOICE_RATES SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_8000\r
+\r
+#define RT5625_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\\r
+                       SNDRV_PCM_FMTBIT_S20_3LE |\\r
+                       SNDRV_PCM_FMTBIT_S24_LE |\\r
+                       SNDRV_PCM_FMTBIT_S8)\r
+\r
+static struct snd_soc_dai_ops rt5625_dai_ops_hifi = {\r
+\r
+       .hw_params      = rt5625_hifi_pcm_hw_params,\r
+//     .digital_mute   = rt5625_hifi_codec_mute,\r
+       .set_fmt        = rt5625_hifi_codec_set_dai_fmt,\r
+       .set_pll        = rt5625_codec_set_dai_pll,\r
+       .set_sysclk     = rt5625_hifi_codec_set_dai_sysclk,\r
+\r
+};\r
+\r
+\r
+static struct snd_soc_dai_ops rt5625_dai_ops_voice = {\r
+\r
+       .hw_params      = rt5625_voice_pcm_hw_params,\r
+//     .digital_mute   = rt5625_voice_codec_mute,\r
+       .set_fmt        = rt5625_voice_codec_set_dai_fmt,\r
+       .set_pll        = rt5625_codec_set_dai_pll,\r
+       .set_sysclk     = rt5625_voice_codec_set_dai_sysclk,\r
+\r
+};\r
+\r
+\r
+\r
+struct snd_soc_dai rt5625_dai[] = {\r
+       /*hifi codec dai*/\r
+       {\r
+               .name = "RT5625 HiFi",\r
+               .id = 1,\r
+               .playback = {\r
+                       .stream_name = "HiFi Playback",\r
+                       .channels_min = 1,\r
+                       .channels_max = 2,\r
+                       .rates = RT5625_STEREO_RATES,\r
+                       .formats = RT5625_FORMATS,\r
+               },\r
+               .capture = {\r
+                       .stream_name = "HiFi Capture",\r
+                       .channels_min = 1,\r
+                       .channels_max = 2,\r
+                       .rates = RT5625_STEREO_RATES,\r
+                       .formats = RT5625_FORMATS,\r
+               },\r
+               \r
+               .ops = &rt5625_dai_ops_hifi,\r
+       },\r
+\r
+       /*voice codec dai*/\r
+       {\r
+               .name = "RT5625 Voice",\r
+               .id = 2,\r
+               .playback = {\r
+                       .stream_name = "Voice Playback",\r
+                       .channels_min = 1,\r
+                       .channels_max = 1,\r
+                       .rates = RT5626_VOICE_RATES,\r
+                       .formats = RT5625_FORMATS,\r
+               },\r
+               .capture = {\r
+                       .stream_name = "Voice Capture",\r
+                       .channels_min = 1,\r
+                       .channels_max = 1,\r
+                       .rates = RT5626_VOICE_RATES,\r
+                       .formats = RT5625_FORMATS,\r
+               },\r
+               \r
+               .ops = &rt5625_dai_ops_voice,\r
+\r
+       },\r
+};\r
+\r
+EXPORT_SYMBOL_GPL(rt5625_dai);\r
+\r
+\r
+static void rt5625_work(struct work_struct *work)\r
+{\r
+       struct snd_soc_codec *codec =\r
+                container_of(work, struct snd_soc_codec, delayed_work.work);\r
+       rt5625_set_bias_level(codec, codec->bias_level);\r
+}\r
+\r
+\r
+#if defined(CONFIG_SND_HWDEP)\r
+\r
+#if REALTEK_HWDEP\r
+\r
+#define RT_CE_CODEC_HWDEP_NAME "rt56xx hwdep "\r
+\r
+\r
+static int rt56xx_hwdep_open(struct snd_hwdep *hw, struct file *file)\r
+{\r
+       DBG("enter %s\n", __func__);\r
+       return 0;\r
+}\r
+\r
+static int rt56xx_hwdep_release(struct snd_hwdep *hw, struct file *file)\r
+{\r
+       DBG("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
+       DBG("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
+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
+\r
+#endif\r
+\r
+static int rt5625_init(struct snd_soc_device *socdev)\r
+{\r
+\r
+       struct snd_soc_codec *codec = socdev->card->codec;\r
+       int ret = 0;\r
+\r
+       codec->name = "RT5625";\r
+       codec->owner = THIS_MODULE;\r
+       codec->read = rt5625_read;\r
+       codec->write = rt5625_write;\r
+       codec->set_bias_level = rt5625_set_bias_level;\r
+       codec->dai= rt5625_dai;\r
+       codec->num_dai = 2;\r
+       codec->reg_cache_step = 2;              \r
+       codec->reg_cache_size = ARRAY_SIZE(rt5625_reg)*2;\r
+       codec->reg_cache = kmemdup(rt5625_reg, sizeof(rt5625_reg), GFP_KERNEL);\r
+       if (codec->reg_cache == NULL)\r
+               return -ENOMEM;\r
+\r
+       rt5625_reset(codec);\r
+\r
+       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);\r
+       if (ret < 0 )\r
+       {\r
+               printk(KERN_ERR "rt5625:  failed to create pcms\n");\r
+               goto pcm_err;\r
+       }\r
+       \r
+       rt5625_write(codec, RT5625_PD_CTRL_STAT, 0);\r
+       rt5625_write(codec, RT5625_PWR_MANAG_ADD1, PWR_MAIN_BIAS);\r
+       rt5625_write(codec, RT5625_PWR_MANAG_ADD2, PWR_MIXER_VREF);\r
+       rt5625_reg_init(codec);\r
+       rt5625_set_bias_level(codec, SND_SOC_BIAS_PREPARE);\r
+       codec->bias_level = SND_SOC_BIAS_STANDBY;\r
+       schedule_delayed_work(&codec->delayed_work, msecs_to_jiffies(80));\r
+\r
+#if (RT5625_EQ_FUNC_ENA==1)    \r
+       rt5625_update_eqmode(codec,POP);\r
+#endif\r
+       \r
+       rt5625_add_controls(codec);\r
+       rt5625_add_widgets(codec);\r
+\r
+       #if defined(CONFIG_SND_HWDEP)\r
+\r
+               #if REALTEK_HWDEP\r
+\r
+                realtek_ce_init_hwdep(codec);\r
+\r
+               #endif\r
+\r
+       #endif\r
+\r
+       ret = snd_soc_init_card(socdev);\r
+\r
+       if (ret < 0)\r
+       {\r
+               printk(KERN_ERR "rt5625: failed to register card\n");\r
+               goto card_err;\r
+       }\r
+       DBG("rt5625: initial ok\n");\r
+       return 0;\r
+\r
+       card_err:\r
+               snd_soc_free_pcms(socdev);\r
+               snd_soc_dapm_free(socdev);\r
+       \r
+       pcm_err:\r
+               kfree(codec->reg_cache);\r
+               return ret;\r
+       \r
+       \r
+}\r
+\r
+\r
+static int rt5625_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id)\r
+{\r
+       struct snd_soc_device *socdev = rt5625_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 = rt5625_init(socdev);\r
+       if (ret < 0)\r
+               pr_err("failed to initialise rt5625\n");\r
+\r
+       return ret;\r
+}\r
+\r
+static int rt5625_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 rt5625_i2c_id[] = {\r
+               {"rt5625", 0},\r
+               {}\r
+};\r
+MODULE_DEVICE_TABLE(i2c, rt5625_i2c_id);\r
+static struct i2c_driver rt5625_i2c_driver = {\r
+       .driver = {\r
+               .name = "RT5625 I2C Codec",\r
+               .owner = THIS_MODULE,\r
+       },\r
+       .probe =    rt5625_i2c_probe,\r
+       .remove =   rt5625_i2c_remove,\r
+       .id_table = rt5625_i2c_id,\r
+};\r
+\r
+\r
+static int rt5625_add_i2c_device(struct platform_device *pdev,\r
+                                const struct rt5625_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
+\r
+       ret = i2c_add_driver(&rt5625_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, "rt5625", 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
+#if 0\r
+err_driver:\r
+       i2c_del_driver(&rt5625_i2c_driver);\r
+       return -ENODEV;\r
+#endif\r
+}\r
+\r
+\r
+static int rt5625_probe(struct platform_device *pdev)\r
+{\r
+       struct snd_soc_device *socdev = platform_get_drvdata(pdev);\r
+       struct rt5625_setup_data *setup;\r
+       struct snd_soc_codec *codec;\r
+       struct rt5625_priv *rt5625;\r
+       int ret;\r
+\r
+       pr_info("RT5625 Audio Codec %s", RT5625_VERSION);\r
+\r
+       if(socdev->codec_data)\r
+       {\r
+               setup = socdev->codec_data;             \r
+       }\r
+\r
+       codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);\r
+       if (codec == NULL)\r
+               return -ENOMEM;\r
+\r
+       rt5625 = kzalloc(sizeof(struct rt5625_priv), GFP_KERNEL);\r
+       if (rt5625 == NULL) {\r
+               kfree(codec);\r
+               return -ENOMEM;\r
+       }\r
+       codec->private_data = rt5625;\r
+       socdev->card->codec = codec;\r
+\r
+       mutex_init(&codec->mutex);\r
+       INIT_LIST_HEAD(&codec->dapm_widgets);\r
+       INIT_LIST_HEAD(&codec->dapm_paths);\r
+       rt5625_socdev = socdev;\r
+       INIT_DELAYED_WORK(&codec->delayed_work, rt5625_work);\r
+\r
+       ret = -ENODEV;\r
+//     if (setup->i2c_address) \r
+       {\r
+               codec->hw_write = (hw_write_t)i2c_master_send;\r
+               //codec->hw_read = (hw_read_t)i2c_master_recv;\r
+               ret = rt5625_add_i2c_device(pdev, setup);\r
+       }\r
+\r
+       if (ret != 0) {\r
+               kfree(codec->private_data);\r
+               kfree(codec);\r
+               socdev->card->codec = NULL;\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
+\r
+static int rt5625_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
+               rt5625_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
+       i2c_unregister_device(codec->control_data);\r
+       i2c_del_driver(&rt5625_i2c_driver);\r
+       kfree(codec->private_data);\r
+       kfree(codec);\r
+\r
+       return 0;\r
+}\r
+\r
+\r
+static int rt5625_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
+       rt5625_set_bias_level(codec, SND_SOC_BIAS_OFF);\r
+\r
+       return 0;\r
+}\r
+\r
+static int rt5625_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
+\r
+       \r
+//     int i;\r
+//     u8 data[3];\r
+//     u16 *cache = codec->reg_cache;\r
+\r
+#if 1\r
+       rt5625_reset(codec);\r
+       rt5625_write(codec, RT5625_PD_CTRL_STAT, 0);\r
+       rt5625_write(codec, RT5625_PWR_MANAG_ADD1, PWR_MAIN_BIAS);\r
+       rt5625_write(codec, RT5625_PWR_MANAG_ADD2, PWR_MIXER_VREF);\r
+       rt5625_reg_init(codec);\r
+#else\r
+       /* Sync reg_cache with the hardware */\r
+       for (i = 0; i < ARRAY_SIZE(rt5625_reg); i++) {\r
+               if (i == RT5625_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
+       rt5625_set_bias_level(codec, SND_SOC_BIAS_STANDBY);\r
+#endif\r
+\r
+       /* charge rt5625 caps */\r
+       if (codec->suspend_bias_level == SND_SOC_BIAS_ON) {\r
+               rt5625_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(100));\r
+       }\r
+\r
+       return 0;\r
+}\r
+\r
+\r
+struct snd_soc_codec_device soc_codec_dev_rt5625 = {\r
+       .probe =        rt5625_probe,\r
+       .remove =       rt5625_remove,\r
+       .suspend =      rt5625_suspend,\r
+       .resume =       rt5625_resume,\r
+};\r
+\r
+EXPORT_SYMBOL_GPL(soc_codec_dev_rt5625);\r
+\r
+static int __init rt5625_modinit(void)\r
+{\r
+       return snd_soc_register_dais(rt5625_dai, ARRAY_SIZE(rt5625_dai));\r
+}\r
+\r
+static void __exit rt5625_exit(void)\r
+{\r
+       snd_soc_unregister_dais(rt5625_dai, ARRAY_SIZE(rt5625_dai));\r
+}\r
+\r
+module_init(rt5625_modinit);\r
+module_exit(rt5625_exit);\r
+MODULE_LICENSE("GPL");\r
+\r