add wm8988 driver for kernel3.0
author陈金泉 <chenjq@rock-chips.com>
Mon, 21 Nov 2011 12:46:27 +0000 (20:46 +0800)
committer陈金泉 <chenjq@rock-chips.com>
Mon, 21 Nov 2011 12:46:27 +0000 (20:46 +0800)
arch/arm/mach-rk29/board-rk29-ddr3sdk.c
sound/soc/codecs/wm8988.c
sound/soc/rk29/rk29_wm8988.c

index b589b176341f06c1f4531d2a991a79a52cebd191..295cb617c47f00bdba7f4d8758554c1e505282ca 100755 (executable)
@@ -1418,7 +1418,7 @@ static struct i2c_board_info __initdata board_i2c0_devices[] = {
                 .flags                  = 0,
         },
 #endif
-#if defined (CONFIG_SND_SOC_alc5631)
+#if defined (CONFIG_SND_SOC_RT5631)
         {
                 .type                   = "rt5631",
                 .addr                   = 0x1a,
@@ -1432,6 +1432,13 @@ static struct i2c_board_info __initdata board_i2c0_devices[] = {
                .flags                  = 0,
        },
 #endif
+#if defined (CONFIG_SND_SOC_WM8988)
+       {
+               .type                   = "wm8988",
+               .addr           = 0x1A,
+               .flags                  = 0,
+       },
+#endif
 #if defined (CONFIG_SND_SOC_WM8900)
        {
                .type                   = "wm8900",
index d7170f1381aa758084834de1f7eae0532d7e00a7..89bbc7dd242e37b529f26ef86770018ffe41da26 100644 (file)
 #include <sound/pcm_params.h>
 #include <sound/tlv.h>
 #include <sound/soc.h>
+#include <sound/soc-dapm.h>
 #include <sound/initval.h>
 
+#include <mach/iomux.h>
+#include <mach/gpio.h>
+
 #include "wm8988.h"
 
+#include <linux/proc_fs.h>
+#include <linux/gpio.h>
+
+#if 0
+#define DBG(x...) printk(KERN_INFO x)
+#else
+#define DBG(x...) do { } while (0)
+#endif
+
 /*
  * wm8988 register cache
  * We can't read the WM8988 register space when we
@@ -53,6 +66,8 @@ struct wm8988_priv {
        unsigned int sysclk;
        enum snd_soc_control_type control_type;
        struct snd_pcm_hw_constraint_list *sysclk_constraints;
+       int is_startup;         // gModify.Add
+       int is_biason;
 };
 
 
@@ -190,6 +205,8 @@ static int wm8988_lrc_control(struct snd_soc_dapm_widget *w,
        else
                adctl2 |= 0x4;
 
+       DBG("Enter::%s----%d, adctl2 = %x\n",__FUNCTION__,__LINE__,adctl2);
+       
        return snd_soc_write(codec, WM8988_ADCTL2, adctl2);
 }
 
@@ -290,8 +307,9 @@ static const struct snd_soc_dapm_widget wm8988_dapm_widgets[] = {
        SND_SOC_DAPM_ADC("Right ADC", "Right Capture", WM8988_PWR1, 2, 0),
        SND_SOC_DAPM_ADC("Left ADC", "Left Capture", WM8988_PWR1, 3, 0),
 
-       SND_SOC_DAPM_DAC("Right DAC", "Right Playback", WM8988_PWR2, 7, 0),
-       SND_SOC_DAPM_DAC("Left DAC", "Left Playback", WM8988_PWR2, 8, 0),
+       /* gModify.Cmmt Implement when suspend/startup */
+       /*SND_SOC_DAPM_DAC("Right DAC", "Right Playback", WM8988_PWR2, 7, 0),*/
+       /*SND_SOC_DAPM_DAC("Left DAC", "Left Playback", WM8988_PWR2, 8, 0),*/
 
        SND_SOC_DAPM_MIXER("Left Mixer", SND_SOC_NOPM, 0, 0,
                &wm8988_left_mixer_controls[0],
@@ -477,7 +495,7 @@ static struct snd_pcm_hw_constraint_list constraints_112896 = {
 };
 
 static unsigned int rates_12[] = {
-       8000, 11025, 12000, 16000, 22050, 2400, 32000, 41100, 48000,
+       8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000,
        48000, 88235, 96000,
 };
 
@@ -495,6 +513,8 @@ static int wm8988_set_dai_sysclk(struct snd_soc_dai *codec_dai,
        struct snd_soc_codec *codec = codec_dai->codec;
        struct wm8988_priv *wm8988 = snd_soc_codec_get_drvdata(codec);
 
+    DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
+               
        switch (freq) {
        case 11289600:
        case 18432000:
@@ -575,6 +595,8 @@ static int wm8988_set_dai_fmt(struct snd_soc_dai *codec_dai,
                return -EINVAL;
        }
 
+       DBG("Enter::%s----%d  iface=%x\n",__FUNCTION__,__LINE__,iface);
+
        snd_soc_write(codec, WM8988_IFACE, iface);
        return 0;
 }
@@ -585,6 +607,17 @@ static int wm8988_pcm_startup(struct snd_pcm_substream *substream,
        struct snd_soc_codec *codec = dai->codec;
        struct wm8988_priv *wm8988 = snd_soc_codec_get_drvdata(codec);
 
+       if (!wm8988->is_startup) {
+               wm8988->is_startup = 1;
+               snd_soc_write(codec, WM8988_PWR1, 0xfc);
+               gpio_direction_output(RK29_PIN6_PB5, GPIO_LOW);
+               mdelay(100);            // Discharge C310
+               snd_soc_write(codec, WM8988_PWR2, 0x1e0);
+               gpio_direction_output(RK29_PIN6_PB5, GPIO_HIGH);
+       }
+
+       DBG("Enter::%s----%d  wm8988->sysclk=%d\n",__FUNCTION__,__LINE__,wm8988->sysclk); 
+
        /* The set of sample rates that can be supported depends on the
         * MCLK supplied to the CODEC - enforce this.
         */
@@ -639,6 +672,8 @@ static int wm8988_pcm_hw_params(struct snd_pcm_substream *substream,
                break;
        }
 
+       DBG("Enter::%s----%d  iface=%x srate =%x rate=%d\n",__FUNCTION__,__LINE__,iface,srate,params_rate(params));
+
        /* set iface & srate */
        snd_soc_write(codec, WM8988_IFACE, iface);
        if (coeff >= 0)
@@ -653,6 +688,8 @@ static int wm8988_mute(struct snd_soc_dai *dai, int mute)
        struct snd_soc_codec *codec = dai->codec;
        u16 mute_reg = snd_soc_read(codec, WM8988_ADCDAC) & 0xfff7;
 
+       DBG("Enter::%s----%d--mute=%d\n",__FUNCTION__,__LINE__,mute);
+
        if (mute)
                snd_soc_write(codec, WM8988_ADCDAC, mute_reg | 0x8);
        else
@@ -663,13 +700,22 @@ static int wm8988_mute(struct snd_soc_dai *dai, int mute)
 static int wm8988_set_bias_level(struct snd_soc_codec *codec,
                                 enum snd_soc_bias_level level)
 {
+       struct wm8988_priv *wm8988 = snd_soc_codec_get_drvdata(codec);
        u16 pwr_reg = snd_soc_read(codec, WM8988_PWR1) & ~0x1c1;
 
+       DBG("Enter::%s----%d level =%d\n",__FUNCTION__,__LINE__,level);
+
        switch (level) {
        case SND_SOC_BIAS_ON:
+               wm8988->is_biason = 1;
                break;
 
        case SND_SOC_BIAS_PREPARE:
+               if (wm8988->is_startup && wm8988->is_biason) {
+                       snd_soc_write(codec, WM8988_PWR2, 0x0);
+                       wm8988->is_startup = 0;
+                       wm8988->is_biason = 0;
+               }
                /* VREF, VMID=2x50k, digital enabled */
                snd_soc_write(codec, WM8988_PWR1, pwr_reg | 0x00c0);
                break;
@@ -709,7 +755,7 @@ static struct snd_soc_dai_ops wm8988_ops = {
 };
 
 static struct snd_soc_dai_driver wm8988_dai = {
-       .name = "wm8988-hifi",
+       .name = "WM8988 HiFi",
        .playback = {
                .stream_name = "Playback",
                .channels_min = 1,
@@ -730,6 +776,8 @@ static struct snd_soc_dai_driver wm8988_dai = {
 
 static int wm8988_suspend(struct snd_soc_codec *codec, pm_message_t state)
 {
+       DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
+
        wm8988_set_bias_level(codec, SND_SOC_BIAS_OFF);
        return 0;
 }
@@ -740,6 +788,8 @@ static int wm8988_resume(struct snd_soc_codec *codec)
        u8 data[2];
        u16 *cache = codec->reg_cache;
 
+       DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
+
        /* Sync reg_cache with the hardware */
        for (i = 0; i < WM8988_NUM_REG; i++) {
                if (i == WM8988_RESET)
@@ -748,12 +798,30 @@ static int wm8988_resume(struct snd_soc_codec *codec)
                data[1] = cache[i] & 0x00ff;
                codec->hw_write(codec->control_data, data, 2);
        }
+       
+       //snd_soc_write(codec, WM8988_PWR1, 0xfc);
+       //snd_soc_write(codec, WM8988_PWR2, 0x1e0);
 
        wm8988_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
        return 0;
 }
 
+static struct snd_soc_codec *wm8988_codec;
+
+static int entry_read(char *page, char **start, off_t off,
+               int count, int *eof, void *data)
+{
+       int len;
+
+       snd_soc_write(wm8988_codec, WM8988_PWR1, 0x0000);
+       snd_soc_write(wm8988_codec, WM8988_PWR2, 0x0000);
+
+       len = sprintf(page, "wm8988 suspend...\n");
+
+       return len ;
+}
+
 static int wm8988_probe(struct snd_soc_codec *codec)
 {
        struct wm8988_priv *wm8988 = snd_soc_codec_get_drvdata(codec);
@@ -761,6 +829,13 @@ static int wm8988_probe(struct snd_soc_codec *codec)
        int ret = 0;
        u16 reg;
 
+       if (codec == NULL) {
+               dev_err(codec->dev, "Codec device not registered\n");
+               return -ENODEV;
+       }
+
+       wm8988_codec = codec;
+
        ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8988->control_type);
        if (ret < 0) {
                dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
@@ -773,6 +848,14 @@ static int wm8988_probe(struct snd_soc_codec *codec)
                return ret;
        }
 
+#if 0
+               /*disable speaker */
+               gpio_request(RK2818_PIN_PF7, "WM8988"); 
+               rk2818_mux_api_set(GPIOE_SPI1_FLASH_SEL_NAME, IOMUXA_GPIO1_A3B7);
+               gpio_direction_output(RK2818_PIN_PF7,GPIO_HIGH);
+               
+#endif
+
        /* set the update bits (we always update left then right) */
        reg = snd_soc_read(codec, WM8988_RADC);
        snd_soc_write(codec, WM8988_RADC, reg | 0x100);
@@ -783,7 +866,40 @@ static int wm8988_probe(struct snd_soc_codec *codec)
        reg = snd_soc_read(codec, WM8988_ROUT2V);
        snd_soc_write(codec, WM8988_ROUT2V, reg | 0x0100);
        reg = snd_soc_read(codec, WM8988_RINVOL);
-       snd_soc_write(codec, WM8988_RINVOL, reg | 0x0100);
+       snd_soc_write(codec, WM8988_RINVOL, reg | 0x0100); 
+       
+       snd_soc_write(codec, WM8988_LOUTM1, 0x120); 
+       snd_soc_write(codec, WM8988_ROUTM2, 0x120);  
+       snd_soc_write(codec, WM8988_LOUTM2, 0x0070);
+       snd_soc_write(codec, WM8988_ROUTM1, 0x0070);
+//tcl miaozh modify    
+//     snd_soc_write(codec, WM8988_LOUT1V, 0x017f); 
+//     snd_soc_write(codec, WM8988_ROUT1V, 0x017f);
+       snd_soc_write(codec, WM8988_LOUT1V, 0x017a); 
+       snd_soc_write(codec, WM8988_ROUT1V, 0x017a);
+       
+       snd_soc_write(codec, WM8988_LDAC, 0xfa/*0xff*/);  // Change max by zhansb@110415
+       snd_soc_write(codec, WM8988_RDAC, 0x1fa/*0x1ff*/);//vol set 
+
+       //TCL lgw add 20110412
+       snd_soc_write(codec, WM8988_LINVOL,  0x0117);
+       snd_soc_write(codec, WM8988_RINVOL,  0x0117);
+
+       snd_soc_write(codec, WM8988_ADCTL2, 0x0184);
+
+       snd_soc_write(codec, WM8988_LADC, 0x01ec);
+       snd_soc_write(codec, WM8988_RADC, 0x01ec);
+       
+       snd_soc_write(codec, WM8988_ADCIN,  0x0140);
+       snd_soc_write(codec, WM8988_LADCIN, 0x00f0);//0x00e0
+       snd_soc_write(codec, WM8988_RADCIN, 0x0);//0x00e0
+       //lgw end
+       
+       snd_soc_write(codec, WM8988_SRATE,0x100);  ///SET MCLK/8
+       //snd_soc_write(codec, WM8988_PWR1, 0x1cc);  ///(0x80|0x40|0x20|0x08|0x04|0x10|0x02));
+       //TCL lgw modify 20110412
+       //snd_soc_write(codec, WM8988_PWR1, 0xfc);
+       //snd_soc_write(codec, WM8988_PWR2, 0x1e0);  //power r l out1
 
        wm8988_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
@@ -792,6 +908,7 @@ static int wm8988_probe(struct snd_soc_codec *codec)
        snd_soc_dapm_new_controls(dapm, wm8988_dapm_widgets,
                                  ARRAY_SIZE(wm8988_dapm_widgets));
        snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
+       create_proc_read_entry("wm8988_suspend", 0644, NULL, entry_read, NULL);
 
        return 0;
 }
@@ -842,7 +959,7 @@ static int __devexit wm8988_spi_remove(struct spi_device *spi)
 
 static struct spi_driver wm8988_spi_driver = {
        .driver = {
-               .name   = "wm8988-codec",
+               .name   = "WM8988",
                .owner  = THIS_MODULE,
        },
        .probe          = wm8988_spi_probe,
@@ -886,7 +1003,7 @@ MODULE_DEVICE_TABLE(i2c, wm8988_i2c_id);
 
 static struct i2c_driver wm8988_i2c_driver = {
        .driver = {
-               .name = "wm8988-codec",
+               .name = "WM8988",
                .owner = THIS_MODULE,
        },
        .probe =    wm8988_i2c_probe,
index 29c4a709ab84a91cfdf7feab8c9b35d4443cb0f3..e9abd89e43b5e44f5d689d02cd4017c76f635308 100755 (executable)
@@ -1,5 +1,5 @@
 /*
- * rk2818_wm8988.c  --  SoC audio for rockchip
+ * rk29_wm8988.c  --  SoC audio for rockchip
  *
  * Driver for rockchip wm8988 audio
  *
 #include "rk29_pcm.h"
 #include "rk29_i2s.h"
 
+#include <mach/gpio.h>
+
 #if 0
 #define        DBG(x...)       printk(KERN_INFO x)
 #else
 #define        DBG(x...)
 #endif
 
-static int rk2818_hw_params(struct snd_pcm_substream *substream,
+//static void *rk29_speaker = NULL;
+
+static int rk29_hw_params(struct snd_pcm_substream *substream,
        struct snd_pcm_hw_params *params)
 {
-    struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
-       struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
        int ret;
          
     DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);    
@@ -44,39 +48,39 @@ static int rk2818_hw_params(struct snd_pcm_substream *substream,
        #define HW_PARAMS_FLAG_EQVOL_OFF 0x22
     if ((params->flags == HW_PARAMS_FLAG_EQVOL_ON)||(params->flags == HW_PARAMS_FLAG_EQVOL_OFF))
     {
-       ret = codec_dai->ops->hw_params(substream, params, codec_dai); //by Vincent
+               ret = codec_dai->driver->ops->hw_params(substream, params, codec_dai); //by Vincent
        DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
     }
     else
     {
            /* set codec DAI configuration */
-           #if defined (CONFIG_SND_CODEC_SOC_SLAVE) 
-           ret = codec_dai->ops->set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
+           #if defined (CONFIG_SND_RK29_CODEC_SOC_SLAVE) 
+                ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
                SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); 
            #endif      
-           #if defined (CONFIG_SND_CODEC_SOC_MASTER) 
-           ret = codec_dai->ops->set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
+           #if defined (CONFIG_SND_RK29_CODEC_SOC_MASTER) 
+                ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
                SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM ); 
            #endif
            if (ret < 0)
                  return ret; 
            /* set cpu DAI configuration */
-           #if defined (CONFIG_SND_CODEC_SOC_SLAVE) 
-           ret = cpu_dai->ops->set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
+           #if defined (CONFIG_SND_RK29_CODEC_SOC_SLAVE) 
+                ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
                SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
            #endif      
-           #if defined (CONFIG_SND_CODEC_SOC_MASTER) 
-           ret = cpu_dai->ops->set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
+           #if defined (CONFIG_SND_RK29_CODEC_SOC_MASTER) 
+                ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
                SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); 
            #endif              
            if (ret < 0)
                  return ret;
          }
-    
+       
          return 0;
 }
 
-static const struct snd_soc_dapm_widget rk2818_dapm_widgets[] = {
+static const struct snd_soc_dapm_widget rk29_dapm_widgets[] = {
        SND_SOC_DAPM_LINE("Audio Out", NULL),
        SND_SOC_DAPM_LINE("Line in", NULL),
        SND_SOC_DAPM_MIC("Micn", NULL),
@@ -96,84 +100,86 @@ static const struct snd_soc_dapm_route audio_map[]= {
 /*
  * Logic for a wm8988 as connected on a rockchip board.
  */
-static int rk2818_wm8988_init(struct snd_soc_codec *codec)
+static int rk29_wm8988_init(struct snd_soc_pcm_runtime *rtd)
 {
-       struct snd_soc_dai *codec_dai = &codec->dai[0];
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+       struct snd_soc_codec *codec = rtd->codec;
+       struct snd_soc_dapm_context *dapm = &codec->dapm;
        int ret;
          
     DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
     
     ret = snd_soc_dai_set_sysclk(codec_dai, 0,
-               12000000, SND_SOC_CLOCK_IN);
+               /*12000000*/11289600, SND_SOC_CLOCK_IN);
        if (ret < 0) {
                printk(KERN_ERR "Failed to set WM8988 SYSCLK: %d\n", ret);
                return ret;
        }
        
     /* Add specific widgets */
-       snd_soc_dapm_new_controls(codec, rk2818_dapm_widgets,
-                                 ARRAY_SIZE(rk2818_dapm_widgets));
-       snd_soc_dapm_nc_pin(codec, "LOUT2");
-       snd_soc_dapm_nc_pin(codec, "ROUT2");
+       snd_soc_dapm_new_controls(dapm, rk29_dapm_widgets,
+                                 ARRAY_SIZE(rk29_dapm_widgets));
+       //snd_soc_dapm_nc_pin(codec, "LOUT2");
+       //snd_soc_dapm_nc_pin(codec, "ROUT2");
        
     /* Set up specific audio path audio_mapnects */
-    snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
+        snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
        
-    snd_soc_dapm_sync(codec);
+        snd_soc_dapm_sync(dapm);
  
     return 0;
 }
 
-static struct snd_soc_ops rk2818_ops = {
-         .hw_params = rk2818_hw_params,
+static struct snd_soc_ops rk29_ops = {
+         .hw_params = rk29_hw_params,
 };
 
-static struct snd_soc_dai_link rk2818_dai = {
-         .name = "WM8988",
-         .stream_name = "WM8988 PCM",
-         .cpu_dai = &rk2818_i2s_dai,
-         .codec_dai = &wm8988_dai,
-         .init = rk2818_wm8988_init,
-         .ops = &rk2818_ops,
+static struct snd_soc_dai_link rk29_dai = {
+       .name = "WM8988",
+       .stream_name = "WM8988 PCM",
+       .codec_name = "WM8988.0-001a",
+       .platform_name = "rockchip-audio",
+       .cpu_dai_name = "rk29_i2s.0",
+       .codec_dai_name = "WM8988 HiFi",
+       .init = rk29_wm8988_init,
+       .ops = &rk29_ops,
 };
 
-static struct snd_soc_card snd_soc_card_rk2818 = {
-         .name = "RK2818_WM8988",
-         .platform = &rk2818_soc_platform,
-         .dai_link = &rk2818_dai,
-         .num_links = 1,
+static struct snd_soc_card snd_soc_card_rk29 = {
+       .name = "RK29_WM8988",
+       .dai_link = &rk29_dai,
+       .num_links = 1,
 };
 
-
-static struct snd_soc_device rk2818_snd_devdata = {
-         .card = &snd_soc_card_rk2818,
-         .codec_dev = &soc_codec_dev_wm8988,
-};
-
-static struct platform_device *rk2818_snd_device;
+static struct platform_device *rk29_snd_device;
 
 static int __init audio_card_init(void)
 {
-       int ret =0;     
+    int ret =0;        
+       
+    //rk29_speaker = rk29_speaker_init(RK29_PIN6_PB6, GPIO_HIGH, 2, (200*1000*1000));
+
     DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
-       rk2818_snd_device = platform_device_alloc("soc-audio", -1);
-       if (!rk2818_snd_device) {
+       rk29_snd_device = platform_device_alloc("soc-audio", -1);
+       if (!rk29_snd_device) {
                  DBG("platform device allocation failed\n");
                  ret = -ENOMEM;
                  return ret;
        }
-       platform_set_drvdata(rk2818_snd_device, &rk2818_snd_devdata);
-       rk2818_snd_devdata.dev = &rk2818_snd_device->dev;
-       ret = platform_device_add(rk2818_snd_device);
+       platform_set_drvdata(rk29_snd_device, &snd_soc_card_rk29);
+       ret = platform_device_add(rk29_snd_device);
        if (ret) {
            DBG("platform device add failed\n");
-           platform_device_put(rk2818_snd_device);
+           platform_device_put(rk29_snd_device);
+            return ret;
        }
-       return ret;
+               
+        return ret;
 }
 static void __exit audio_card_exit(void)
 {
-       platform_device_unregister(rk2818_snd_device);
+    platform_device_unregister(rk29_snd_device);
+    //rk29_speaker_deinit(rk29_speaker);       
 }
 
 module_init(audio_card_init);