rk29_phone: fix hook key irq. if headset have not hook key then not reported keydown
author邱建斌 <qjb@rock-chips.com>
Tue, 28 Jun 2011 02:32:21 +0000 (10:32 +0800)
committer邱建斌 <qjb@rock-chips.com>
Tue, 28 Jun 2011 02:32:21 +0000 (10:32 +0800)
arch/arm/mach-rk29/board-rk29-a22.c
arch/arm/mach-rk29/board-rk29-phonesdk.c
drivers/headset_observe/rk_headset.c
drivers/headset_observe/rk_headset.h
sound/soc/codecs/wm8994.c

index 68f14f77102fdf0e7a10a2cdc30939baf92f21c6..f665242e61565adccd2a361f87cd13c784c60ff0 100755 (executable)
@@ -1532,6 +1532,7 @@ struct rk_headset_pdata rk_headset_info = {
        .Headset_gpio           = RK29_PIN3_PA6,
        .headset_in_type= HEADSET_IN_HIGH,
        .Hook_gpio = RK29_PIN4_PD1,//Detection Headset--Must be set
+       .hook_key_code = KEY_MEDIA,
 };
 
 struct platform_device rk_device_headset = {
index 8e5b2fd2866dd20189bf0a3c007124ea7875fcd5..f87c1d6755634df8fb4fc56cb3a2508f31499c90 100755 (executable)
@@ -1617,6 +1617,7 @@ struct rk_headset_pdata rk_headset_info = {
        .Headset_gpio           = RK29_PIN4_PD2,
        .headset_in_type= HEADSET_IN_HIGH,
        .Hook_gpio = RK29_PIN4_PD1,//Detection Headset--Must be set
+       .hook_key_code = KEY_MEDIA,
 };
 
 struct platform_device rk_device_headset = {
index 64d870c102988f35bcd9d42de82ab8e504609c11..5fcccad310908533b315e5bbb1cf298dcf0a43a7 100755 (executable)
@@ -39,7 +39,7 @@
 #include <linux/earlysuspend.h>
 
 /* Debug */
-#if 0
+#if 1
 #define DBG(x...) printk(x)
 #else
 #define DBG(x...) do { } while (0)
 #define HEADSET 0
 #define HOOK 1
 
+#define HEADSET_IN 1
+#define HEADSET_OUT 0
+#define HOOK_DOWN 0
+#define HOOK_UP 1
+#define enable 1
+#define disable 0
+
+extern int wm8994_set_status(void);
 /* headset private data */
 struct headset_priv {
        struct input_dev *input_dev;
        struct rk_headset_pdata *pdata;
        unsigned int headset_status:1;
        unsigned int hook_status:1;
-       
-       struct switch_dev sdev;
+       unsigned int isMic:1;
+       unsigned int isHook_irq:1;
        int cur_headset_status; 
-       struct mutex mutex_lock[2];     
        
        unsigned int irq[2];
        unsigned int irq_type[2];
-       struct delayed_work h_delayed_work[2];          
-       
+       struct delayed_work h_delayed_work[2];
+       struct switch_dev sdev;
+       struct mutex mutex_lock[2];     
+       struct timer_list headset_timer;
        unsigned char *keycodes;
 };
 static struct headset_priv *headset_info;
@@ -74,13 +83,14 @@ static struct headset_priv *headset_info;
 static irqreturn_t headset_interrupt(int irq, void *dev_id)
 {
 //     DBG("---headset_interrupt---\n");       
-       schedule_delayed_work(&headset_info->h_delayed_work[HEADSET], msecs_to_jiffies(20));
+       schedule_delayed_work(&headset_info->h_delayed_work[HEADSET], msecs_to_jiffies(50));
        return IRQ_HANDLED;
 }
 
 static irqreturn_t Hook_interrupt(int irq, void *dev_id)
 {
 //     DBG("---Hook_interrupt---\n");  
+//     disable_irq_nosync(headset_info->irq[HOOK]);
        schedule_delayed_work(&headset_info->h_delayed_work[HOOK], msecs_to_jiffies(100));
        return IRQ_HANDLED;
 }
@@ -117,7 +127,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++)
@@ -135,7 +145,7 @@ static void headsetobserve_work(struct work_struct *work)
        if(level < 0)
        {
                printk("%s:get pin level  err!\n",__FUNCTION__);
-               return;
+               goto RE_ERROR;
        }
 
        old_status = headset_info->headset_status;
@@ -143,15 +153,15 @@ static void headsetobserve_work(struct work_struct *work)
        {
        case HEADSET_IN_HIGH:
                if(level > 0)
-                       headset_info->headset_status = 1;
+                       headset_info->headset_status = HEADSET_IN;
                else if(level == 0)
-                       headset_info->headset_status = 0;       
+                       headset_info->headset_status = HEADSET_OUT;     
                break;
        case HEADSET_IN_LOW:
                if(level == 0)
-                       headset_info->headset_status = 1;
+                       headset_info->headset_status = HEADSET_IN;
                else if(level > 0)
-                       headset_info->headset_status = 0;               
+                       headset_info->headset_status = HEADSET_OUT;             
                break;                  
        default:
                DBG("---- ERROR: on headset headset_in_type error -----\n");
@@ -159,58 +169,60 @@ static void headsetobserve_work(struct work_struct *work)
        }
        if(old_status == headset_info->headset_status)
        {
-               printk("old_status == headset_info->headset_status\n");
-               mutex_unlock(&headset_info->mutex_lock[HEADSET]);       
-               return;
+               DBG("old_status == headset_info->headset_status\n");
+               goto RE_ERROR;
        }
 
        switch(pdata->headset_in_type)
        {
-               case HEADSET_IN_HIGH:
-                       if(level > 0)
-                       {//in--High level
-                               DBG("--- HEADSET_IN_HIGH headset in HIGH---\n");
-                               enable_irq(headset_info->irq[HOOK]);
-                               headset_info->headset_status = 1;
-                               headset_info->cur_headset_status = BIT_HEADSET;
-                               headset_change_irqtype(HEADSET,IRQF_TRIGGER_FALLING);//
-                       }
-                       else if(level == 0)
-                       {//out--Low level
-                               DBG("---HEADSET_IN_HIGH headset out HIGH---\n");        
+       case HEADSET_IN_HIGH:
+               if(level > 0)
+               {//in--High level
+                       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);//
+                       del_timer(&headset_info->headset_timer);//Æô¶¯¶¨Ê±Æ÷£¬µÈ´ýÇл»µ½¶ú»úͨ·
+                       headset_info->headset_timer.expires = jiffies + 500;
+                       add_timer(&headset_info->headset_timer);
+               }
+               else if(level == 0)
+               {//out--Low level
+                       DBG("---HEADSET_IN_HIGH headset out HIGH---\n");        
+                       if(headset_info->isHook_irq == enable)
+                       {
+                               DBG("disable_irq\n");
+                               headset_info->isHook_irq = disable;
                                disable_irq(headset_info->irq[HOOK]);           
-                               headset_info->headset_status = 0;       
-                               headset_info->cur_headset_status = ~(BIT_HEADSET|BIT_HEADSET_NO_MIC);
-                               headset_change_irqtype(HEADSET,IRQF_TRIGGER_RISING);//
-                       }
-                       break;
-               case HEADSET_IN_LOW:
-                       if(level == 0)
-                       {//in--High level
-                               DBG("---HEADSET_IN_LOW headset in LOW ---\n");
-                               headset_info->headset_status = 1;
-                               headset_info->cur_headset_status = BIT_HEADSET;
-                               headset_change_irqtype(HEADSET,IRQF_TRIGGER_RISING);//
-                               enable_irq(headset_info->irq[HOOK]);
-                       }
-                       else if(level > 0)
-                       {//out--High level
-                               DBG("---HEADSET_IN_LOW headset out LOW ---\n");
-                               headset_info->headset_status = 0;               
-                               headset_info->cur_headset_status = ~(BIT_HEADSET|BIT_HEADSET_NO_MIC);
-                               headset_change_irqtype(HEADSET,IRQF_TRIGGER_FALLING);//
-                               disable_irq(headset_info->irq[HOOK]);
-                       }
-                       break;                  
-               default:
-                       DBG("---- ERROR: on headset headset_in_type error -----\n");
-                       break;                  
+                       }       
+                       headset_info->cur_headset_status = ~(BIT_HEADSET|BIT_HEADSET_NO_MIC);
+                       headset_change_irqtype(HEADSET,IRQF_TRIGGER_RISING);//
+               }
+               break;
+       case HEADSET_IN_LOW:
+               if(level == 0)
+               {//in--High level
+                       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]);
+               }
+               else if(level > 0)
+               {//out--High level
+                       DBG("---HEADSET_IN_LOW headset out LOW ---\n");
+                       headset_info->cur_headset_status = ~(BIT_HEADSET|BIT_HEADSET_NO_MIC);
+                       headset_change_irqtype(HEADSET,IRQF_TRIGGER_FALLING);//
+                       disable_irq(headset_info->irq[HOOK]);
+               }
+               break;                  
+       default:
+               DBG("---- ERROR: on headset headset_in_type error -----\n");
+               break;                  
        }
        
