rk29phone: fix wm8994 suspend and resume noise
author邱建斌 <qjb@rock-chips.com>
Thu, 30 Jun 2011 03:17:37 +0000 (11:17 +0800)
committer邱建斌 <qjb@rock-chips.com>
Thu, 30 Jun 2011 03:17:37 +0000 (11:17 +0800)
arch/arm/configs/rk29_FIH_defconfig
arch/arm/configs/rk29_newton_defconfig
arch/arm/configs/rk29_phonepadsdk_defconfig
arch/arm/configs/rk29_sdk_defconfig
drivers/headset_observe/Kconfig
drivers/headset_observe/rk_headset.c
sound/soc/codecs/wm8994.c
sound/soc/codecs/wm8994.h

index d9449fd7d9b649a7c7b76055d443be53637b2f24..7db412162badb516ab912d556c1db135090a9741 100644 (file)
@@ -988,7 +988,7 @@ CONFIG_ADC_RK29=y
 #
 # Headset device support
 #
-CONFIG_RK_HEADSET_DET=y
+# CONFIG_RK_HEADSET_DET is not set
 
 #
 # PPS support
index 6bf1ecc8b31694fed7a4512d6a3818b2d822d6c9..eb198a7253c718b45374f95d66c05336f20eb7a5 100644 (file)
@@ -967,9 +967,8 @@ CONFIG_ADC_RK29=y
 #
 # Headset device support
 #
-CONFIG_RK_HEADSET_DET=y
+# CONFIG_RK_HEADSET_DET is not set
 
-#
 # PPS support
 #
 # CONFIG_PPS is not set
index bc8451cdb8b40139973315d2a79412ddc25e14f4..09ad0de837b7a1d1213f63e7c44dbada1a3d682f 100755 (executable)
@@ -1154,7 +1154,7 @@ CONFIG_ADC_RK29=y
 #
 # Headset device support
 #
-CONFIG_RK_HEADSET_DET=y
+# CONFIG_RK_HEADSET_DET is not set
 
 #
 # PPS support
index 9e5f7d960a640c24716b2345689bf270e9b96459..e420fa4b4de2602b4f318edde06789e75be15cc5 100755 (executable)
@@ -1155,9 +1155,8 @@ CONFIG_ADC_RK29=y
 #
 # Headset device support
 #
-CONFIG_RK_HEADSET_DET=y
+# CONFIG_RK_HEADSET_DET is not set
 
-#
 # PPS support
 #
 # CONFIG_PPS is not set
index 19415bea9c3c787d57704c01528a1e139820933f..08381d6db6d0c62fa8573782c0a7a152d32ccd2c 100755 (executable)
@@ -12,7 +12,7 @@ config HEADSET_DET
 
 config RK_HEADSET_DET
        depends on !ARCH_RK2818
-       default y
+       default n
        tristate "RK headset detech support"
        ---help---
                Universal headphone driver(write begin rk29)
index 22c32f17a7fddc121479513a180e9fd0ef189f0a..3cad1a203dbe0e456a6b9a91f8fffad913039d23 100755 (executable)
@@ -128,7 +128,7 @@ static void headsetobserve_work(struct work_struct *work)
        int i,level = 0;
        struct rk_headset_pdata *pdata = headset_info->pdata;
        static unsigned int old_status = 0;
-       DBG("---headsetobserve_work---\n");
+//     DBG("---headsetobserve_work---\n");
        mutex_lock(&headset_info->mutex_lock[HEADSET]);
 
        for(i=0; i<3; i++)
