newton:cs42l52 only support 44.1k sample rate
[firefly-linux-kernel-4.4.55.git] / sound / soc / codecs / cs42l52.c
index 8a1a1b21717364c413596f6c041218ede41cb17f..d28699767b0dda945980e95c569ca205e057f68d 100755 (executable)
 #include <sound/initval.h>
 #include <sound/tlv.h>
 
-#include       <linux/types.h>
-#include       <linux/device.h>
-#include       <asm/io.h>
+#include <linux/types.h>
+#include <linux/device.h>
+
+#include <asm/io.h>
 #include "cs42l52.h"
 #include <mach/board.h>
+
 //#include "cs42L52_control.h"
+
+
+#if defined (CONFIG_SND_RK29_CODEC_SOC_MASTER) 
+       #define AUTO_DETECT_DISABLE
+#else
+       //#define AUTO_DETECT_DISABLE
+       #undef AUTO_DETECT_DISABLE
+#endif
+
 //#define DEBUG
 #ifdef DEBUG
 #define SOCDBG(fmt, arg...)    printk(KERN_ERR "%s: %s() " fmt, SOC_CS42L52_NAME, __FUNCTION__, ##arg)
 #else
-#define SOCDBG(fmt, arg...)
+#define SOCDBG(fmt, arg...)    do { } while (0)
 #endif
 #define SOCINF(fmt, args...)   printk(KERN_INFO "%s: " fmt, SOC_CS42L52_NAME,  ##args)
 #define SOCERR(fmt, args...)   printk(KERN_ERR "%s: " fmt, SOC_CS42L52_NAME,  ##args)
 
+
+
 static void soc_cs42l52_work(struct work_struct *work);
-static int soc_cs42l52_set_bias_level(struct snd_soc_codec *codec,
-                               enum snd_soc_bias_level level);
-static int soc_cs42l52_pcm_hw_params(struct snd_pcm_substream *substream,
-                        struct snd_pcm_hw_params *params, struct snd_soc_dai *dai);
-static int soc_cs42l52_set_sysclk(struct snd_soc_dai *codec_dai,
-                        int clk_id, u_int freq, int dir);
 
-static int soc_cs42l52_set_dai_clkdiv(struct snd_soc_dai *codec_dai,
-                                               int div_id, int div);
+static struct snd_soc_codec *cs42l52_codec;
 
-static int soc_cs42l52_digital_mute(struct snd_soc_dai *dai, int mute);
-static int soc_cs42l52_set_fmt(struct snd_soc_dai *codec_dai,
-                        u_int fmt);
-static unsigned int soc_cs42l52_read(struct snd_soc_codec *codec,
-                               u_int reg);
+//added for suspend
+#ifdef CONFIG_HAS_EARLYSUSPEND
+#include <linux/earlysuspend.h>
+static struct early_suspend cs42l52_early_suspend;
+#endif
 
 /**
  * snd_soc_get_volsw - single mixer get callback
@@ -105,6 +111,7 @@ int snd_soc_cs42l5x_get_volsw(struct snd_kcontrol *kcontrol,
 int snd_soc_cs42l5x_put_volsw(struct snd_kcontrol *kcontrol,
     struct snd_ctl_elem_value *ucontrol)
 {
+SOCDBG("i am here\n");
     struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
     int reg = kcontrol->private_value & 0xff;
     int shift = (kcontrol->private_value >> 8) & 0x0f;
@@ -247,7 +254,6 @@ int snd_soc_cs42l5x_put_volsw_2r(struct snd_kcontrol *kcontrol,
 /*
  * CS42L52 register default value
  */