-                                       
        switch_set_state(&headset_info->sdev, headset_info->cur_headset_status);        
-       DBG("Headset_dev.cur_headset_status = %d\n",headset_info->cur_headset_status);
-
+       DBG("headset_info->cur_headset_status = %d\n",headset_info->cur_headset_status);
+RE_ERROR:
        mutex_unlock(&headset_info->mutex_lock[HEADSET]);       
 }
 
@@ -219,14 +231,13 @@ static void Hook_work(struct work_struct *work)
        int i,level = 0;
        struct rk_headset_pdata *pdata = headset_info->pdata;
        static unsigned int old_status = 0;
-       
+
        DBG("---Hook_work---\n");
        mutex_lock(&headset_info->mutex_lock[HOOK]);
-       if(headset_info->headset_status == 0)
+       if(headset_info->headset_status == HEADSET_OUT)
        {
-               printk("Headset is out\n");
-               mutex_unlock(&headset_info->mutex_lock[HOOK]);
-               return;
+               DBG("Headset is out\n");
+               goto RE_ERROR;
        }       
        
        for(i=0; i<3; i++)
@@ -244,39 +255,92 @@ static void Hook_work(struct work_struct *work)
        if(level < 0)
        {
                printk("%s:get pin level  err!\n",__FUNCTION__);
-               return;
+               goto RE_ERROR;
        }
        
        old_status = headset_info->hook_status;
        if(level == 0)