@@ -179,7 +179,7 @@ static void headsetobserve_work(struct work_struct *work)
        case HEADSET_IN_HIGH:
                if(level > 0)
                {//in--High level
-                       DBG("--- HEADSET_IN_HIGH headset in HIGH---\n");
+               //      DBG("--- HEADSET_IN_HIGH headset in HIGH---\n");
                //      enable_irq(headset_info->irq[HOOK]);
                        headset_info->cur_headset_status = BIT_HEADSET;
                        headset_change_irqtype(HEADSET,IRQF_TRIGGER_FALLING);//
@@ -189,10 +189,10 @@ static void headsetobserve_work(struct work_struct *work)
                }
                else if(level == 0)
                {//out--Low level
-                       DBG("---HEADSET_IN_HIGH headset out HIGH---\n");        
+               //      DBG("---HEADSET_IN_HIGH headset out HIGH---\n");        
                        if(headset_info->isHook_irq == enable)
                        {
-                               DBG("disable_irq\n");
+                       //      DBG("disable_irq\n");
                                headset_info->isHook_irq = disable;
                                disable_irq(headset_info->irq[HOOK]);           
                        }       
@@ -203,14 +203,23 @@ static void headsetobserve_work(struct work_struct *work)
        case HEADSET_IN_LOW:
                if(level == 0)
                {//in--High level
-                       DBG("---HEADSET_IN_LOW headset in LOW ---\n");
+               //      DBG("---HEADSET_IN_LOW headset in LOW ---\n");
                        headset_info->cur_headset_status = BIT_HEADSET;
                        headset_change_irqtype(HEADSET,IRQF_TRIGGER_RISING);//
                        enable_irq(headset_info->irq[HOOK]);
+                       del_timer(&headset_info->headset_timer);//Start the timer, wait for switch to the headphone channel
+                       headset_info->headset_timer.expires = jiffies + 500;
+                       add_timer(&headset_info->headset_timer);                        
                }
                else if(level > 0)
                {//out--High level
-                       DBG("---HEADSET_IN_LOW headset out LOW ---\n");
+               //      DBG("---HEADSET_IN_LOW headset out LOW ---\n");
+                       if(headset_info->isHook_irq == enable)
+                       {
+                       //      DBG("disable_irq\n");
+                               headset_info->isHook_irq = disable;
+                               disable_irq(headset_info->irq[HOOK]);           
+                       }                               
                        headset_info->cur_headset_status = ~(BIT_HEADSET|BIT_HEADSET_NO_MIC);
                        headset_change_irqtype(HEADSET,IRQF_TRIGGER_FALLING);//
                        disable_irq(headset_info->irq[HOOK]);
@@ -233,14 +242,20 @@ static void Hook_work(struct work_struct *work)
        struct rk_headset_pdata *pdata = headset_info->pdata;
        static unsigned int old_status = 0;
 
-       DBG("---Hook_work---\n");
+//     DBG("---Hook_work---\n");
        mutex_lock(&headset_info->mutex_lock[HOOK]);
        if(headset_info->headset_status == HEADSET_OUT)
        {
                DBG("Headset is out\n");
                goto RE_ERROR;
        }       
-       
+       #ifdef CONFIG_SND_SOC_WM8994
+       if(wm8994_set_status() < 0)
+       {
+               DBG("wm8994 is not set on heatset channel\n");
+               goto RE_ERROR;
+       }
+       #endif          
        for(i=0; i<3; i++)
        {
                level = gpio_get_value(pdata->Hook_gpio);
@@ -294,7 +309,7 @@ static void headset_timer_callback(unsigned long arg)
        struct rk_headset_pdata *pdata = headset->pdata;
        int i,level = 0;
        
-       DBG("headset_timer_callback\n");        
+//     DBG("headset_timer_callback\n");        
 
        if(headset->headset_status == HEADSET_OUT)
        {
@@ -333,7 +348,7 @@ static void headset_timer_callback(unsigned long arg)
        else if(level > 0)      
        {       
                headset->isMic = 1;//have mic
-               DBG("enable_irq\n");    
+       //      DBG("enable_irq\n");    
                enable_irq(headset_info->irq[HOOK]);
                headset->isHook_irq = enable;
        }       
index 92a32e1ca1617f24fb2ca57c330ac2eb62b3c719..66283338cd7823509b5944818c748813ce02eefc 100755 (executable)
@@ -231,7 +231,7 @@ static int wm8994_read(unsigned short reg,unsigned short *value)
        unsigned short regs=((reg>>8)&0x00FF)|((reg<<8)&0xFF00),values;
        char i = 2;
        mutex_lock(&wm8994->io_lock);
-//     if(wm8994->RW_status == ERROR)return -EIO;
+       if(wm8994->RW_status == ERROR) goto out;
 
        while(i > 0)
        {
@@ -250,6 +250,7 @@ static int wm8994_read(unsigned short reg,unsigned short *value)
        
        wm8994->RW_status = ERROR;      
        printk("%s---line->%d:Codec read error! reg = 0x%x , value = 0x%x\n",__FUNCTION__,__LINE__,reg,*value);
+out:   
        mutex_unlock(&wm8994->io_lock);
        return -EIO;
 }
@@ -263,7 +264,8 @@ static int wm8994_write(unsigned short reg,unsigned short value)
        
        mutex_lock(&wm8994->io_lock);
 
-//     if(wm8994->RW_status == ERROR)return -EIO;
+       if(wm8994->RW_status == ERROR) goto out;
+
 #ifdef WM8994_PROC     
        if(debug_write_read != 0)
                DBG("%s:0x%04x = 0x%04x\n",__FUNCTION__,reg,value);
@@ -280,6 +282,8 @@ static int wm8994_write(unsigned short reg,unsigned short value)
        
        wm8994->RW_status = ERROR;
        printk("%s---line->%d:Codec write error! reg = 0x%x , value = 0x%x\n",__FUNCTION__,__LINE__,reg,value);
+
+out:   
        mutex_unlock(&wm8994->io_lock);
        return -EIO;
 }
@@ -402,7 +406,7 @@ static int wm8994_sysclk_config(void)
 
        if(wm8994->sysclk == 12288000)
                return wm8994_SYSCLK_12288M;
-       else if(wm8994->sysclk == 3072000)
+       else
                return wm8994_SYSCLK_3072M;
 
        printk("wm8994_sysclk_config error\n"); 
@@ -419,6 +423,38 @@ static void wm8994_set_AIF1DAC_EQ(void)
                ((bank_vol[5]+12)<<6));
 }
 
+static int wm8994_reset_ldo(void)
+{
+       struct wm8994_priv *wm8994 = wm8994_codec->private_data;        
+       struct wm8994_pdata *pdata = wm8994->pdata;
+       unsigned short value;
+       
+       if(wm8994->RW_status == TRUE)
+               return 0;
+               
+       gpio_request(pdata->Power_EN_Pin, NULL);
+       gpio_direction_output(pdata->Power_EN_Pin,GPIO_LOW);
+       gpio_free(pdata->Power_EN_Pin); 
+       msleep(50);
+       gpio_request(pdata->Power_EN_Pin, NULL);
+       gpio_direction_output(pdata->Power_EN_Pin,GPIO_HIGH);
+       gpio_free(pdata->Power_EN_Pin);         
+       msleep(50);
+       
+       wm8994->RW_status = TRUE;
+       wm8994_read(0x00,  &value);
+
+       if(value == 0x8994)
+               DBG("wm8994_reset_ldo Read ID = 0x%x\n",value);
+       else
+       {
+               wm8994->RW_status = ERROR;
+               printk("wm8994_reset_ldo Read ID error value = 0x%x\n",value);
+               return -1;
+       }       
+               
+       return 0;       
+}
 //Set the volume of each channel (including recording)
 static void wm8994_set_channel_vol(void)
 {
@@ -607,8 +643,7 @@ static void wm8994_set_channel_vol(void)
 }
 
 #define wm8994_reset() wm8994_set_all_mute();\
-                                               wm8994_write(WM8994_RESET, 0)
-                                               
+                                               wm8994_write(WM8994_RESET, 0)                                   
 
 void AP_to_headset(void)
 {
@@ -954,7 +989,7 @@ void AP_to_speakers_and_headset(void)
        DBG("%s::%d\n",__FUNCTION__,__LINE__);
        if(wm8994_current_mode==wm8994_AP_to_speakers_and_headset)return;
        wm8994_current_mode=wm8994_AP_to_speakers_and_headset;
-       wm8994_reset();
+       wm8994_write(WM8994_RESET, 0);
        msleep(WM8994_DELAY);
 
        wm8994_write(0x39,  0x006C);
@@ -1018,10 +1053,23 @@ void recorder_and_AP_to_headset(void)
 
        if(wm8994_current_mode==wm8994_recorder_and_AP_to_headset)return;
        wm8994_current_mode=wm8994_recorder_and_AP_to_headset;
-       wm8994_reset();
+       wm8994_write(WM8994_RESET, 0);
        msleep(WM8994_DELAY);
+       
+       wm8994_write(0x39, 0x006C);
 
-       wm8994_write(0x01,  0x0003);
+       wm8994_write(0x01, 0x0003);
+       msleep(35);     
+       wm8994_write(0xFF, 0x0000);
+       msleep(5);
+       wm8994_write(0x4C, 0x9F25);
+       msleep(5);
+       wm8994_write(0x01, 0x0303);
+       wm8994_write(0x60, 0x0022);
+       msleep(5);      
+       wm8994_write(0x54, 0x0033);//
+       
+//     wm8994_write(0x01,  0x0003);    
        wm8994_write(0x200, 0x0000);
        msleep(WM8994_DELAY);
 //clk
@@ -1069,14 +1117,14 @@ void recorder_and_AP_to_headset(void)
        wm8994_write(0x611, 0x01A0); // DAC1_VU=1, DAC1R_VOL=1100_0000
        wm8994_set_channel_vol();       
 //other
-       wm8994_write(0x4C,  0x9F25);            
+//     wm8994_write(0x4C,  0x9F25);            
 //power
        wm8994_write(0x01,  0x0333);
        wm8994_write(0x02,  0x6110); // TSHUT_ENA=1, TSHUT_OPDIS=1, MIXINR_ENA=1,IN1R_ENA=1
        wm8994_write(0x03,  0x3030);
        wm8994_write(0x04,  0x0303); // AIF1ADC1L_ENA=1, AIF1ADC1R_ENA=1, ADCL_ENA=1, ADCR_ENA=1
        wm8994_write(0x05,  0x0303); // AIF1DAC1L_ENA=1, AIF1DAC1R_ENA=1, DAC1L_ENA=1, DAC1R_ENA=1
-       
+
 }
 
 void recorder_and_AP_to_speakers(void)
@@ -1085,7 +1133,7 @@ void recorder_and_AP_to_speakers(void)
 
        if(wm8994_current_mode==wm8994_recorder_and_AP_to_speakers)return;
        wm8994_current_mode=wm8994_recorder_and_AP_to_speakers;
-       wm8994_reset();
+       wm8994_write(WM8994_RESET, 0);
        msleep(WM8994_DELAY);
 
        wm8994_write(0x39,  0x006C);
@@ -1148,7 +1196,7 @@ void recorder_and_AP_to_speakers(void)
        wm8994_write(0x03,  0x0330); // SPKRVOL_ENA=1, SPKLVOL_ENA=1, MIXOUTL_ENA=1, MIXOUTR_ENA=1  
        wm8994_write(0x05,  0x0303); // AIF1DAC1L_ENA=1, AIF1DAC1R_ENA=1, DAC1L_ENA=1, DAC1R_ENA=1      
        wm8994_write(0x01,  0x3003);
-       msleep(20);
+       msleep(50);
        wm8994_write(0x01,  0x3033);
 }
 