-
 static const u8 soc_cs42l52_reg_default[] = {
        0x00, 0xE0, 0x01, 0x07, 0x05, /*4*/
        0xa0, 0x00, 0x00, 0x81, /*8*/
@@ -290,8 +296,8 @@ static int soc_cs42l52_write(struct snd_soc_codec *codec,
        int i,num, ret = 0;
        struct soc_codec_cs42l52 *info = (struct soc_codec_cs42l52*)codec->private_data;
 
-       datas[0] = reg & 0xff; /*reg addr*/
-       datas[1] = val & 0xff; /*reg val*/
+       datas[0] = reg & 0xff;
+       datas[1] = val & 0xff;
        codec->num_dai = 1;
        if(info->flags & SOC_CS42L52_ALL_IN_ONE)
        {
@@ -315,7 +321,6 @@ static int soc_cs42l52_write(struct snd_soc_codec *codec,
                        ret = -EIO;
        }
 
-       printk(KERN_INFO"soc_cs42l52_write---reg=%d--val=%d\n",reg,val);
        if(ret >= 0)
                soc_cs42l52_write_reg_cache(codec, reg, val);
 
@@ -330,53 +335,99 @@ static unsigned int soc_cs42l52_read(struct snd_soc_codec *codec,
 {
 #if 1
        u8 data;
-       u8 addr;
-        int i, ret = 0;
-
-        struct soc_codec_cs42l52 *info = (struct soc_codec_cs42l52*)codec->private_data;
-#ifndef CONFIG_CS42L52_DEBUG
-       if(reg == CODEC_CS42L52_SPK_STATUS)
-       {
-#endif
-               addr = reg & 0xff;
-               if(info->flags & SOC_CS42L52_ALL_IN_ONE)
-               {
-                       codec->num_dai = 1;
-                       for(i = 0; i < codec->num_dai; i++)
-                       {
-                               if(codec->hw_write(codec->control_data, &addr, 1) == 1)
-                               {
-//                                     if(codec->hw_read(codec->control_data, &data, 1) == 1)
-                                       {
-//                                             ret |= data << (i * 8);
-                                       }
-                               }
-                               else{
-                                       ret = -EIO;
-                                       break;
-                               }
-
-                               }       
-               }
-#ifndef CONFIG_CS42L52_DEBUG
+       if(i2c_master_reg8_recv(codec->control_data,reg,&data,1,50*1000)>0) {
+               return data;
+       }
+       else {
+               printk("cs42l52  read error\n");
+               return -1;
        }
-       else{
-
-
-               u8 *cache = codec->reg_cache;
-               u8 retval;
-               retval = reg > SOC_CS42L52_REG_NUM ? -EINVAL : cache[reg];
-/*             SOCDBG("%s (cache) 0x%x = %02x (%d)\n", reg, retval, retval); */
-               return retval;
-       }               
-#endif
-//     SOCDBG("0x%x = %02x (%d)\n", reg, ret, ret); 
-       return ret;
 #else
        return codec->read(codec, reg);
 #endif 
 }
 
+struct soc_cs42l52_clk_para {
+       u32 mclk;
+       u32 rate;
+       u8 speed;
+       u8 group;
+       u8 videoclk;
+       u8 ratio;
+       u8 mclkdiv2;
+};
+
+static const struct soc_cs42l52_clk_para clk_map_table[] = {
+       /*8k*/
+       {12288000, 8000, CLK_CTL_S_QS_MODE, CLK_CTL_32K_SR, CLK_CTL_NOT_27M, CLK_CTL_RATIO_128, 0},
+       {18432000, 8000, CLK_CTL_S_QS_MODE, CLK_CTL_32K_SR, CLK_CTL_NOT_27M, CLK_CTL_RATIO_128, 0},
+       {12000000, 8000, CLK_CTL_S_QS_MODE, CLK_CTL_32K_SR, CLK_CTL_NOT_27M, CLK_CTL_RATIO_125, 0},
+       {24000000, 8000, CLK_CTL_S_QS_MODE, CLK_CTL_32K_SR, CLK_CTL_NOT_27M, CLK_CTL_RATIO_125, 1},
+       {27000000, 8000, CLK_CTL_S_QS_MODE, CLK_CTL_32K_SR, CLK_CTL_27M_MCLK, CLK_CTL_RATIO_125, 0}, /*4*/
+
+       /*11.025k*/
+       {11289600, 11025, CLK_CTL_S_QS_MODE, CLK_CTL_NOT_32K, CLK_CTL_NOT_27M, CLK_CTL_RATIO_128, 0},
+       {16934400, 11025, CLK_CTL_S_QS_MODE, CLK_CTL_NOT_32K, CLK_CTL_NOT_27M, CLK_CTL_RATIO_128, 0},
+       
+       /*16k*/
+       {12288000, 16000, CLK_CTL_S_HS_MODE, CLK_CTL_32K_SR, CLK_CTL_NOT_27M, CLK_CTL_RATIO_128, 0},
+       {18432000, 16000, CLK_CTL_S_HS_MODE, CLK_CTL_32K_SR, CLK_CTL_NOT_27M, CLK_CTL_RATIO_128, 0},
+       {12000000, 16000, CLK_CTL_S_HS_MODE, CLK_CTL_32K_SR, CLK_CTL_NOT_27M, CLK_CTL_RATIO_125, 0},/*9*/
+       {24000000, 16000, CLK_CTL_S_HS_MODE, CLK_CTL_32K_SR, CLK_CTL_NOT_27M, CLK_CTL_RATIO_125, 1},
+       {27000000, 16000, CLK_CTL_S_HS_MODE, CLK_CTL_32K_SR, CLK_CTL_27M_MCLK, CLK_CTL_RATIO_125, 1},
+
+       /*22.05k*/
+       {11289600, 22050, CLK_CTL_S_HS_MODE, CLK_CTL_NOT_32K, CLK_CTL_NOT_27M, CLK_CTL_RATIO_128, 0},
+       {16934400, 22050, CLK_CTL_S_HS_MODE, CLK_CTL_NOT_32K, CLK_CTL_NOT_27M, CLK_CTL_RATIO_128, 0},
+       
+       /* 32k */
+       {12288000, 32000, CLK_CTL_S_SS_MODE, CLK_CTL_32K_SR, CLK_CTL_NOT_27M, CLK_CTL_RATIO_128, 0},/*14*/
+       {18432000, 32000, CLK_CTL_S_SS_MODE, CLK_CTL_32K_SR, CLK_CTL_NOT_27M, CLK_CTL_RATIO_128, 0},
+       {12000000, 32000, CLK_CTL_S_SS_MODE, CLK_CTL_32K_SR, CLK_CTL_NOT_27M, CLK_CTL_RATIO_125, 0},
+       {24000000, 32000, CLK_CTL_S_SS_MODE, CLK_CTL_32K_SR, CLK_CTL_NOT_27M, CLK_CTL_RATIO_125, 1},
+       {27000000, 32000, CLK_CTL_S_SS_MODE, CLK_CTL_32K_SR, CLK_CTL_27M_MCLK, CLK_CTL_RATIO_125, 0},
+
+       /* 44.1k */
+       {11289600, 44100, CLK_CTL_S_SS_MODE, CLK_CTL_NOT_32K, CLK_CTL_NOT_27M, CLK_CTL_RATIO_128, 0},/*19*/
+       {16934400, 44100, CLK_CTL_S_SS_MODE, CLK_CTL_NOT_32K, CLK_CTL_NOT_27M, CLK_CTL_RATIO_128, 0},
+       {12000000, 44100, CLK_CTL_S_SS_MODE, CLK_CTL_NOT_32K, CLK_CTL_NOT_27M, CLK_CTL_RATIO_136, 0},
+
+       /* 48k */
+       {12288000, 48000, CLK_CTL_S_SS_MODE, CLK_CTL_NOT_32K, CLK_CTL_NOT_27M, CLK_CTL_RATIO_128, 0},
+       {18432000, 48000, CLK_CTL_S_SS_MODE, CLK_CTL_NOT_32K, CLK_CTL_NOT_27M, CLK_CTL_RATIO_128, 0},
+       {12000000, 48000, CLK_CTL_S_SS_MODE, CLK_CTL_NOT_32K, CLK_CTL_NOT_27M, CLK_CTL_RATIO_125, 0},
+       {24000000, 48000, CLK_CTL_S_SS_MODE, CLK_CTL_NOT_32K, CLK_CTL_NOT_27M, CLK_CTL_RATIO_125, 1},/*25*/
+       {27000000, 48000, CLK_CTL_S_SS_MODE, CLK_CTL_NOT_32K, CLK_CTL_27M_MCLK, CLK_CTL_RATIO_125, 1},
+
+       /* 88.2k */
+       {11289600, 88200, CLK_CTL_S_DS_MODE, CLK_CTL_NOT_32K, CLK_CTL_NOT_27M, CLK_CTL_RATIO_128, 0},
+       {16934400, 88200, CLK_CTL_S_DS_MODE, CLK_CTL_NOT_32K, CLK_CTL_NOT_27M, CLK_CTL_RATIO_128, 0},
+
+       /* 96k */
+       {12288000, 96000, CLK_CTL_S_DS_MODE, CLK_CTL_NOT_32K, CLK_CTL_NOT_27M, CLK_CTL_RATIO_128, 0},
+       {18432000, 96000, CLK_CTL_S_DS_MODE, CLK_CTL_NOT_32K, CLK_CTL_NOT_27M, CLK_CTL_RATIO_128, 0},/*30*/
+       {12000000, 96000, CLK_CTL_S_DS_MODE, CLK_CTL_NOT_32K, CLK_CTL_NOT_27M, CLK_CTL_RATIO_125, 0},
+       {24000000, 96000, CLK_CTL_S_DS_MODE, CLK_CTL_NOT_32K, CLK_CTL_NOT_27M, CLK_CTL_RATIO_125, 1},
+};
+
+static int soc_cs42l52_get_clk(int mclk, int rate)
+{
+       int i , ret = 0;
+       u_int mclk1, mclk2 = 0;
+
+       for(i = 0; i < ARRAY_SIZE(clk_map_table); i++){
+               if(clk_map_table[i].rate == rate){
+                       mclk1 = clk_map_table[i].mclk;
+                       if(abs(mclk - mclk1) < abs(mclk - mclk2)){
+                               mclk2 = mclk1;
+                               ret = i;
+                       }
+               }
+       }
+
+       return ret < ARRAY_SIZE(clk_map_table) ? ret : -EINVAL;
+}
+
 static const char *cs42l52_mic_bias[] = {"0.5VA", "0.6VA", "0.7VA", "0.8VA", "0.83VA", "0.91VA"};
 static const char *cs42l52_hpf_freeze[] = {"Continuous DC Subtraction", "Frozen DC Subtraction"};
 static const char *cs42l52_hpf_corner_freq[] = {"Normal", "119Hz", "236Hz", "464Hz"};
@@ -473,7 +524,7 @@ SOC_SINGLE("Tone Control Playback Switch", CODEC_CS42L52_BEEP_TONE_CTL, 0, 1, 0)
 SOC_SINGLE("Treble Gain Playback Volume", CODEC_CS42L52_TONE_CTL, 4, 15, 1),
 SOC_SINGLE("Bass Gain Playback Volume", CODEC_CS42L52_TONE_CTL, 0, 15, 1),
 
-SOC_DOUBLE_R_CS42L52("Master Playback Volume", CODEC_CS42L52_MASTERA_VOL, CODEC_CS42L52_MASTERB_VOL,0xe4, 0x34), /*40*/
+SOC_DOUBLE_R_CS42L52("Master Playback Volume", CODEC_CS42L52_MASTERA_VOL, CODEC_CS42L52_MASTERB_VOL,0x18, 0x18), /* koffu 40*/
 SOC_DOUBLE_R_CS42L52("HP Digital Playback Volume", CODEC_CS42L52_HPA_VOL, CODEC_CS42L52_HPB_VOL, 0xff, 0x1),
 SOC_DOUBLE("HP Digital Playback Switch", CODEC_CS42L52_PB_CTL2, 6, 7, 1, 1),
 SOC_DOUBLE_R_CS42L52("Speaker Playback Volume", CODEC_CS42L52_SPKA_VOL, CODEC_CS42L52_SPKB_VOL, 0xff, 0x1),
@@ -514,7 +565,8 @@ static int soc_cs42l52_add_controls(struct snd_soc_codec *codec)
        for(i = 0; i < ARRAY_SIZE(soc_cs42l52_controls); i++)
        {
                ret = snd_ctl_add(codec->card,
-                       snd_soc_cnew(&soc_cs42l52_controls[i], codec, NULL));
+               snd_soc_cnew(&soc_cs42l52_controls[i], codec, NULL));
+
                if(ret < 0)
                {
                        SOCDBG("add cs42l52 controls failed\n");
@@ -558,10 +610,12 @@ static const struct snd_kcontrol_new cs42l52_hpb_mux =
 SOC_DAPM_ENUM("Route", soc_cs42l52_enum[21]);
 
 static const struct snd_soc_dapm_widget soc_cs42l52_dapm_widgets[] = {
+
        /* Input path */
        SND_SOC_DAPM_ADC("ADC Left", "Capture", CODEC_CS42L52_PWCTL1, 1, 1),
-       SND_SOC_DAPM_ADC("ADC Right", "Capture", CODEC_CS42L52_PWCTL1, 2, 1),
+       //SND_SOC_DAPM_ADC("ADC Right", "Capture", CODEC_CS42L52_PWCTL1, 2, 1),
 
+       
        SND_SOC_DAPM_MUX("MICA Mux Capture Switch", SND_SOC_NOPM, 0, 0, &cs42l52_mica_mux),
        SND_SOC_DAPM_MUX("MICB Mux Capture Switch", SND_SOC_NOPM, 0, 0, &cs42l52_micb_mux),
        SND_SOC_DAPM_MUX("MICA Stereo Mux Capture Switch", SND_SOC_NOPM, 1, 0, &cs42l52_mica_stereo_mux),
@@ -570,6 +624,7 @@ static const struct snd_soc_dapm_widget soc_cs42l52_dapm_widgets[] = {
        SND_SOC_DAPM_MUX("ADC Mux Left Capture Switch", SND_SOC_NOPM, 1, 1, &cs42l52_adca_mux),
        SND_SOC_DAPM_MUX("ADC Mux Right Capture Switch", SND_SOC_NOPM, 2, 1, &cs42l52_adcb_mux),
 
+
        /* Sum switches */
        SND_SOC_DAPM_PGA("AIN1A Switch", CODEC_CS42L52_ADC_PGA_A, 0, 0, NULL, 0),
        SND_SOC_DAPM_PGA("AIN2A Switch", CODEC_CS42L52_ADC_PGA_A, 1, 0, NULL, 0),
@@ -602,11 +657,11 @@ static const struct snd_soc_dapm_widget soc_cs42l52_dapm_widgets[] = {
        SND_SOC_DAPM_DAC("DAC Left", "Playback", SND_SOC_NOPM, 0, 0),
        SND_SOC_DAPM_DAC("DAC Right", "Playback", SND_SOC_NOPM, 0, 0),
 
-       // SND_SOC_DAPM_PGA("HP Amp Left", CODEC_CS42L52_PWCTL3, 4, 1, NULL, 0),
-       // SND_SOC_DAPM_PGA("HP Amp Right", CODEC_CS42L52_PWCTL3, 6, 1, NULL, 0),
+       SND_SOC_DAPM_PGA("HP Amp Left", CODEC_CS42L52_PWCTL3, 4, 1, NULL, 0),
+       SND_SOC_DAPM_PGA("HP Amp Right", CODEC_CS42L52_PWCTL3, 6, 1, NULL, 0),
 
-       // SND_SOC_DAPM_PGA("SPK Pwr Left", CODEC_CS42L52_PWCTL3, 0, 1, NULL, 0),
-       // SND_SOC_DAPM_PGA("SPK Pwr Right", CODEC_CS42L52_PWCTL3, 2, 1, NULL, 0),
+       SND_SOC_DAPM_PGA("SPK Pwr Left", CODEC_CS42L52_PWCTL3, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA("SPK Pwr Right", CODEC_CS42L52_PWCTL3, 2, 0, NULL, 0),
 
        SND_SOC_DAPM_OUTPUT("HPA"),
        SND_SOC_DAPM_OUTPUT("HPB"),
@@ -632,54 +687,54 @@ static const struct snd_soc_dapm_route soc_cs42l52_audio_map[] = {
        {"ADC Mux Left Capture Switch", "AIN1", "INPUT1A"},
        {"ADC Mux Right Capture Switch", "AIN1", "INPUT1B"},
        {"ADC Mux Left Capture Switch", "AIN2", "INPUT2A"},
-        {"ADC Mux Right Capture Switch", "AIN2", "INPUT2B"},
+       {"ADC Mux Right Capture Switch", "AIN2", "INPUT2B"},
        {"ADC Mux Left Capture Switch", "AIN3", "INPUT3A"},
-        {"ADC Mux Right Capture Switch", "AIN3", "INPUT3B"},
+       {"ADC Mux Right Capture Switch", "AIN3", "INPUT3B"},
        {"ADC Mux Left Capture Switch", "AIN4", "INPUT4A"},
-        {"ADC Mux Right Capture Switch", "AIN4", "INPUT4B"},
+       {"ADC Mux Right Capture Switch", "AIN4", "INPUT4B"},
 
        /* left capture part */
-        {"AIN1A Switch", NULL, "INPUT1A"},
-        {"AIN2A Switch", NULL, "INPUT2A"},
-        {"AIN3A Switch", NULL, "INPUT3A"},
-        {"AIN4A Switch", NULL, "INPUT4A"},
-        {"MICA Switch",  NULL, "MICA"},
-        {"PGA MICA", NULL, "MICA Switch"},
-
-        {"PGA Left", NULL, "AIN1A Switch"},
-        {"PGA Left", NULL, "AIN2A Switch"},
-        {"PGA Left", NULL, "AIN3A Switch"},
-        {"PGA Left", NULL, "AIN4A Switch"},
-        {"PGA Left", NULL, "PGA MICA"},
+       {"AIN1A Switch", NULL, "INPUT1A"},
+       {"AIN2A Switch", NULL, "INPUT2A"},
+       {"AIN3A Switch", NULL, "INPUT3A"},
+       {"AIN4A Switch", NULL, "INPUT4A"},
+       {"MICA Switch",  NULL, "MICA"},
+       {"PGA MICA", NULL, "MICA Switch"},
+
+       {"PGA Left", NULL, "AIN1A Switch"},
+       {"PGA Left", NULL, "AIN2A Switch"},
+       {"PGA Left", NULL, "AIN3A Switch"},
+       {"PGA Left", NULL, "AIN4A Switch"},
+       {"PGA Left", NULL, "PGA MICA"},
 
        /* right capture part */
-        {"AIN1B Switch", NULL, "INPUT1B"},
-        {"AIN2B Switch", NULL, "INPUT2B"},
-        {"AIN3B Switch", NULL, "INPUT3B"},
-        {"AIN4B Switch", NULL, "INPUT4B"},
-        {"MICB Switch",  NULL, "MICB"},
-        {"PGA MICB", NULL, "MICB Switch"},
-
-        {"PGA Right", NULL, "AIN1B Switch"},
-        {"PGA Right", NULL, "AIN2B Switch"},
-        {"PGA Right", NULL, "AIN3B Switch"},
-        {"PGA Right", NULL, "AIN4B Switch"},
-        {"PGA Right", NULL, "PGA MICB"},
+       {"AIN1B Switch", NULL, "INPUT1B"},
+       {"AIN2B Switch", NULL, "INPUT2B"},
+       {"AIN3B Switch", NULL, "INPUT3B"},
+       {"AIN4B Switch", NULL, "INPUT4B"},
+       {"MICB Switch",  NULL, "MICB"},
+       {"PGA MICB", NULL, "MICB Switch"},
+
+       {"PGA Right", NULL, "AIN1B Switch"},
+       {"PGA Right", NULL, "AIN2B Switch"},
+       {"PGA Right", NULL, "AIN3B Switch"},
+       {"PGA Right", NULL, "AIN4B Switch"},
+       {"PGA Right", NULL, "PGA MICB"},
 
        {"ADC Mux Left Capture Switch", "PGA", "PGA Left"},
-        {"ADC Mux Right Capture Switch", "PGA", "PGA Right"},
+       {"ADC Mux Right Capture Switch", "PGA", "PGA Right"},
        {"ADC Left", NULL, "ADC Mux Left Capture Switch"},
        {"ADC Right", NULL, "ADC Mux Right Capture Switch"},
 
        /* Mic Bias */
-        {"Mic Bias Capture Switch", "On", "PGA MICA"},
-        {"Mic Bias Capture Switch", "On", "PGA MICB"},
+       {"Mic Bias Capture Switch", "On", "PGA MICA"},
+       {"Mic Bias Capture Switch", "On", "PGA MICB"},
        {"Mic-Bias", NULL, "Mic Bias Capture Switch"},
        {"Mic-Bias", NULL, "Mic Bias Capture Switch"},
-        {"ADC Mux Left Capture Switch",  "PGA", "Mic-Bias"},
-        {"ADC Mux Right Capture Switch", "PGA", "Mic-Bias"},
-        {"Passthrough Left Playback Switch",  "On", "Mic-Bias"},
-        {"Passthrough Right Playback Switch", "On", "Mic-Bias"},
+       {"ADC Mux Left Capture Switch",  "PGA", "Mic-Bias"},
+       {"ADC Mux Right Capture Switch", "PGA", "Mic-Bias"},
+       {"Passthrough Left Playback Switch",  "On", "Mic-Bias"},
+       {"Passthrough Right Playback Switch", "On", "Mic-Bias"},
 
        /* loopback path */
        {"Passthrough Left Playback Switch",  "On",  "PGA Left"},
@@ -687,7 +742,7 @@ static const struct snd_soc_dapm_route soc_cs42l52_audio_map[] = {
        {"Passthrough Left Playback Switch",  "Off", "DAC Left"},
        {"Passthrough Right Playback Switch", "Off", "DAC Right"},
 
-/* Output map */
+       /* Output map */
        /* Headphone */
        {"HP Amp Left",  NULL, "Passthrough Left Playback Switch"},
        {"HP Amp Right", NULL, "Passthrough Right Playback Switch"},
@@ -695,14 +750,13 @@ static const struct snd_soc_dapm_route soc_cs42l52_audio_map[] = {
        {"HPB", NULL, "HP Amp Right"},
 
        /* Speakers */
-       
        {"SPK Pwr Left",  NULL, "DAC Left"},
        {"SPK Pwr Right", NULL, "DAC Right"},
        {"SPKA", NULL, "SPK Pwr Left"},
        {"SPKB", NULL, "SPK Pwr Right"},
 
        /* terminator */
-     //   {NULL, NULL, NULL},
+       //{NULL, NULL, NULL},
 };
 
 static int soc_cs42l52_add_widgets(struct snd_soc_codec *soc_codec)
@@ -716,153 +770,86 @@ static int soc_cs42l52_add_widgets(struct snd_soc_codec *soc_codec)
        snd_soc_dapm_new_widgets(soc_codec);
         return 0;
 }
-
+#if 0
 #define SOC_CS42L52_RATES ( SNDRV_PCM_RATE_8000  | SNDRV_PCM_RATE_11025 | \
                             SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | \
                             SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \
                             SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | \
-                            SNDRV_PCM_RATE_96000 ) /*refer to cs42l52 datasheet page35*/
-
+                            SNDRV_PCM_RATE_96000 )
+#else
+#define SOC_CS42L52_RATES  SNDRV_PCM_RATE_44100
+#endif
 #define SOC_CS42L52_FORMATS ( SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_U16_LE | \
                               SNDRV_PCM_FMTBIT_S18_3LE | SNDRV_PCM_FMTBIT_U18_3LE | \
                               SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_U20_3LE | \
                               SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_U24_LE )
 
-static struct snd_soc_dai_ops cs42l52_ops = {
-                       .hw_params = soc_cs42l52_pcm_hw_params,
-                       .set_sysclk = soc_cs42l52_set_sysclk,
-                       .set_fmt = soc_cs42l52_set_fmt,
-                       .digital_mute = soc_cs42l52_digital_mute,
-                       .set_clkdiv = soc_cs42l52_set_dai_clkdiv,
-};
-
-
-struct  snd_soc_dai soc_cs42l52_dai = {
-                .name = SOC_CS42L52_NAME,
-                .playback = {
-                        .stream_name = "Playback",
-                        .channels_min = 1,
-                        .channels_max = SOC_CS42L52_DEFAULT_MAX_CHANS,
-                        .rates = SOC_CS42L52_RATES,
-                        .formats = SOC_CS42L52_FORMATS,
-                },
-                .capture = {
-                        .stream_name = "Capture",
-                        .channels_min = 1,
-                        .channels_max = SOC_CS42L52_DEFAULT_MAX_CHANS,
-                        .rates = SOC_CS42L52_RATES,
-                        .formats = SOC_CS42L52_FORMATS,
-                },
-                               .ops = &cs42l52_ops,    
-#if 0
-                .ops = {
-                        .hw_params = soc_cs42l52_pcm_hw_params,
-                        .set_sysclk = soc_cs42l52_set_sysclk,
-                        .set_fmt = soc_cs42l52_set_fmt,
-                        .digital_mute = soc_cs42l52_digital_mute,
-                },
-#endif
-};
-
-EXPORT_SYMBOL_GPL(soc_cs42l52_dai);
-
-/* #define CONFIG_MANUAL_CLK */
 
-/* page 37 from cs42l52 datasheet */
-static void soc_cs42l52_required_setup(struct snd_soc_codec *codec)
+/*
+ *----------------------------------------------------------------------------
+ * Function : soc_cs42l52_set_bias_level
+ * Purpose  : This function is to get triggered when dapm events occurs.
+ *            
+ *----------------------------------------------------------------------------
+ */
+int soc_cs42l52_set_bias_level(struct snd_soc_codec *codec, enum snd_soc_bias_level level)
 {
-       u8 data;
-       soc_cs42l52_write(codec, 0x00, 0x99);
-       soc_cs42l52_write(codec, 0x3e, 0xba);
-       soc_cs42l52_write(codec, 0x47, 0x80);
-       data = soc_cs42l52_read(codec, 0x32);
-       soc_cs42l52_write(codec, 0x32, data | 0x80);
-       soc_cs42l52_write(codec, 0x32, data & 0x7f);
-       soc_cs42l52_write(codec, 0x00, 0x00);
-}
-
-
-static struct snd_soc_codec *cs42l52_codec;
-
-#if defined (CONFIG_I2C) || defined (CONFIG_I2C_MODULE)
-
-static int cs42l52_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
-{      
-   struct snd_soc_codec *soc_codec;
-       struct soc_codec_cs42l52 * info;
-       struct cs42l52_platform_data *pdata = i2c->dev.platform_data;
-       unsigned int reg;
-       int i, ret = 0;
-       printk(KERN_INFO"cs42l52_i2c_probe\n");
-       
-       soc_codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
-       if (soc_codec == NULL)
-               return -ENOMEM;
-
-       soc_codec->name = SOC_CS42L52_NAME;
-       soc_codec->owner = THIS_MODULE;
-       soc_codec->write = soc_cs42l52_write;
-       soc_codec->read = soc_cs42l52_read;
-       soc_codec->hw_write = (hw_write_t)i2c_master_send;
-       mutex_init(&soc_codec->mutex);
-       INIT_LIST_HEAD(&soc_codec->dapm_widgets);
-       INIT_LIST_HEAD(&soc_codec->dapm_paths);
-       
-       soc_codec->set_bias_level = soc_cs42l52_set_bias_level;
-       soc_codec->dai = &soc_cs42l52_dai;
-       soc_codec->dai->playback.channels_max = 2;
-       soc_codec->dai->capture.channels_max = 2;
-       soc_codec->num_dai = 1;
-       soc_codec->control_data = i2c;
-       soc_codec->dev = &i2c->dev;     
-       soc_codec->pcm_devs = 0;  /*pcm device num index*/
-       soc_codec->pop_time = 2;
-       soc_codec->dai[0].codec = soc_codec;
-
-       soc_codec->reg_cache_size = sizeof(soc_cs42l52_reg_default);
-
-       soc_codec->reg_cache = kmemdup(soc_cs42l52_reg_default, sizeof(soc_cs42l52_reg_default), GFP_KERNEL);
-
-       info = (struct soc_codec_cs42l52 *)kmalloc(sizeof(struct soc_codec_cs42l52),GFP_KERNEL);
+       u8 pwctl1 = soc_cs42l52_read(codec, CODEC_CS42L52_PWCTL1) & 0x9f;
+       u8 pwctl2 = soc_cs42l52_read(codec, CODEC_CS42L52_PWCTL2) & 0x07;
 
-       if (info == NULL) {
-               kfree(soc_codec);
-               return -ENOMEM;
-       }
+       switch (level) {
+        case SND_SOC_BIAS_ON: /* full On */
+               SOCDBG("full on\n");
+               break;
+        case SND_SOC_BIAS_PREPARE: /* partial On */
+               SOCDBG("partial on\n");
+               pwctl1 &= ~(PWCTL1_PDN_CHRG | PWCTL1_PDN_CODEC);
+                soc_cs42l52_write(codec, CODEC_CS42L52_PWCTL1, pwctl1);
+                break;
+        case SND_SOC_BIAS_STANDBY: /* Off, with power */
+               SOCDBG("off with power\n");
+               pwctl1 &= ~(PWCTL1_PDN_CHRG | PWCTL1_PDN_CODEC);
+                soc_cs42l52_write(codec, CODEC_CS42L52_PWCTL1, pwctl1);
+                break;
+        case SND_SOC_BIAS_OFF: /* Off, without power */
+               SOCDBG("off without power\n");
+              soc_cs42l52_write(codec, CODEC_CS42L52_PWCTL1, pwctl1 | 0x9f);
+               soc_cs42l52_write(codec, CODEC_CS42L52_PWCTL2, pwctl2 | 0x07);
+                break;
+        }
+        codec->bias_level = level;
 
-       info->sysclk = SOC_CS42L52_DEFAULT_CLK;
-       info->format = SOC_CS42L52_DEFAULT_FORMAT;
+        return 0;
+}
 
-       soc_codec->private_data =(void*)info;   
-       
-       printk(KERN_INFO"soc_cs42l52_setup1\n");
-       if(!soc_codec->reg_cache)
-       {
-               SOCERR("%s: err out of memory\n", __FUNCTION__);
-               ret = -ENOMEM;
-               goto err;
-       }
-       if (pdata->init_platform_hw)                              
-               pdata->init_platform_hw();
+/*
+ *----------------------------------------------------------------------------
+ * Function : cs42l52_power_init
+ * Purpose  : This function is toinit codec to a normal status
+ *   
+ *----------------------------------------------------------------------------
+ */
+static void cs42l52_power_init (struct snd_soc_codec *soc_codec)
+{
+       int i,ret;
 
-       /*initialize codec*/
-       for(i = 0; i < soc_codec->num_dai; i++) //while(1) //
+       SOCDBG("\n");
+       for(i = 0; i < soc_codec->num_dai; i++)
        {
-       
                SOCINF("Cirrus CS42L52 codec , revision %d\n", ret & CHIP_REV_MASK);
+
                /*set hp default volume*/
                soc_cs42l52_write(soc_codec, CODEC_CS42L52_HPA_VOL, DEFAULT_HP_VOL);
                soc_cs42l52_write(soc_codec, CODEC_CS42L52_HPB_VOL, DEFAULT_HP_VOL);
 
-       
                /*set spk default volume*/
                soc_cs42l52_write(soc_codec, CODEC_CS42L52_SPKA_VOL, DEFAULT_SPK_VOL);
                soc_cs42l52_write(soc_codec, CODEC_CS42L52_SPKB_VOL, DEFAULT_SPK_VOL);
 
-               
                /*set output default powerstate*/
                soc_cs42l52_write(soc_codec, CODEC_CS42L52_PWCTL3, 5);
-#ifdef CONFIG_MANUAL_CLK
+
+#ifdef AUTO_DETECT_DISABLE
                soc_cs42l52_write(soc_codec, CODEC_CS42L52_CLK_CTL, 
                                (soc_cs42l52_read(soc_codec, CODEC_CS42L52_CLK_CTL) 
                                 & ~CLK_CTL_AUTODECT_ENABLE));
@@ -871,133 +858,155 @@ static int cs42l52_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id
                                (soc_cs42l52_read(soc_codec, CODEC_CS42L52_CLK_CTL)
                                 |CLK_CTL_AUTODECT_ENABLE));
 #endif
-       
+
                /*default output stream configure*/
                soc_cs42l52_write(soc_codec, CODEC_CS42L52_PB_CTL1,
                                (soc_cs42l52_read(soc_codec, CODEC_CS42L52_PB_CTL1)
-                               | (PB_CTL1_HP_GAIN_07099 << PB_CTL1_HP_GAIN_SHIFT)));
+                               | (PB_CTL1_HP_GAIN_06047 << PB_CTL1_HP_GAIN_SHIFT)));
 
                soc_cs42l52_write(soc_codec, CODEC_CS42L52_MISC_CTL,
                                (soc_cs42l52_read(soc_codec, CODEC_CS42L52_MISC_CTL))
                                | (MISC_CTL_DEEMPH | MISC_CTL_DIGZC | MISC_CTL_DIGSFT));
-       
-               /*default input stream configure*/
-               //soc_cs42l52_write(soc_codec, CODEC_CS42L52_ADC_PGA_A, info->adc_sel1); 
-               soc_cs42l52_write(soc_codec, CODEC_CS42L52_ADC_PGA_A, 0<<6); 
-
-                               //soc_cs42l52_write(soc_codec, CODEC_CS42L52_ADC_PGA_B, info->adc_sel2);
-               soc_cs42l52_write(soc_codec, CODEC_CS42L52_ADC_PGA_B, 1<<7);
 
                soc_cs42l52_write(soc_codec, CODEC_CS42L52_MICA_CTL,
                                (soc_cs42l52_read(soc_codec, CODEC_CS42L52_MICA_CTL)
                                | 0<<6));/*pre-amplifer 16db*/
                 soc_cs42l52_write(soc_codec, CODEC_CS42L52_MICB_CTL,
-                                (soc_cs42l52_read(soc_codec, CODEC_CS42L52_MICB_CTL)
-                               | 0<<6));
-                /*default input stream path configure*/
-                soc_cs42l52_write(soc_codec, CODEC_CS42L52_ANALOG_HPF_CTL, 
-                                (soc_cs42l52_read(soc_codec, CODEC_CS42L52_ANALOG_HPF_CTL)
-                                | HPF_CTL_ANLGSFTB | HPF_CTL_ANLGSFTA));
-                soc_cs42l52_write(soc_codec, CODEC_CS42L52_PGAA_CTL, PGAX_CTL_VOL_6DB);
-                soc_cs42l52_write(soc_codec, CODEC_CS42L52_PGAB_CTL, PGAX_CTL_VOL_6DB); /*PGA volume*/
-
-                soc_cs42l52_write(soc_codec, CODEC_CS42L52_ADCA_VOL, ADCX_VOL_12DB);
-                soc_cs42l52_write(soc_codec, CODEC_CS42L52_ADCB_VOL, ADCX_VOL_12DB); /*ADC volume*/
+                               (soc_cs42l52_read(soc_codec, CODEC_CS42L52_MICB_CTL)
+                               | 0<<6));/*pre-amplifer 16db*/
 
-                soc_cs42l52_write(soc_codec, CODEC_CS42L52_ALC_CTL,
-                                (ALC_CTL_ALCB_ENABLE | ALC_CTL_ALCA_ENABLE)); /*enable ALC*/
+                soc_cs42l52_write(soc_codec, CODEC_CS42L52_PWCTL2, 0x00);
+                soc_cs42l52_write(soc_codec, CODEC_CS42L52_ADC_PGA_A, 0x90); 
+                soc_cs42l52_write(soc_codec, CODEC_CS42L52_ADC_PGA_B, 0x90); 
 
-                soc_cs42l52_write(soc_codec, CODEC_CS42L52_ALC_THRESHOLD,
-                                ((ALC_RATE_0DB << ALC_MAX_RATE_SHIFT)
-                                 | (ALC_RATE_3DB << ALC_MIN_RATE_SHIFT)));/*ALC max and min threshold*/
+                soc_cs42l52_write(soc_codec, CODEC_CS42L52_MICA_CTL, 0x2c);
+                soc_cs42l52_write(soc_codec, CODEC_CS42L52_MICB_CTL, 0x2c);
 
+                soc_cs42l52_write(soc_codec, CODEC_CS42L52_PGAA_CTL, 0x00);  //0dB PGA
+                soc_cs42l52_write(soc_codec, CODEC_CS42L52_PGAB_CTL, 0x00);  //0dB PGA
 
-                soc_cs42l52_write(soc_codec, CODEC_CS42L52_NOISE_GATE_CTL,
-                                (NG_ENABLE | (NG_MIN_70DB << NG_THRESHOLD_SHIFT)
-                                 | (NG_DELAY_100MS << NG_DELAY_SHIFT))); /*Noise Gate enable*/
+                soc_cs42l52_write(soc_codec, CODEC_CS42L52_ADC_HPF_FREQ, 0x0F);  //enable 464Hz HPF
+                        
+               //soc_cs42l52_write(soc_codec, CODEC_CS42L52_MASTERA_VOL, 0x12);
+               //soc_cs42l52_write(soc_codec, CODEC_CS42L52_MASTERB_VOL, 0x12);
 
-                soc_cs42l52_write(soc_codec, CODEC_CS42L52_BEEP_VOL, BEEP_VOL_12DB);
+               //soc_cs42l52_write(soc_codec, CODEC_CS42L52_HPA_VOL, 0xc0);
+               //soc_cs42l52_write(soc_codec, CODEC_CS42L52_HPB_VOL, 0xc0);
 
-                soc_cs42l52_write(soc_codec, CODEC_CS42L52_ADCA_MIXER_VOL, 0x80 | ADC_MIXER_VOL_12DB);
-                soc_cs42l52_write(soc_codec, CODEC_CS42L52_ADCB_MIXER_VOL, 0x80 | ADC_MIXER_VOL_12DB);
-       }
-       soc_cs42l52_dai.dev = &i2c->dev;
+               soc_cs42l52_write(soc_codec, CODEC_CS42L52_BEEP_TONE_CTL, 0X07);
+               soc_cs42l52_write(soc_codec, CODEC_CS42L52_TONE_CTL, 0X8f);
 
-       cs42l52_codec = soc_codec;
+               /*      
+               soc_cs42l52_write(soc_codec, CODEC_CS42L52_MASTERA_VOL, 0x00);
+               soc_cs42l52_write(soc_codec, CODEC_CS42L52_MASTERB_VOL, 0x00);
 
-       ret = snd_soc_register_codec(soc_codec);
-       if (ret != 0) {
-               dev_err(&i2c->dev, "Failed to register codec: %d\n", ret);
-               goto err;
+               soc_cs42l52_write(soc_codec, CODEC_CS42L52_BEEP_TONE_CTL, 0X00);
+               soc_cs42l52_write(soc_codec, CODEC_CS42L52_TONE_CTL, 0X00);
+               */
        }
 
-    INIT_DELAYED_WORK(&soc_codec->delayed_work, soc_cs42l52_work);
+       return;
+}
 
-       ret = snd_soc_register_dai(&soc_cs42l52_dai);
-       if (ret != 0) {
-               dev_err(&i2c->dev, "Failed to register DAI: %d\n", ret);
-               goto err_codec;
-       }
+/*
+ *----------------------------------------------------------------------------
+ * Function : soc_cs42l52_work
+ * Purpose  : This function is to power on bias.
+ *            
+ *----------------------------------------------------------------------------
+ */
+static void soc_cs42l52_work(struct work_struct *work)
+{
+       struct snd_soc_codec *codec =
+                container_of(work, struct snd_soc_codec, delayed_work.work);
 
-       return ret;
+       soc_cs42l52_set_bias_level(codec, codec->bias_level);
 
-err_codec:
-       snd_soc_unregister_codec(soc_codec);
-err:
-       kfree(cs42l52_codec);
-       cs42l52_codec = NULL;
-       return ret;
+       return;
 }
 
-static int cs42l52_i2c_remove(struct i2c_client *client)
-{
-        
-       snd_soc_unregister_dai(&soc_cs42l52_dai);
-       snd_soc_unregister_codec(cs42l52_codec);
+/*
+ *----------------------------------------------------------------------------
+ * Function : soc_cs42l52_trigger
+ * Purpose  : This function is to respond to trigger.
+ *            
+ *----------------------------------------------------------------------------
+ */
+static int soc_cs42l52_trigger(struct snd_pcm_substream *substream,
+                         int status,
+                         struct snd_soc_dai *dai)
+{      
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_dai_link *machine = rtd->dai;
+       struct snd_soc_dai *codec_dai = machine->codec_dai;
 
-       soc_cs42l52_set_bias_level(cs42l52_codec, SND_SOC_BIAS_OFF);
+       SOCDBG ("substream->stream:%s status:%d\n",
+                  substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? "PLAYBACK":"CAPTURE", status);
 
-       soc_cs42l52_dai.dev = NULL;
-       if(cs42l52_codec->reg_cache)            
-               kfree(cs42l52_codec->reg_cache);
-       if(cs42l52_codec->private_data)         
-               kfree(cs42l52_codec->private_data);
-       kfree(cs42l52_codec);
-       cs42l52_codec = NULL;
+       if(status == 1 || status == 0){
+               if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK){
+                       codec_dai->playback.active = status;
+               }else{
+                       codec_dai->capture.active = status;
+               }
+       }
 
        return 0;
 }
 
-static const struct i2c_device_id cs42l52_i2c_id[] = {
-       { "cs42l52", 0 },
-       { }
-};
-MODULE_DEVICE_TABLE(i2c, cs42l52_i2c_id);
+/*
+ *----------------------------------------------------------------------------
+ * Function : soc_cs42l52_hw_params
+ * Purpose  : This function is to set the hardware parameters for CS42L52.
+ *            The functions set the sample rate and audio serial data word 
+ *            length.
+ *            
+ *----------------------------------------------------------------------------
+ */
+static int soc_cs42l52_hw_params(struct snd_pcm_substream *substream,
+                        struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_device *soc_dev = rtd->socdev;
+       struct snd_soc_codec *soc_codec = soc_dev->card->codec;
+       struct soc_codec_cs42l52 *info = (struct soc_codec_cs42l52*)soc_codec->private_data;
 
-static struct i2c_driver cs42l52_i2c_drv = {
-       .driver = {
-               .name = "CS42L52",
-               .owner = THIS_MODULE,
-       },
-       .probe =    cs42l52_i2c_probe,
-       .remove =   cs42l52_i2c_remove,
-       .id_table = cs42l52_i2c_id,
+       u32 clk = 0;
+       int ret = 0;
+       int index = soc_cs42l52_get_clk(info->sysclk, params_rate(params));
 
-};
+       SOCDBG("----------sysclk=%d,rate=%d\n",info->sysclk, params_rate(params));
 
+       if(index >= 0)
+       {
+               info->sysclk = clk_map_table[index].mclk;
+               clk |= (clk_map_table[index].speed << CLK_CTL_SPEED_SHIFT) | 
+                     (clk_map_table[index].group << CLK_CTL_32K_SR_SHIFT) | 
+                     (clk_map_table[index].videoclk << CLK_CTL_27M_MCLK_SHIFT) | 
+                     (clk_map_table[index].ratio << CLK_CTL_RATIO_SHIFT) | 
+                     clk_map_table[index].mclkdiv2;
+
+#ifdef AUTO_DETECT_DISABLE
+               soc_cs42l52_write(soc_codec, CODEC_CS42L52_CLK_CTL, clk);
+#else
+               soc_cs42l52_write(soc_codec, CODEC_CS42L52_CLK_CTL, 0xa0);
 #endif
-#if 1 
-static int soc_cs42l52_set_dai_clkdiv(struct snd_soc_dai *codec_dai,
-               int div_id, int div)
-{
-       struct snd_soc_codec *codec = codec_dai->codec;
-       u16 reg;
-       
-       printk("soc_cs42l52_set_dai_clkdiv\n");
-       return 0;
+       }
+       else{
+               SOCDBG("can't find out right mclk\n");
+               ret = -EINVAL;
+       }
+
+       return ret;
 }
 
-#endif
+/*
+ *----------------------------------------------------------------------------
+ * Function : soc_cs42l52_set_sysclk
+ * Purpose  : This function is to set the DAI system clock
+ *            
+ *----------------------------------------------------------------------------
+ */
 static int soc_cs42l52_set_sysclk(struct snd_soc_dai *codec_dai,
                        int clk_id, u_int freq, int dir)
 {
@@ -1005,18 +1014,26 @@ static int soc_cs42l52_set_sysclk(struct snd_soc_dai *codec_dai,
        struct snd_soc_codec *soc_codec = codec_dai->codec;
        struct soc_codec_cs42l52 *info = (struct soc_codec_cs42l52*)soc_codec->private_data;
 
-       if((freq >= SOC_CS42L52_MIN_CLK) && (freq <= SOC_CS42L52_MAX_CLK))
-       {
+       SOCDBG("sysclk=%dHz,freq=%d\n", info->sysclk,freq);
+
+       if((freq >= SOC_CS42L52_MIN_CLK) && (freq <= SOC_CS42L52_MAX_CLK)){
                info->sysclk = freq;
-               SOCDBG("sysclk %d\n", info->sysclk);
+               SOCDBG("info->sysclk set to %d Hz\n", info->sysclk);
        }
        else{
-               SOCDBG("invalid paramter\n");
+               printk("invalid paramter\n");
                ret = -EINVAL;
        }
        return ret;
 }
 
+/*
+ *----------------------------------------------------------------------------
+ * Function : soc_cs42l52_set_fmt
+ * Purpose  : This function is to set the DAI format
+ *            
+ *----------------------------------------------------------------------------
+ */
 static int soc_cs42l52_set_fmt(struct snd_soc_dai *codec_dai,
                        u_int fmt)
 {
@@ -1026,8 +1043,7 @@ static int soc_cs42l52_set_fmt(struct snd_soc_dai *codec_dai,
        u8 iface = 0;
 
        /* set master/slave audio interface */
-        switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
-
+       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
        case SND_SOC_DAIFMT_CBM_CFM:
                SOCDBG("codec dai fmt master\n");
                iface = IFACE_CTL1_MASTER;
@@ -1042,8 +1058,7 @@ static int soc_cs42l52_set_fmt(struct snd_soc_dai *codec_dai,
        }
 
         /* interface format */
-        switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
-
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
        case SND_SOC_DAIFMT_I2S:
                SOCDBG("codec dai fmt i2s\n");
                iface |= (IFACE_CTL1_ADC_FMT_I2S | IFACE_CTL1_DAC_FMT_I2S);
@@ -1071,8 +1086,7 @@ static int soc_cs42l52_set_fmt(struct snd_soc_dai *codec_dai,
        }
 
        /* clock inversion */
-        switch (fmt & SND_SOC_DAIFMT_INV_MASK) { /*tonyliu*/
-
+       switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
        case SND_SOC_DAIFMT_NB_NF:
                SOCDBG("codec dai fmt normal sclk\n");
                break;
@@ -1092,189 +1106,257 @@ static int soc_cs42l52_set_fmt(struct snd_soc_dai *codec_dai,
 
        info->format = iface;
 done:
-       return ret;
+       soc_cs42l52_write(soc_codec, CODEC_CS42L52_IFACE_CTL1, info->format);
 
+       return ret;
 }
 
+/*
+ *----------------------------------------------------------------------------
+ * Function : soc_cs42l52_digital_mute
+ * Purpose  : This function is to mute DAC or not
+ *            
+ *----------------------------------------------------------------------------
+ */
 static int soc_cs42l52_digital_mute(struct snd_soc_dai *dai, int mute)
 {
        struct snd_soc_codec *soc_codec = dai->codec;
        u8 mute_val = soc_cs42l52_read(soc_codec, CODEC_CS42L52_PB_CTL1) & PB_CTL1_MUTE_MASK;
 
-       if(mute)
-       {
-               printk(KERN_INFO"soc_cs42l52_digital_mute=1 %d\n",mute_val);
+       SOCDBG("%d\n",mute);
 
-               soc_cs42l52_write(soc_codec, CODEC_CS42L52_PB_CTL1, mute_val | PB_CTL1_MSTB_MUTE | PB_CTL1_MSTA_MUTE);
+       if(mute) {
+               soc_cs42l52_write(soc_codec, CODEC_CS42L52_PB_CTL1, mute_val \
+                       | PB_CTL1_MSTB_MUTE | PB_CTL1_MSTA_MUTE);
        }
-       else{
-               printk(KERN_INFO"soc_cs42l52_digital_mute=0 %d\n",mute_val);
+       else {
                soc_cs42l52_write(soc_codec, CODEC_CS42L52_PB_CTL1, mute_val );
        }
 
        return 0;
 }
 
-struct soc_cs42l52_clk_para {
-       u32 mclk;
-       u32 rate;
-       u8 speed;
-       u8 group;
-       u8 videoclk;
-       u8 ratio;
-       u8 mclkdiv2;
+static struct snd_soc_dai_ops cs42l52_ops = {
+                       .hw_params              = soc_cs42l52_hw_params,
+                       .set_sysclk             = soc_cs42l52_set_sysclk,
+                       .set_fmt                = soc_cs42l52_set_fmt,
+                       .trigger                = soc_cs42l52_trigger,
+                       .digital_mute   = soc_cs42l52_digital_mute,
+};
+/*
+ *----------------------------------------------------------------------------
+ * @struct  soc_cs42l52_dai |
+ *          It is SoC Codec DAI structure which has DAI capabilities viz., 
+ *          playback and capture, DAI runtime information viz. state of DAI 
+ *                     and pop wait state, and DAI private data. 
+ *          The AIC3111 rates ranges from 8k to 192k
+ *          The PCM bit format supported are 16, 20, 24 and 32 bits
+ *----------------------------------------------------------------------------
+ */
+struct  snd_soc_dai soc_cs42l52_dai = {
+            .name = SOC_CS42L52_NAME,
+            .playback = {
+                    .stream_name = "Playback",
+                    .channels_min = 1,
+                    .channels_max = SOC_CS42L52_DEFAULT_MAX_CHANS,
+                    .rates = SOC_CS42L52_RATES,
+                    .formats = SOC_CS42L52_FORMATS,
+            },
+            .capture = {
+                    .stream_name = "Capture",
+                    .channels_min = 1,
+                    .channels_max = SOC_CS42L52_DEFAULT_MAX_CHANS,
+                    .rates = SOC_CS42L52_RATES,
+                    .formats = SOC_CS42L52_FORMATS,
+            },
+                       .ops = &cs42l52_ops,
 };
+EXPORT_SYMBOL_GPL(soc_cs42l52_dai);
 
-static const struct soc_cs42l52_clk_para clk_map_table[] = {
-       /*8k*/
-       {12288000, 8000, CLK_CTL_S_QS_MODE, CLK_CTL_32K_SR, CLK_CTL_NOT_27M, CLK_CTL_RATIO_128, 0},
-       {18432000, 8000, CLK_CTL_S_QS_MODE, CLK_CTL_32K_SR, CLK_CTL_NOT_27M, CLK_CTL_RATIO_128, 0},
-       {12000000, 8000, CLK_CTL_S_QS_MODE, CLK_CTL_32K_SR, CLK_CTL_NOT_27M, CLK_CTL_RATIO_125, 0},
-       {24000000, 8000, CLK_CTL_S_QS_MODE, CLK_CTL_32K_SR, CLK_CTL_NOT_27M, CLK_CTL_RATIO_125, 1},
-       {27000000, 8000, CLK_CTL_S_QS_MODE, CLK_CTL_32K_SR, CLK_CTL_27M_MCLK, CLK_CTL_RATIO_125, 0}, /*4*/
 
-       /*11.025k*/
-       {11289600, 11025, CLK_CTL_S_QS_MODE, CLK_CTL_NOT_32K, CLK_CTL_NOT_27M, CLK_CTL_RATIO_128, 0},
-       {16934400, 11025, CLK_CTL_S_QS_MODE, CLK_CTL_NOT_32K, CLK_CTL_NOT_27M, CLK_CTL_RATIO_128, 0},
-       
-       /*16k*/
-       {12288000, 16000, CLK_CTL_S_HS_MODE, CLK_CTL_32K_SR, CLK_CTL_NOT_27M, CLK_CTL_RATIO_128, 0},
-       {18432000, 16000, CLK_CTL_S_HS_MODE, CLK_CTL_32K_SR, CLK_CTL_NOT_27M, CLK_CTL_RATIO_128, 0},
-       {12000000, 16000, CLK_CTL_S_HS_MODE, CLK_CTL_32K_SR, CLK_CTL_NOT_27M, CLK_CTL_RATIO_125, 0},/*9*/
-       {24000000, 16000, CLK_CTL_S_HS_MODE, CLK_CTL_32K_SR, CLK_CTL_NOT_27M, CLK_CTL_RATIO_125, 1},
-       {27000000, 16000, CLK_CTL_S_HS_MODE, CLK_CTL_32K_SR, CLK_CTL_27M_MCLK, CLK_CTL_RATIO_125, 1},
-
-       /*22.05k*/
-       {11289600, 22050, CLK_CTL_S_HS_MODE, CLK_CTL_NOT_32K, CLK_CTL_NOT_27M, CLK_CTL_RATIO_128, 0},
-       {16934400, 22050, CLK_CTL_S_HS_MODE, CLK_CTL_NOT_32K, CLK_CTL_NOT_27M, CLK_CTL_RATIO_128, 0},
-       
-       /* 32k */
-       {12288000, 32000, CLK_CTL_S_SS_MODE, CLK_CTL_32K_SR, CLK_CTL_NOT_27M, CLK_CTL_RATIO_128, 0},/*14*/
-       {18432000, 32000, CLK_CTL_S_SS_MODE, CLK_CTL_32K_SR, CLK_CTL_NOT_27M, CLK_CTL_RATIO_128, 0},
-       {12000000, 32000, CLK_CTL_S_SS_MODE, CLK_CTL_32K_SR, CLK_CTL_NOT_27M, CLK_CTL_RATIO_125, 0},
-       {24000000, 32000, CLK_CTL_S_SS_MODE, CLK_CTL_32K_SR, CLK_CTL_NOT_27M, CLK_CTL_RATIO_125, 1},
-       {27000000, 32000, CLK_CTL_S_SS_MODE, CLK_CTL_32K_SR, CLK_CTL_27M_MCLK, CLK_CTL_RATIO_125, 0},
+#if defined (CONFIG_I2C) || defined (CONFIG_I2C_MODULE)
+static int cs42l52_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
+{      
+       struct snd_soc_codec *soc_codec;
+       struct soc_codec_cs42l52 * info;
+       struct cs42l52_platform_data *pdata = i2c->dev.platform_data;
+       int ret = 0;
 
-       /* 44.1k */
-       {11289600, 44100, CLK_CTL_S_SS_MODE, CLK_CTL_NOT_32K, CLK_CTL_NOT_27M, CLK_CTL_RATIO_128, 0},/*19*/
-       {16934400, 44100, CLK_CTL_S_SS_MODE, CLK_CTL_NOT_32K, CLK_CTL_NOT_27M, CLK_CTL_RATIO_128, 0},
+       soc_codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
+       if (soc_codec == NULL)
+               return -ENOMEM;
 
-       /* 48k */
-       {12288000, 48000, CLK_CTL_S_SS_MODE, CLK_CTL_NOT_32K, CLK_CTL_NOT_27M, CLK_CTL_RATIO_128, 0},
-       {18432000, 48000, CLK_CTL_S_SS_MODE, CLK_CTL_NOT_32K, CLK_CTL_NOT_27M, CLK_CTL_RATIO_128, 0},
-       {12000000, 48000, CLK_CTL_S_SS_MODE, CLK_CTL_NOT_32K, CLK_CTL_NOT_27M, CLK_CTL_RATIO_125, 0},
-       {24000000, 48000, CLK_CTL_S_SS_MODE, CLK_CTL_NOT_32K, CLK_CTL_NOT_27M, CLK_CTL_RATIO_125, 1},/*24*/
-       {27000000, 48000, CLK_CTL_S_SS_MODE, CLK_CTL_NOT_32K, CLK_CTL_27M_MCLK, CLK_CTL_RATIO_125, 1},
+       soc_codec->name = SOC_CS42L52_NAME;
+       soc_codec->owner = THIS_MODULE;
+       soc_codec->write = soc_cs42l52_write;
+       soc_codec->read = soc_cs42l52_read;
+       soc_codec->hw_write = (hw_write_t)i2c_master_send;
+       mutex_init(&soc_codec->mutex);
+       INIT_LIST_HEAD(&soc_codec->dapm_widgets);
+       INIT_LIST_HEAD(&soc_codec->dapm_paths);
+       
+       soc_codec->set_bias_level = soc_cs42l52_set_bias_level;
+       soc_codec->dai = &soc_cs42l52_dai;
+       soc_codec->dai->playback.channels_max = 2;
+       soc_codec->dai->capture.channels_max = 2;
+       soc_codec->num_dai = 1;
+       soc_codec->control_data = i2c;
+       soc_codec->dev = &i2c->dev;     
+       soc_codec->pcm_devs = 0;
+       soc_codec->pop_time = 2;
+       soc_codec->dai[0].codec = soc_codec;
 
-       /* 88.2k */
-       {11289600, 88200, CLK_CTL_S_DS_MODE, CLK_CTL_NOT_32K, CLK_CTL_NOT_27M, CLK_CTL_RATIO_128, 0},
-       {16934400, 88200, CLK_CTL_S_DS_MODE, CLK_CTL_NOT_32K, CLK_CTL_NOT_27M, CLK_CTL_RATIO_128, 0},
+       soc_codec->reg_cache_size = sizeof(soc_cs42l52_reg_default);
 
-       /* 96k */
-       {12288000, 96000, CLK_CTL_S_DS_MODE, CLK_CTL_NOT_32K, CLK_CTL_NOT_27M, CLK_CTL_RATIO_128, 0},
-       {18432000, 96000, CLK_CTL_S_DS_MODE, CLK_CTL_NOT_32K, CLK_CTL_NOT_27M, CLK_CTL_RATIO_128, 0},/*29*/
-       {12000000, 96000, CLK_CTL_S_DS_MODE, CLK_CTL_NOT_32K, CLK_CTL_NOT_27M, CLK_CTL_RATIO_125, 0},
-       {24000000, 96000, CLK_CTL_S_DS_MODE, CLK_CTL_NOT_32K, CLK_CTL_NOT_27M, CLK_CTL_RATIO_125, 1},
-};
+       soc_codec->reg_cache = kmemdup(soc_cs42l52_reg_default, sizeof(soc_cs42l52_reg_default), GFP_KERNEL);
 
-static int soc_cs42l52_get_clk(int mclk, int rate)
-{
+       info = (struct soc_codec_cs42l52 *)kmalloc(sizeof(struct soc_codec_cs42l52),GFP_KERNEL);
+       if (info == NULL) {
+               kfree(soc_codec);
+               return -ENOMEM;
+       }
 
-       int i , ret = 0;
-       u_int mclk1, mclk2 = 0;
+       info->sysclk = SOC_CS42L52_DEFAULT_CLK;
+       info->format = SOC_CS42L52_DEFAULT_FORMAT;
 
-       for(i = 0; i < ARRAY_SIZE(clk_map_table); i++)
-       {
-               if(clk_map_table[i].rate == rate)
-               {
-                       mclk1 = clk_map_table[i].mclk;
-                       {
-                               if(abs(mclk - mclk1) < abs(mclk - mclk2))
-                               {
-                                       mclk2 = mclk1;
-                                       ret = i;
-                               }
-                       }
-               }
+       soc_codec->private_data =(void*)info;   
+       if(!soc_codec->reg_cache) {
+               SOCERR("%s: err out of memory\n", __FUNCTION__);
+               ret = -ENOMEM;
+               goto err;
        }
 
-       return ret < ARRAY_SIZE(clk_map_table) ? ret : -EINVAL;
-}
+       if (pdata->init_platform_hw)                              
+               pdata->init_platform_hw();
 
-static int soc_cs42l52_pcm_hw_params(struct snd_pcm_substream *substream,
-                        struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
-{
-       int ret = 0;
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_device *soc_dev = rtd->socdev;
-       struct snd_soc_codec *soc_codec = soc_dev->card->codec;
-       struct soc_codec_cs42l52 *info = (struct soc_codec_cs42l52*)soc_codec->private_data;
+       /*initialize codec*/
+       cs42l52_power_init(soc_codec);
 
-       info->format = SOC_CS42L52_DEFAULT_FORMAT;
-       u32 clk = 0;
-       int index = soc_cs42l52_get_clk(info->sysclk, params_rate(params));
+    INIT_DELAYED_WORK(&soc_codec->delayed_work, soc_cs42l52_work);
 
-       if(index >= 0)
-       {
-               info->sysclk = clk_map_table[index].mclk;
-               clk |= (clk_map_table[index].speed << CLK_CTL_SPEED_SHIFT) | 
-                     (clk_map_table[index].group << CLK_CTL_32K_SR_SHIFT) | 
-                     (clk_map_table[index].videoclk << CLK_CTL_27M_MCLK_SHIFT) | 
-                     (clk_map_table[index].ratio << CLK_CTL_RATIO_SHIFT) | 
-                     clk_map_table[index].mclkdiv2;
-#ifdef CONFIG_MANUAL_CLK
-               soc_cs42l52_write(soc_codec, CODEC_CS42L52_CLK_CTL, clk);
-#else
-               soc_cs42l52_write(soc_codec, CODEC_CS42L52_CLK_CTL, 0xa0);
-#endif
-               soc_cs42l52_write(soc_codec, CODEC_CS42L52_IFACE_CTL1, info->format);
+       soc_cs42l52_dai.dev = &i2c->dev;
+       cs42l52_codec = soc_codec;
 
+       ret = snd_soc_register_codec(soc_codec);
+       if (ret != 0) {
+               dev_err(&i2c->dev, "Failed to register codec: %d\n", ret);
+               goto err;
        }
-       else{
-               SOCDBG("can't find out right mclk\n");
-               ret = -EINVAL;
+
+       ret = snd_soc_register_dai(&soc_cs42l52_dai);
+       if (ret != 0) {
+               dev_err(&i2c->dev, "Failed to register DAI: %d\n", ret);
+               goto err_codec;
        }
 
        return ret;
+
+err_codec:
+       snd_soc_unregister_codec(soc_codec);
+err:
+       kfree(cs42l52_codec);
+       cs42l52_codec = NULL;
+       return ret;
 }
 
-int soc_cs42l52_set_bias_level(struct snd_soc_codec *codec, enum snd_soc_bias_level level)
+static int cs42l52_i2c_remove(struct i2c_client *client)
 {
-       u8 pwctl1 = soc_cs42l52_read(codec, CODEC_CS42L52_PWCTL1) & 0x9f;
-       u8 pwctl2 = soc_cs42l52_read(codec, CODEC_CS42L52_PWCTL2) & 0x07;
+       snd_soc_unregister_dai(&soc_cs42l52_dai);
+       snd_soc_unregister_codec(cs42l52_codec);
 
-       switch (level) {
-        case SND_SOC_BIAS_ON: /* full On */
-               SOCDBG("full on\n");
-               break;
-        case SND_SOC_BIAS_PREPARE: /* partial On */
-               SOCDBG("partial on\n");
-               pwctl1 &= ~(PWCTL1_PDN_CHRG | PWCTL1_PDN_CODEC);
-                soc_cs42l52_write(codec, CODEC_CS42L52_PWCTL1, pwctl1);
-                break;
-        case SND_SOC_BIAS_STANDBY: /* Off, with power */
-               SOCDBG("off with power\n");
-               pwctl1 &= ~(PWCTL1_PDN_CHRG | PWCTL1_PDN_CODEC);
-                soc_cs42l52_write(codec, CODEC_CS42L52_PWCTL1, pwctl1);
-                break;
-        case SND_SOC_BIAS_OFF: /* Off, without power */
-               SOCDBG("off without power\n");
-                soc_cs42l52_write(codec, CODEC_CS42L52_PWCTL1, pwctl1 | 0x9f);
-               soc_cs42l52_write(codec, CODEC_CS42L52_PWCTL2, pwctl2 | 0x07);
-                break;
-        }
-        codec->bias_level = level;
-        return 0;
+       soc_cs42l52_set_bias_level(cs42l52_codec, SND_SOC_BIAS_OFF);
+
+       soc_cs42l52_dai.dev = NULL;
+       if(cs42l52_codec->reg_cache)            
+               kfree(cs42l52_codec->reg_cache);
+       if(cs42l52_codec->private_data)         
+               kfree(cs42l52_codec->private_data);
+       kfree(cs42l52_codec);
+       cs42l52_codec = NULL;
+
+       return 0;
 }
 
-static void soc_cs42l52_work(struct work_struct *work)
+
+static int cs42l52_i2c_shutdown(struct i2c_client *client)
 {
-       struct snd_soc_codec *codec =
-                container_of(work, struct snd_soc_codec, delayed_work.work);
+       SOCDBG("i am here\n");        
+       snd_soc_unregister_dai(&soc_cs42l52_dai);
+       snd_soc_unregister_codec(cs42l52_codec);
 
-       soc_cs42l52_set_bias_level(codec, codec->bias_level);
+       soc_cs42l52_set_bias_level(cs42l52_codec, SND_SOC_BIAS_OFF);
+
+       soc_cs42l52_dai.dev = NULL;
+       if(cs42l52_codec->reg_cache)            
+               kfree(cs42l52_codec->reg_cache);
+       if(cs42l52_codec->private_data)         
+               kfree(cs42l52_codec->private_data);
+       kfree(cs42l52_codec);
+       cs42l52_codec = NULL;
+
+       return 0;
+}
+
+static const struct i2c_device_id cs42l52_i2c_id[] = {
+       { "cs42l52", 0 },
+};
+MODULE_DEVICE_TABLE(i2c, cs42l52_i2c_id);
+
+static struct i2c_driver cs42l52_i2c_drv = {
+       .driver = {
+               .name = "CS42L52",
+               .owner = THIS_MODULE,
+       },
+       .probe =    cs42l52_i2c_probe,
+       .remove =   cs42l52_i2c_remove,
+       .shutdown =  cs42l52_i2c_shutdown,
+       .id_table = cs42l52_i2c_id,
+};
+
+#endif
+
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+static int soc_cs42l52_suspend(struct early_suspend *h)
+{
+       
+       soc_cs42l52_write(cs42l52_codec, CODEC_CS42L52_PWCTL1, PWCTL1_PDN_CODEC);
+       soc_cs42l52_set_bias_level(cs42l52_codec, SND_SOC_BIAS_OFF);
+       return 0;
 }
 
+static int soc_cs42l52_resume(struct early_suspend *h)
+{
+       struct snd_soc_codec *soc_codec = cs42l52_codec;
+       struct soc_codec_cs42l52 *info = (struct soc_codec_cs42l52*) soc_codec->private_data;
+       int i, reg;
+       u8 data[2];
+       u8 *reg_cache = (u8*) soc_codec->reg_cache;
+       soc_codec->num_dai = 1;
+       /* Sync reg_cache with the hardware */
+       for(i = 0; i < soc_codec->num_dai; i++) {
+
+           for(reg = 0; reg < ARRAY_SIZE(soc_cs42l52_reg_default); reg++) {
+               data[0] = reg;
+               data[1] = reg_cache[reg];
+               if(soc_codec->hw_write(soc_codec->control_data, data, 2) != 2)
+                   break;
+           }
+       }
+
+       soc_cs42l52_set_bias_level(soc_codec, SND_SOC_BIAS_STANDBY);
+
+       /*charge cs42l52 codec*/
+       if(soc_codec->suspend_bias_level == SND_SOC_BIAS_ON)
+       {
+               soc_cs42l52_set_bias_level(soc_codec, SND_SOC_BIAS_PREPARE);
+               soc_codec->bias_level = SND_SOC_BIAS_ON;
+               schedule_delayed_work(&soc_codec->delayed_work, msecs_to_jiffies(1000));
+       }
+       return 0;
+
+}
+#else
 static int soc_cs42l52_suspend(struct platform_device *pdev, pm_message_t state)
 {
        struct snd_soc_device *soc_dev = (struct snd_soc_device*)platform_get_drvdata(pdev);
@@ -1282,7 +1364,6 @@ static int soc_cs42l52_suspend(struct platform_device *pdev, pm_message_t state)
        
        soc_cs42l52_write(soc_codec, CODEC_CS42L52_PWCTL1, PWCTL1_PDN_CODEC);
        soc_cs42l52_set_bias_level(soc_codec, SND_SOC_BIAS_OFF);
-
        return 0;
 }
 
@@ -1315,11 +1396,10 @@ static int soc_cs42l52_resume(struct platform_device *pdev)
                soc_codec->bias_level = SND_SOC_BIAS_ON;
                schedule_delayed_work(&soc_codec->delayed_work, msecs_to_jiffies(1000));
        }
-
        return 0;
 
 }
-
+#endif
 static int soc_cs42l52_probe(struct platform_device *pdev)
 {
        struct snd_soc_device *soc_dev = platform_get_drvdata(pdev);
@@ -1333,17 +1413,15 @@ static int soc_cs42l52_probe(struct platform_device *pdev)
 
        soc_dev->card->codec = cs42l52_codec;
        soc_codec = cs42l52_codec;
-                
-               ret = snd_soc_new_pcms(soc_dev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
+
+       ret = snd_soc_new_pcms(soc_dev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
        if(ret)
        {
                SOCERR("%s: add new pcms failed\n",__FUNCTION__);
                goto pcm_err;
        }
-       /*init done*/
 
        soc_cs42l52_add_controls(soc_codec);
-
        soc_cs42l52_add_widgets(soc_codec);
 
        ret = snd_soc_init_card(soc_dev);
@@ -1356,6 +1434,11 @@ static int soc_cs42l52_probe(struct platform_device *pdev)
                goto card_err;
        }
 
+#ifdef CONFIG_HAS_EARLYSUSPEND   
+       cs42l52_early_suspend.suspend =soc_cs42l52_suspend;  
+       cs42l52_early_suspend.resume =soc_cs42l52_resume;//   cs42l52_early_suspend.level = 0x2;    
+       register_early_suspend(&cs42l52_early_suspend);
+#endif
        return ret;
 
 card_err:
@@ -1372,33 +1455,90 @@ static int soc_cs42l52_remove(struct platform_device *pdev)
 
        snd_soc_free_pcms(socdev);
        snd_soc_dapm_free(socdev);
-
+#ifdef CONFIG_HAS_EARLYSUSPEND         
+       unregister_early_suspend(&cs42l52_early_suspend);
+#endif 
        return 0;
 }
 
 struct snd_soc_codec_device soc_codec_dev_cs42l52 = {
        .probe = soc_cs42l52_probe,
        .remove = soc_cs42l52_remove,
+#ifndef        CONFIG_HAS_EARLYSUSPEND
        .suspend = soc_cs42l52_suspend,
        .resume = soc_cs42l52_resume,
+#endif 
 };
 
 EXPORT_SYMBOL_GPL(soc_codec_dev_cs42l52);
 
 static int __init cs42l52_modinit(void)
 {
-       printk(KERN_INFO"cs42l52_i2c_probe\n");
        return i2c_add_driver(&cs42l52_i2c_drv);
 }
 module_init(cs42l52_modinit);
 
 static void __exit cs42l52_exit(void)
 {
-       printk(KERN_INFO"cs42l52_i2c_probe\n");
        i2c_del_driver(&cs42l52_i2c_drv);
 }
 module_exit(cs42l52_exit);
 
+
+
 MODULE_DESCRIPTION("ALSA SoC CS42L52 Codec");
 MODULE_AUTHOR("Bo Liu, Bo.Liu@cirrus.com, www.cirrus.com");
 MODULE_LICENSE("GPL");
+
+
+
+
+#ifdef CONFIG_PROC_FS
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+static int proc_cs42l52_show (struct seq_file *s, void *v)
+{
+       struct snd_soc_codec *codec = cs42l52_codec;
+       int reg;
+
+       seq_printf (s, "    cs42l52 registers:\n");
+       for (reg = 0; reg < 53; reg++) {
+               if (reg%10 == 0) 
+                       seq_printf (s, "\n            ");
+               seq_printf (s, "0x%02x ", soc_cs42l52_read(codec, reg));
+       }
+       seq_printf (s, "\n\n");
+
+#if 0//for check cache
+       u8 *cache = codec->reg_cache;
+       seq_printf (s, "            cache:\n");
+       for (reg = 0; reg < 53; reg++) {
+               if (reg%10 == 0) 
+                       seq_printf (s, "\n            ");
+               seq_printf (s, "0x%02x ", cache[reg]);
+       }
+       seq_printf (s, "\n\n");
+#endif
+
+       return 0;
+}
+
+static int proc_cs42l52_open (struct inode *inode, struct file *file)
+{
+       return single_open (file, proc_cs42l52_show, NULL);
+}
+
+static const struct file_operations proc_cs42l52_fops = {
+       .open           = proc_cs42l52_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
+static int __init codec_proc_init (void)
+{
+       proc_create ("cs42l52", 0, NULL, &proc_cs42l52_fops);
+       return 0;
+}
+late_initcall (codec_proc_init);
+#endif /* CONFIG_PROC_FS */