-               headset_info->hook_status = 1;
+               headset_info->hook_status = HOOK_UP;
        else if(level > 0)      
-               headset_info->hook_status = 0;
+               headset_info->hook_status = HOOK_DOWN;
        if(old_status == headset_info->hook_status)
        {
-               printk("old_status == headset_info->hook_status\n");
-               mutex_unlock(&headset_info->mutex_lock[HOOK]);
-               return;
+               DBG("old_status == headset_info->hook_status\n");
+               goto RE_ERROR;
        }       
        
        if(level == 0)
        {
                DBG("---HOOK Down ---\n");
                headset_change_irqtype(HOOK,IRQF_TRIGGER_RISING);//
-               input_report_key(headset_info->input_dev,KEY_MEDIA,headset_info->hook_status);
-               input_sync(headset_info->input_dev);    
+               input_report_key(headset_info->input_dev,pdata->hook_key_code,headset_info->hook_status);
+               input_sync(headset_info->input_dev);
        }
        else if(level > 0)
        {
                DBG("---HOOK Up ---\n");                
                headset_change_irqtype(HOOK,IRQF_TRIGGER_FALLING);//
-               input_report_key(headset_info->input_dev,KEY_MEDIA,headset_info->hook_status);
-               input_sync(headset_info->input_dev);    
+               input_report_key(headset_info->input_dev,pdata->hook_key_code,headset_info->hook_status);
+               input_sync(headset_info->input_dev);
        }
-
+RE_ERROR:
        mutex_unlock(&headset_info->mutex_lock[HOOK]);
 }
 
+static void headset_timer_callback(unsigned long arg)
+{
+       struct headset_priv *headset = (struct headset_priv *)(arg);
+       struct rk_headset_pdata *pdata = headset->pdata;
+       int i,level = 0;
+       
+       DBG("headset_timer_callback\n");        
+
+       if(headset->headset_status == HEADSET_OUT)
+       {
+               DBG("Headset is out\n");
+               goto out;
+       }
+       if(wm8994_set_status() < 0)
+       {
+               DBG("wm8994 is not set on heatset channel\n");
+               headset_info->headset_timer.expires = jiffies + 500;
+               add_timer(&headset_info->headset_timer);        
+               goto out;
+       }
+       
+       for(i=0; i<3; i++)
+       {
+               level = gpio_get_value(pdata->Hook_gpio);
+               if(level < 0)
+               {
+                       printk("%s:get pin level again,pin=%d,i=%d\n",__FUNCTION__,pdata->Hook_gpio,i);
+                       msleep(1);
+                       continue;
+               }
+               else
+               break;
+       }
+       if(level < 0)
+       {
+               printk("%s:get pin level  err!\n",__FUNCTION__);
+               goto out;
+       }
+
+//ÑÓ³ÙÒ»¶Îʱ¼ä¶ú»ú»¹ÊÇ°´ÏµĻ°£¬ÄÇôӦ¸ÃÊÇÎÞ°´¼ü¶ú»ú
+       if(level == 0)
+               headset->isMic= 0;//No microphone
+       else if(level > 0)      
+       {       
+               headset->isMic = 1;//have mic
+               DBG("enable_irq\n");    
+               enable_irq(headset_info->irq[HOOK]);
+               headset->isHook_irq = enable;
+       }       
+       DBG("headset->isMic = %d\n",headset->isMic);
+out:
+       return;
+}
+
 static ssize_t h2w_print_name(struct switch_dev *sdev, char *buf)
 {
        return sprintf(buf, "Headset\n");
@@ -319,8 +383,9 @@ static int rockchip_headsetobserve_probe(struct platform_device *pdev)
        }       
        headset->pdata = pdev->dev.platform_data;
        pdata = headset->pdata;
-       headset->headset_status = 0;
-       headset->hook_status = 0;
+       headset->headset_status = HEADSET_OUT;
+       headset->hook_status = HOOK_UP;
+       headset->isHook_irq = disable;
        headset->cur_headset_status = 0;
        headset->sdev.name = "h2w";
        headset->sdev.print_name = h2w_print_name;
@@ -333,6 +398,15 @@ static int rockchip_headsetobserve_probe(struct platform_device *pdev)
        
        INIT_DELAYED_WORK(&headset->h_delayed_work[HEADSET], headsetobserve_work);
        INIT_DELAYED_WORK(&headset->h_delayed_work[HOOK], Hook_work);
+
+//     init_timer(&headset->headset_timer);
+//     headset->headset_timer.function = headset_timer_callback;
+//     headset->headset_timer.data = (unsigned long)headset;
+//     headset->headset_timer.expires = jiffies + 3000;
+       headset->isMic = 0;
+       setup_timer(&headset->headset_timer, headset_timer_callback, (unsigned long)headset);
+//     headset->headset_timer.expires = jiffies + 1000;
+//     add_timer(&headset->headset_timer);     
 //------------------------------------------------------------------
        ret = gpio_request(pdata->Headset_gpio, NULL);
        if (ret) 
@@ -361,8 +435,7 @@ static int rockchip_headsetobserve_probe(struct platform_device *pdev)
        if (ret) 
                goto failed_free;
        disable_irq(headset->irq[HOOK]);