@@ -2610,7 +2658,7 @@ int snd_soc_put_route(struct snd_kcontrol *kcontrol,
                wm8994_write(0,0);
                msleep(50);
                goto out;
-       }       
+       }
        //before set the route -- disable PA
        switch(route)
        {
@@ -2686,6 +2734,14 @@ int snd_soc_put_route(struct snd_kcontrol *kcontrol,
                        printk("wm8994 error route!!!\n");
                        goto out;
        }
+
+       if(wm8994->RW_status == ERROR)
+       {//Failure to read or write, will re-power on wm8994
+               cancel_delayed_work_sync(&wm8994->wm8994_delayed_work);
+               wm8994->work_type = SNDRV_PCM_TRIGGER_PAUSE_PUSH;
+               schedule_delayed_work(&wm8994->wm8994_delayed_work, msecs_to_jiffies(10));
+               goto out;
+       }
        //after set the route -- enable PA
        switch(route)
        {
@@ -2875,7 +2931,6 @@ static void wm8994_work_fun(struct work_struct *work)
        struct snd_soc_codec *codec = wm8994_codec;
        struct wm8994_priv *wm8994 = codec->private_data;
        struct wm8994_pdata *pdata = wm8994->pdata;
-       unsigned short value;
        int error_count = 5;
 //     DBG("Enter %s---%d = %d\n",__FUNCTION__,__LINE__,wm8994_current_mode);
 
@@ -2903,23 +2958,25 @@ static void wm8994_work_fun(struct work_struct *work)
                        {
                        //      DBG("wm8994->kcontrol->private_value != SPEAKER_NORMAL\n");
                                return;
-                       }       
+                       }
                        wm8994_current_mode = null;
                        snd_soc_put_route(wm8994->kcontrol,NULL);
                }               
                break;
        case SNDRV_PCM_TRIGGER_RESUME:  
                msleep(100);