-//------------------------------------------------------------------   
-       
+//------------------------------------------------------------------           
        // Create and register the input driver. 
        headset->input_dev = input_allocate_device();
        if (!headset->input_dev) {
@@ -392,7 +465,7 @@ static int rockchip_headsetobserve_probe(struct platform_device *pdev)
        
 //     set_bit(KEY_MEDIA, headset->input_dev->keybit);
 //     clear_bit(0, headset->input_dev->keybit);
-       input_set_capability(headset->input_dev, EV_KEY, KEY_MEDIA);
+       input_set_capability(headset->input_dev, EV_KEY, pdata->hook_key_code);
 //     input_set_capability(headset->input_dev, EV_SW, SW_HEADPHONE_INSERT);
 //     input_set_capability(headset->input_dev, EV_KEY, KEY_END);
 
index c1f7a91862ec55cb0e3d976605e0e201f72796fa..51e2655d3fbc22c763252578b7eaf91c75a47e99 100755 (executable)
@@ -7,7 +7,7 @@
 
 struct rk_headset_pdata{
        unsigned int Hook_gpio;//Detection Headset--Must be set
-
+       int     hook_key_code;
        unsigned int Headset_gpio;//Detection Headset--Must be set
        unsigned int headset_in_type;// Headphones into the state level--Must be set    
 };
index d7cb1914566c231cc4f37b954a96d1359e64db59..92a32e1ca1617f24fb2ca57c330ac2eb62b3c719 100755 (executable)
@@ -136,6 +136,7 @@ unsigned short BT_vol_table[16]             ={0x01DB,0x01DC,0x01DD,0x01DE,0x01DF,0x01E0,
 /* codec private data */
 struct wm8994_priv {
        struct mutex io_lock;
+       struct mutex route_lock;
        unsigned int sysclk;
        struct snd_soc_codec codec;
        struct snd_kcontrol *kcontrol;//The current working path
@@ -198,6 +199,31 @@ int reg_recv_data(struct i2c_client *client, unsigned short *reg, unsigned short
        return ret;
 }
 
+int wm8994_set_status(void)
+{
+       struct wm8994_priv *wm8994 = wm8994_codec->private_data;        
+       int ret = 1;
+       mutex_lock(&wm8994->route_lock);
+       
+       switch(wm8994_current_mode)
+       {
+       case wm8994_AP_to_headset:
+       case wm8994_recorder_and_AP_to_headset:
+       case wm8994_handsetMIC_to_baseband_to_headset:
+       case wm8994_handsetMIC_to_baseband_to_headset_and_record:
+               ret = 1;
+               break;
+       default:
+               ret = -1;
+               break;
+       }
+
+       mutex_unlock(&wm8994->route_lock);      
+       return ret;
+}
+EXPORT_SYMBOL_GPL(wm8994_set_status);
+
+
 static int wm8994_read(unsigned short reg,unsigned short *value)
 {
        struct wm8994_priv *wm8994 = wm8994_codec->private_data;
@@ -937,10 +963,6 @@ void AP_to_speakers_and_headset(void)
        msleep(WM8994_DELAY);
 //clk
 //     wm8994_write(0x701, 0x0000);//MCLK2
-       wm8994_write(0x208, 0x0008); //DSP_FS1CLK_ENA=1, DSP_FSINTCLK_ENA=1
-       wm8994_write(0x208, 0x000A); //DSP_FS1CLK_ENA=1, DSP_FSINTCLK_ENA=1
-       wm8994_write(0x210, 0x0083); // SR=48KHz
-       wm8994_write(0x300, 0xC010); // i2s 16 bits
        if(wm8994_sysclk_config() == wm8994_SYSCLK_3072M)
        {
                wm8994_write(0x220, 0x0000); 
@@ -948,9 +970,17 @@ void AP_to_speakers_and_headset(void)
                wm8994_write(0x222, 0); 
                wm8994_write(0x223, 0x0400);            
                wm8994_write(0x220, 0x0004); 
+               msleep(10);
                wm8994_write(0x220, 0x0005);                    
-               wm8994_write(0x200, 0x0011); // sysclk = MCLK1
+               msleep(5);
+               wm8994_write(0x200, 0x0010); // sysclk = MCLK1
        }
+       wm8994_write(0x208, 0x0008); //DSP_FS1CLK_ENA=1, DSP_FSINTCLK_ENA=1
+       wm8994_write(0x208, 0x000A); //DSP_FS1CLK_ENA=1, DSP_FSINTCLK_ENA=1
+       wm8994_write(0x210, 0x0083); // SR=48KHz
+       wm8994_write(0x300, 0xC010); // i2s 16 bits     
+       if(wm8994_sysclk_config() == wm8994_SYSCLK_3072M)
+               wm8994_write(0x200, 0x0011); // sysclk = MCLK1
        else 
                wm8994_write(0x200, 0x0001); // sysclk = MCLK1
 //     wm8994_write(0x200, 0x0009); // sysclk = MCLK2
@@ -991,14 +1021,10 @@ void recorder_and_AP_to_headset(void)
        wm8994_reset();
        msleep(WM8994_DELAY);
 
-       wm8994_write(0x01,  0x0023);
+       wm8994_write(0x01,  0x0003);
        wm8994_write(0x200, 0x0000);
        msleep(WM8994_DELAY);
 //clk
-       wm8994_write(0x208, 0x0008); //DSP_FS1CLK_ENA=1, DSP_FSINTCLK_ENA=1
-       wm8994_write(0x208, 0x000A); //DSP_FS1CLK_ENA=1, DSP_FSINTCLK_ENA=1
-       wm8994_write(0x210, 0x0083); // SR=48KHz
-       wm8994_write(0x300, 0xC010); // i2s 16 bits
        if(wm8994_sysclk_config() == wm8994_SYSCLK_3072M)
        {
                wm8994_write(0x220, 0x0000); 
@@ -1006,11 +1032,20 @@ void recorder_and_AP_to_headset(void)
                wm8994_write(0x222, 0); 
                wm8994_write(0x223, 0x0400);            
                wm8994_write(0x220, 0x0004); 
+               msleep(10);
                wm8994_write(0x220, 0x0005);                    
-               wm8994_write(0x200, 0x0011); // sysclk = MCLK1
+               msleep(5);
+               wm8994_write(0x200, 0x0010); // sysclk = MCLK1
        }
+       wm8994_write(0x208, 0x0008); //DSP_FS1CLK_ENA=1, DSP_FSINTCLK_ENA=1
+       wm8994_write(0x208, 0x000A); //DSP_FS1CLK_ENA=1, DSP_FSINTCLK_ENA=1
+       wm8994_write(0x210, 0x0083); // SR=48KHz
+       wm8994_write(0x300, 0xC050); // i2s 16 bits     
+       msleep(10);
+       if(wm8994_sysclk_config() == wm8994_SYSCLK_3072M)
+               wm8994_write(0x200, 0x0011); // sysclk = MCLK1
        else 
-               wm8994_write(0x200, 0x0001); // sysclk = MCLK1
+               wm8994_write(0x200, 0x0001); // sysclk = MCLK1  
 //recorder
        wm8994_write(0x28,  0x0003); // IN1RP_TO_IN1R=1, IN1RN_TO_IN1R=1
        wm8994_write(0x606, 0x0002); // ADC1L_TO_AIF1ADC1L=1
@@ -1058,11 +1093,6 @@ void recorder_and_AP_to_speakers(void)
        msleep(WM8994_DELAY);
 //clk
 //     wm8994_write(0x701, 0x0000);//MCLK2
-       wm8994_write(0x208, 0x0008); //DSP_FS1CLK_ENA=1, DSP_FSINTCLK_ENA=1
-       wm8994_write(0x208, 0x000A); //DSP_FS1CLK_ENA=1, DSP_FSINTCLK_ENA=1
-       wm8994_write(0x210, 0x0083); // SR=48KHz
-       wm8994_write(0x300, 0xC010); // i2s 16 bits
-
        if(wm8994_sysclk_config() == wm8994_SYSCLK_3072M)
        {
                wm8994_write(0x220, 0x0000); 
@@ -1070,9 +1100,17 @@ void recorder_and_AP_to_speakers(void)
                wm8994_write(0x222, 0); 
                wm8994_write(0x223, 0x0400);            
                wm8994_write(0x220, 0x0004); 
+               msleep(10);
                wm8994_write(0x220, 0x0005);                    
-               wm8994_write(0x200, 0x0011); // sysclk = MCLK1
+               msleep(5);
+               wm8994_write(0x200, 0x0010); // sysclk = MCLK1
        }
+       wm8994_write(0x208, 0x0008); //DSP_FS1CLK_ENA=1, DSP_FSINTCLK_ENA=1
+       wm8994_write(0x208, 0x000A); //DSP_FS1CLK_ENA=1, DSP_FSINTCLK_ENA=1
+       wm8994_write(0x210, 0x0083); // SR=48KHz
+       wm8994_write(0x300, 0xC010); // i2s 16 bits     
+       if(wm8994_sysclk_config() == wm8994_SYSCLK_3072M)
+               wm8994_write(0x200, 0x0011); // sysclk = MCLK1
        else 
                wm8994_write(0x200, 0x0001); // sysclk = MCLK1
        
@@ -1128,10 +1166,6 @@ void handsetMIC_to_baseband_to_headset(void)
        wm8994_write(0x200, 0x0000);
        msleep(WM8994_DELAY);
 //clk
-       wm8994_write(0x208, 0x0008); //DSP_FS1CLK_ENA=1, DSP_FSINTCLK_ENA=1
-       wm8994_write(0x208, 0x000A); //DSP_FS1CLK_ENA=1, DSP_FSINTCLK_ENA=1
-       wm8994_write(0x210, 0x0083); // SR=48KHz
-       wm8994_write(0x300, 0xC010); // i2s 16 bits
        if(wm8994_sysclk_config() == wm8994_SYSCLK_3072M)
        {
                wm8994_write(0x220, 0x0000); 
@@ -1139,9 +1173,17 @@ void handsetMIC_to_baseband_to_headset(void)
                wm8994_write(0x222, 0); 
                wm8994_write(0x223, 0x0400);            
                wm8994_write(0x220, 0x0004); 
+               msleep(10);
                wm8994_write(0x220, 0x0005);                    
-               wm8994_write(0x200, 0x0011); // sysclk = MCLK1
+               msleep(5);
+               wm8994_write(0x200, 0x0010); // sysclk = MCLK1
        }
+       wm8994_write(0x208, 0x0008); //DSP_FS1CLK_ENA=1, DSP_FSINTCLK_ENA=1
+       wm8994_write(0x208, 0x000A); //DSP_FS1CLK_ENA=1, DSP_FSINTCLK_ENA=1
+       wm8994_write(0x210, 0x0083); // SR=48KHz
+       wm8994_write(0x300, 0xC010); // i2s 16 bits     
+       if(wm8994_sysclk_config() == wm8994_SYSCLK_3072M)
+               wm8994_write(0x200, 0x0011); // sysclk = MCLK1
        else 
                wm8994_write(0x200, 0x0001); // sysclk = MCLK1
 //path
@@ -1323,10 +1365,6 @@ void mainMIC_to_baseband_to_earpiece(void)
        wm8994_write(0x200, 0x0000);
        msleep(WM8994_DELAY);
 //clk
-       wm8994_write(0x208, 0x0008); //DSP_FS1CLK_ENA=1, DSP_FSINTCLK_ENA=1
-       wm8994_write(0x208, 0x000A); //DSP_FS1CLK_ENA=1, DSP_FSINTCLK_ENA=1
-       wm8994_write(0x210, 0x0083); // SR=48KHz
-       wm8994_write(0x300, 0x4010); // i2s 16 bits
        if(wm8994_sysclk_config() == wm8994_SYSCLK_3072M)
        {
                wm8994_write(0x220, 0x0000); 
@@ -1334,9 +1372,17 @@ void mainMIC_to_baseband_to_earpiece(void)
                wm8994_write(0x222, 0); 
                wm8994_write(0x223, 0x0400);            
                wm8994_write(0x220, 0x0004); 
+               msleep(10);
                wm8994_write(0x220, 0x0005);                    
-               wm8994_write(0x200, 0x0011); // sysclk = MCLK1
+               msleep(5);
+               wm8994_write(0x200, 0x0010); // sysclk = MCLK1
        }
+       wm8994_write(0x208, 0x0008); //DSP_FS1CLK_ENA=1, DSP_FSINTCLK_ENA=1
+       wm8994_write(0x208, 0x000A); //DSP_FS1CLK_ENA=1, DSP_FSINTCLK_ENA=1
+       wm8994_write(0x210, 0x0083); // SR=48KHz
+       wm8994_write(0x300, 0xC010); // i2s 16 bits     
+       if(wm8994_sysclk_config() == wm8994_SYSCLK_3072M)
+               wm8994_write(0x200, 0x0011); // sysclk = MCLK1
        else 
                wm8994_write(0x200, 0x0001); // sysclk = MCLK1
 //path
@@ -1418,10 +1464,6 @@ void mainMIC_to_baseband_to_speakers(void)
        wm8994_write(0x200, 0x0000);
        msleep(WM8994_DELAY);
 //clk
-       wm8994_write(0x208, 0x0008); //DSP_FS1CLK_ENA=1, DSP_FSINTCLK_ENA=1
-       wm8994_write(0x208, 0x000A); //DSP_FS1CLK_ENA=1, DSP_FSINTCLK_ENA=1
-       wm8994_write(0x210, 0x0083); // SR=48KHz
-       wm8994_write(0x300, 0xC010); // i2s 16 bits
        if(wm8994_sysclk_config() == wm8994_SYSCLK_3072M)
        {
                wm8994_write(0x220, 0x0000); 
@@ -1429,9 +1471,17 @@ void mainMIC_to_baseband_to_speakers(void)
                wm8994_write(0x222, 0); 
                wm8994_write(0x223, 0x0400);            
                wm8994_write(0x220, 0x0004); 
+               msleep(10);
                wm8994_write(0x220, 0x0005);                    
-               wm8994_write(0x200, 0x0011); // sysclk = MCLK1
+               msleep(5);
+               wm8994_write(0x200, 0x0010); // sysclk = MCLK1
        }
+       wm8994_write(0x208, 0x0008); //DSP_FS1CLK_ENA=1, DSP_FSINTCLK_ENA=1
+       wm8994_write(0x208, 0x000A); //DSP_FS1CLK_ENA=1, DSP_FSINTCLK_ENA=1
+       wm8994_write(0x210, 0x0083); // SR=48KHz
+       wm8994_write(0x300, 0xC010); // i2s 16 bits     
+       if(wm8994_sysclk_config() == wm8994_SYSCLK_3072M)
+               wm8994_write(0x200, 0x0011); // sysclk = MCLK1
        else 
                wm8994_write(0x200, 0x0001); // sysclk = MCLK1
 //path
@@ -1523,10 +1573,6 @@ void BT_baseband(void)
        msleep(WM8994_DELAY);
 //CLK  
        //AIF1CLK
-       wm8994_write(0x208, 0x0008);
-       wm8994_write(0x208, 0x000A);
-       wm8994_write(0x210, 0x0083);    // SMbus_16inx_16dat     Write  0x34      * SR=48KHz
-       wm8994_write(0x300, 0xC010);    //DSP/PCM; 16bits; ADC L channel = R channel;MODE A
        if(wm8994_sysclk_config() == wm8994_SYSCLK_3072M)
        {
                wm8994_write(0x220, 0x0000); 
@@ -1534,9 +1580,17 @@ void BT_baseband(void)
                wm8994_write(0x222, 0); 
                wm8994_write(0x223, 0x0400);            
                wm8994_write(0x220, 0x0004); 
+               msleep(10);
                wm8994_write(0x220, 0x0005);                    
-               wm8994_write(0x200, 0x0011); // sysclk = MCLK1
+               msleep(5);
+               wm8994_write(0x200, 0x0010); // sysclk = MCLK1
        }
+       wm8994_write(0x208, 0x0008); //DSP_FS1CLK_ENA=1, DSP_FSINTCLK_ENA=1
+       wm8994_write(0x208, 0x000A); //DSP_FS1CLK_ENA=1, DSP_FSINTCLK_ENA=1
+       wm8994_write(0x210, 0x0083); // SR=48KHz
+       wm8994_write(0x300, 0xC010); // i2s 16 bits     
+       if(wm8994_sysclk_config() == wm8994_SYSCLK_3072M)
+               wm8994_write(0x200, 0x0011); // sysclk = MCLK1
        else 
                wm8994_write(0x200, 0x0001); // sysclk = MCLK1
        //AIF2CLK use FLL2
@@ -1564,15 +1618,14 @@ void BT_baseband(void)
        wm8994_write(0x315, 0x0080);
        wm8994_write(0x310, 0x0118);    //DSP/PCM; 16bits; ADC L channel = R channel;MODE A
        wm8994_write(0x204, 0x0019);    // SMbus_16inx_16dat     Write  0x34      * AIF2 Clocking (1)(204H): 0011  AIF2CLK_SRC=10, AIF2CLK_INV=0, AIF2CLK_DIV=0, AIF2CLK_ENA=1
-
 /*     
        wm8994_write(0x310, 0x0118); 
        wm8994_write(0x204, 0x0001);    
        wm8994_write(0x208, 0x000F);    
        wm8994_write(0x211, 0x0009);    
        wm8994_write(0x312, 0x7000);    
-       wm8994_write(0x313, 0x00F0); */
-       
+       wm8994_write(0x313, 0x00F0); 
+*/     
 //GPIO
        wm8994_write(0x702, 0x2100);
        wm8994_write(0x703, 0x2100);
@@ -2548,15 +2601,15 @@ int snd_soc_put_route(struct snd_kcontrol *kcontrol,
 {
        struct wm8994_priv *wm8994 = wm8994_codec->private_data;
        char route = kcontrol->private_value & 0xff;
-
+       mutex_lock(&wm8994->route_lock);
        wm8994->kcontrol = kcontrol;//save rount
        
-       if(wm8994->First_Poweron == 1 &&
-               route == SPEAKER_NORMAL)
+       if(wm8994->First_Poweron == 1 && route == SPEAKER_NORMAL )
        {//First start & Poweron  mast disable wm8994
                PA_ctrl(GPIO_LOW);
                wm8994_write(0,0);
-               return 0;
+               msleep(50);
+               goto out;
        }       
        //before set the route -- disable PA
        switch(route)
@@ -2631,7 +2684,7 @@ int snd_soc_put_route(struct snd_kcontrol *kcontrol,
                        break;                                  
                default:
                        printk("wm8994 error route!!!\n");
-                       return 0;
+                       goto out;
        }
        //after set the route -- enable PA
        switch(route)
@@ -2644,10 +2697,12 @@ int snd_soc_put_route(struct snd_kcontrol *kcontrol,
                case BLUETOOTH_SCO_NORMAL:              
                        break;
                default:
+                       msleep(50);
                        PA_ctrl(GPIO_HIGH);             
                        break;
        }       
-
+out:   
+       mutex_unlock(&wm8994->route_lock);      
        return 0;
 }
 
@@ -2768,7 +2823,7 @@ static int wm8994_trigger(struct snd_pcm_substream *substream,
        struct snd_soc_codec *codec = dai->codec;
        struct wm8994_priv *wm8994 = codec->private_data;
        
-       if(wm8994_current_mode > wm8994_handsetMIC_to_baseband_to_headset && wm8994_current_mode != null)
+       if(wm8994_current_mode >= wm8994_handsetMIC_to_baseband_to_headset && wm8994_current_mode != null)
                return 0;
 //     DBG("%s::%d status = %d substream->stream '%s'\n",__FUNCTION__,__LINE__,
 //         cmd, substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? "PLAYBACK":"CAPTURE");
@@ -2798,13 +2853,16 @@ static int wm8994_trigger(struct snd_pcm_substream *substream,
                !wm8994->capture_active )
        {//suspend
                DBG("It's going to power down wm8994\n");
+               cancel_delayed_work_sync(&wm8994->wm8994_delayed_work);         
                wm8994->work_type = SNDRV_PCM_TRIGGER_STOP;
-               schedule_delayed_work(&wm8994->wm8994_delayed_work, msecs_to_jiffies(1000));
+               schedule_delayed_work(&wm8994->wm8994_delayed_work, msecs_to_jiffies(2000));
        } 
        else if (wm8994->playback_active 
                        || wm8994->capture_active) 
        {//resume
-               DBG("Power up wm8994\n");               
+               DBG("Power up wm8994\n");       
+               if(wm8994->work_type == SNDRV_PCM_TRIGGER_STOP)
+                       cancel_delayed_work_sync(&wm8994->wm8994_delayed_work);
                wm8994->work_type = SNDRV_PCM_TRIGGER_START;
                schedule_delayed_work(&wm8994->wm8994_delayed_work, msecs_to_jiffies(0));               
        }
@@ -2816,34 +2874,47 @@ 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\n",__FUNCTION__,__LINE__);
+//     DBG("Enter %s---%d = %d\n",__FUNCTION__,__LINE__,wm8994_current_mode);
 
        switch(wm8994->work_type)
        {
        case SNDRV_PCM_TRIGGER_STOP:
+               if(wm8994_current_mode > wm8994_FM_to_speakers_and_record)
+                       return; 
        //      DBG("wm8994 shutdown\n");
+               mutex_lock(&wm8994->route_lock);
                PA_ctrl(GPIO_LOW);
-               wm8994_write(0,0);
                msleep(50);
-               wm8994_write(0x01, 0x0003);
+               wm8994_write(0,0);
                msleep(50);
                wm8994_write(0x01, 0x0023);     
-               wm8994_current_mode = null;//Automatically re-set the wake-up time              
+               wm8994_current_mode = null;//Automatically re-set the wake-up time      
+               mutex_unlock(&wm8994->route_lock);      
                break;
        case SNDRV_PCM_TRIGGER_START:
                if(wm8994->First_Poweron == 1)
                {
                        DBG("wm8994 First_Poweron shutup\n");
                        wm8994->First_Poweron = 0;
+                       if(wm8994->kcontrol->private_value != SPEAKER_NORMAL)
+                       {
+                       //      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);
                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)
@@ -2923,12 +2994,10 @@ static int wm8994_resume(struct platform_device *pdev)
        struct snd_soc_device *socdev = platform_get_drvdata(pdev);
        struct snd_soc_codec *codec = socdev->card->codec;
        struct wm8994_priv *wm8994 = codec->private_data;
-       struct wm8994_pdata *pdata = wm8994->pdata;
+//     struct wm8994_pdata *pdata = wm8994->pdata;
        
        DBG("%s----%d\n",__FUNCTION__,__LINE__);
-       gpio_request(pdata->Power_EN_Pin, NULL);
-       gpio_direction_output(pdata->Power_EN_Pin,GPIO_HIGH);
-       gpio_free(pdata->Power_EN_Pin);
+
 
        wm8994->work_type = SNDRV_PCM_TRIGGER_RESUME;
        schedule_delayed_work(&wm8994->wm8994_delayed_work, msecs_to_jiffies(0));       
@@ -2945,6 +3014,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;
        
        cookie_pot = (char *)vmalloc( len );
        if (!cookie_pot) 
@@ -3080,7 +3151,7 @@ static ssize_t wm8994_proc_write(struct file *file, const char __user *buffer,
 
                                break;                          
                }               
-               break;
+               break;  
        default:
                DBG("Help for wm8994_ts .\n-->The Cmd list: \n");
                DBG("-->'d&&D' Open or close the debug\n");
@@ -3131,6 +3202,8 @@ static int wm8994_probe(struct platform_device *pdev)
        struct wm8994_priv *wm8994;
        struct wm8994_pdata *pdata;
        int ret = 0;
+       
+
 #ifdef WM8994_PROC
        wm8994_proc_init();
 #endif
@@ -3144,6 +3217,10 @@ static int wm8994_probe(struct platform_device *pdev)
        codec = wm8994_codec;
        wm8994 = codec->private_data;
        pdata = wm8994->pdata;
+       //disable power_EN
+       gpio_request(pdata->Power_EN_Pin, NULL);                         
+       gpio_direction_output(pdata->Power_EN_Pin,GPIO_LOW);            
+       gpio_free(pdata->Power_EN_Pin); 
        
        /* register pcms */
        ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
@@ -3160,15 +3237,13 @@ static int wm8994_probe(struct platform_device *pdev)
                dev_err(codec->dev, "failed to register card: %d\n", ret);
                goto card_err;
        }
-       
+
+       PA_ctrl(GPIO_LOW);
        //enable power_EN
+       msleep(50);
        gpio_request(pdata->Power_EN_Pin, NULL);                         
        gpio_direction_output(pdata->Power_EN_Pin,GPIO_HIGH);           
-       gpio_free(pdata->Power_EN_Pin);
-
-       gpio_request(pdata->PA_control_pin, NULL);              //AUDIO_PA_ON    
-       gpio_direction_output(pdata->PA_control_pin,GPIO_LOW);          
-       gpio_free(pdata->PA_control_pin);               
+       gpio_free(pdata->Power_EN_Pin); 
 
        return ret;
 
@@ -3300,7 +3375,7 @@ static int wm8994_i2c_probe(struct i2c_client *i2c,
        wm8994->BT_call_vol = BT_call_maxvol;
        INIT_DELAYED_WORK(&wm8994->wm8994_delayed_work, wm8994_work_fun);
        mutex_init(&wm8994->io_lock);   
-       
+       mutex_init(&wm8994->route_lock);
        return wm8994_register(wm8994, SND_SOC_I2C);
 }
 
@@ -3332,8 +3407,7 @@ static void wm8994_i2c_shutdown(struct i2c_client *client)
        struct wm8994_pdata *pdata = wm8994->pdata;
        DBG("%s----%d\n",__FUNCTION__,__LINE__);
        //disable PA
-       PA_ctrl(GPIO_LOW);
-       wm8994_write(0x00, 0x00);       
+       PA_ctrl(GPIO_LOW);      
        gpio_request(pdata->Power_EN_Pin, NULL);
        gpio_direction_output(pdata->Power_EN_Pin,GPIO_LOW);
        gpio_free(pdata->Power_EN_Pin);