+               gpio_request(pdata->Power_EN_Pin, NULL);
+               gpio_direction_output(pdata->Power_EN_Pin,GPIO_HIGH);
+               gpio_free(pdata->Power_EN_Pin);         
+               msleep(100);
+               wm8994_current_mode = null;
+               snd_soc_put_route(wm8994->kcontrol,NULL);
+               break;
+       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:      
                while(error_count)
                {
-                       gpio_request(pdata->Power_EN_Pin, NULL);
-                       gpio_direction_output(pdata->Power_EN_Pin,GPIO_HIGH);
-                       gpio_free(pdata->Power_EN_Pin);
-                       msleep(100);
-                       wm8994_read(0x00,  &value);
-                       if(value == 0x8994)
+                       if( wm8994_reset_ldo() ==  0)
                        {
-                               DBG("wm8994 Resume Read ID = 0x%x\n",value);
                                wm8994_current_mode = null;
                                snd_soc_put_route(wm8994->kcontrol,NULL);
                                break;
@@ -2927,8 +2984,12 @@ static void wm8994_work_fun(struct work_struct *work)
                        error_count --;
                }
                if(error_count == 0)
-                       printk("wm8994 resume power on error value = %d\n",value);
+               {
+                       PA_ctrl(GPIO_LOW);
+                       printk("wm8994 Major problems, give me log,tks, -- qjb\n");
+               }       
                break;
+
        default:
                break;
        }
@@ -2978,6 +3039,8 @@ static int wm8994_suspend(struct platform_device *pdev, pm_message_t state)
        struct wm8994_pdata *pdata = wm8994->pdata;
        
        DBG("%s----%d\n",__FUNCTION__,__LINE__);
+
+       cancel_delayed_work_sync(&wm8994->wm8994_delayed_work); 
        PA_ctrl(GPIO_LOW);
        wm8994_write(0x00, 0x00);
        
@@ -2998,7 +3061,7 @@ static int wm8994_resume(struct platform_device *pdev)
        
        DBG("%s----%d\n",__FUNCTION__,__LINE__);
 
-
+       cancel_delayed_work_sync(&wm8994->wm8994_delayed_work); 
        wm8994->work_type = SNDRV_PCM_TRIGGER_RESUME;
        schedule_delayed_work(&wm8994->wm8994_delayed_work, msecs_to_jiffies(0));       
 
@@ -3014,8 +3077,8 @@ static ssize_t wm8994_proc_write(struct file *file, const char __user *buffer,
        int reg;
        int value;
        struct snd_kcontrol kcontrol;
-//     struct wm8994_priv *wm8994 = wm8994_codec->private_data;
-//     struct wm8994_pdata *pdata = wm8994->pdata;
+       struct wm8994_priv *wm8994 = wm8994_codec->private_data;
+       struct wm8994_pdata *pdata = wm8994->pdata;
        
        cookie_pot = (char *)vmalloc( len );
        if (!cookie_pot) 
@@ -3152,6 +3215,16 @@ static ssize_t wm8994_proc_write(struct file *file, const char __user *buffer,
                                break;                          
                }               
                break;  
+       case '1':
+               gpio_request(pdata->Power_EN_Pin, NULL);
+               gpio_direction_output(pdata->Power_EN_Pin,GPIO_LOW);
+               gpio_free(pdata->Power_EN_Pin); 
+               break;
+       case '2':       
+               gpio_request(pdata->Power_EN_Pin, NULL);
+               gpio_direction_output(pdata->Power_EN_Pin,GPIO_HIGH);
+               gpio_free(pdata->Power_EN_Pin);                 
+               break;
        default:
                DBG("Help for wm8994_ts .\n-->The Cmd list: \n");
                DBG("-->'d&&D' Open or close the debug\n");
index 419f6dc60f2827c389f2254c2dbaf00ed665cb61..62d4e7a2c17f45ad3837e1218028b397f9b0dbb7 100755 (executable)
@@ -30,7 +30,7 @@
 extern struct snd_soc_dai wm8994_dai;
 extern struct snd_soc_codec_device soc_codec_dev_wm8994;
 
-#define ERROR -1
+#define ERROR 1
 #define TRUE 0
 
 #endif