phonepad: update the headset driver from huawei project, make some code in
author宋秀杰 <sxj@rock-chips.com>
Tue, 4 Sep 2012 12:12:52 +0000 (20:12 +0800)
committer宋秀杰 <sxj@rock-chips.com>
Tue, 4 Sep 2012 12:12:52 +0000 (20:12 +0800)
rt3261.c depend on CONFIG_SND_SOC_RT5623.

drivers/headset_observe/rk_headset_irq_hook_adc.c
sound/soc/codecs/rt3261.c
sound/soc/codecs/rt3261.h
sound/soc/rk29/rk29_rt3261.c

index 53d4a170d60c691125a6e6b9d68c0720a0d381c6..e954e264d56cbd98f42e71f9ea860b1a5941ff28 100755 (executable)
 #define DBG(x...) do { } while (0)
 #endif
 
-#define HOOK_ADC_SAMPLE_TIME   700
-#define HOOK_LEVEL_HIGH                409             //1V*1024/2.5
+#define HOOK_ADC_SAMPLE_TIME   100
+#define HOOK_LEVEL_HIGH                600             //1V*1024/2.5
 #define HOOK_LEVEL_LOW                 204             //0.5V*1024/2.5
+#define HOOK_DEFAULT_VAL               1024    
 
 #define BIT_HEADSET             (1 << 0)
 #define BIT_HEADSET_NO_MIC      (1 << 1)
 
 #define HEADSET_IN 1
 #define HEADSET_OUT 0
-#define HOOK_DOWN 0
-#define HOOK_UP 1
+#define HOOK_DOWN 1
+#define HOOK_UP 0
 #define enable 1
 #define disable 0
 
 #define HEADSET_TIMER 1
 #define HOOK_TIMER 2
 
+#define WAIT 2
+#define BUSY 1
+#define IDLE 0
+
 #ifdef CONFIG_SND_SOC_WM8994
-extern int wm8994_set_status(void);
+extern int wm8994_headset_mic_detect(bool headset_status);
+#endif
+
+#ifdef CONFIG_SND_SOC_RT3261
+extern int rt3261_headset_mic_detect(int jack_insert);
 #endif
 
 /* headset private data */
@@ -79,8 +88,8 @@ struct headset_priv {
        struct rk_headset_pdata *pdata;
        unsigned int headset_status:1;
        unsigned int hook_status:1;
-       unsigned int isMic:1;
-       unsigned int isHook_irq:1;
+       int isMic;
+       unsigned int heatset_irq_working;// headset interrupt working will not check hook key   
        int cur_headset_status; 
        
        unsigned int irq[2];
@@ -92,7 +101,7 @@ struct headset_priv {
        unsigned char *keycodes;
        struct adc_client *client;
        struct timer_list hook_timer;
-       int adc_callback_status;
+       unsigned int hook_time;//ms
 };
 static struct headset_priv *headset_info;
 
@@ -102,45 +111,17 @@ int Headset_isMic(void)
 }
 EXPORT_SYMBOL_GPL(Headset_isMic);
 
+//1
 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(50));
-       return IRQ_HANDLED;
-}
-
-static int headset_change_irqtype(int type,unsigned int irq_type)
-{
-       int ret = 0;
-       DBG("--------%s----------\n",__FUNCTION__);
-       free_irq(headset_info->irq[type],NULL);
-       
-       switch(type)
-       {
-               case HEADSET:
-                       ret = request_irq(headset_info->irq[type], headset_interrupt, irq_type, "headset_hook", NULL);
-                       break;
-               default:
-                       ret = -1;
-                       break;
-       }
-
-       if (ret<0) 
-       {
-               DBG("headset_change_irqtype: request irq failed\n");
-        return ret;
-       }
-       return ret;
-}
-
-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");
-       mutex_lock(&headset_info->mutex_lock[HEADSET]);
-
+       int i,level = 0;        
+       int adc_value = 0;
+       if(headset_info->heatset_irq_working == BUSY || headset_info->heatset_irq_working == WAIT)
+               return IRQ_HANDLED;
+       DBG("In the headset_interrupt for read headset level\n");               
+       headset_info->heatset_irq_working = BUSY;
        for(i=0; i<3; i++)
        {
                level = gpio_get_value(pdata->Headset_gpio);
@@ -156,7 +137,7 @@ static void headsetobserve_work(struct work_struct *work)
        if(level < 0)
        {
                printk("%s:get pin level  err!\n",__FUNCTION__);
-               goto RE_ERROR;
+               goto out;
        }
 
        old_status = headset_info->headset_status;
@@ -180,201 +161,253 @@ static void headsetobserve_work(struct work_struct *work)
        }
        if(old_status == headset_info->headset_status)
        {
-               DBG("old_status == headset_info->headset_status\n");
-               goto RE_ERROR;
+               DBG("Read Headset IO level old status == now status\n");
+               goto out;
        }
 
-       switch(pdata->headset_in_type)
+       DBG("(headset in is %s)headset status is %s\n",
+               pdata->headset_in_type?"high level":"low level",
+               headset_info->headset_status?"in":"out");
+       if(headset_info->headset_status == HEADSET_IN)
        {
-       case HEADSET_IN_HIGH:
-               if(level > 0)
-               {//in--High level
-                       DBG("--- HEADSET_IN_HIGH headset in HIGH---\n");
-                       headset_info->cur_headset_status = BIT_HEADSET_NO_MIC;
-                       headset_change_irqtype(HEADSET,IRQF_TRIGGER_FALLING);//
-
-                       del_timer(&headset_info->headset_timer);//Start the timer, wait for switch to the headphone channel
-                       //      headset_info->headset_timer.expires = jiffies + 500;
-                       headset_info->headset_timer.expires = jiffies + 10;
-                       add_timer(&headset_info->headset_timer);
+               #if 0
+               while(1)
+               {
+                       if(adc_sync_read(headset_info->client) > HOOK_DEFAULT_VAL
+                        || adc_sync_read(headset_info->client) < 0)
+                       {
+                               printk("headset is showly inside\n");
+                       }
+                       else
+                               break;
+                       msleep(50);
+                       
+                       if(pdata->headset_in_type == HEADSET_IN_HIGH)
+                               old_status = headset_info->headset_status = gpio_get_value(pdata->Headset_gpio)?HEADSET_IN:HEADSET_OUT;
+                       else
+                               old_status = headset_info->headset_status = gpio_get_value(pdata->Headset_gpio)?HEADSET_OUT:HEADSET_IN;
+                       if(headset_info->headset_status == HEADSET_OUT)
+                               goto out1;
+                       msleep(5);      
                }
-               else if(level == 0)
-               {//out--Low level
-                       DBG("---HEADSET_IN_HIGH headset out HIGH---\n");        
-
-                       del_timer(&headset_info->hook_timer);   
-                       headset_info->cur_headset_status = ~(BIT_HEADSET|BIT_HEADSET_NO_MIC);
-                       headset_change_irqtype(HEADSET,IRQF_TRIGGER_RISING);//
-                       rk28_send_wakeup_key();
-                       switch_set_state(&headset_info->sdev, headset_info->cur_headset_status);        
-                       DBG("headset_info->cur_headset_status = %d\n",headset_info->cur_headset_status);                        
+               #endif
+               if(pdata->Hook_adc_chn>=0 && 3>=pdata->Hook_adc_chn)
+               {
+               // wait for find Hook key
+                       //#ifdef CONFIG_SND_SOC_RT5625
+                       CHECK_AGAIN:
+                       //headset_info->isMic = rt5625_headset_mic_detect(true);
+                       #ifdef CONFIG_SND_SOC_WM8994
+                       wm8994_headset_mic_detect(true);
+                       #endif
+                       #ifdef CONFIG_SND_SOC_RT3261
+                       rt3261_headset_mic_detect(true);
+                       #endif
+                       //mdelay(400);
+                       adc_value = adc_sync_read(headset_info->client);
+                       if(adc_value >= 0 && adc_value < HOOK_LEVEL_LOW)
+                       {
+                               headset_info->isMic= 0;//No microphone
+                               #ifdef CONFIG_SND_SOC_WM8994
+                               wm8994_headset_mic_detect(false);
+                               #endif
+                               #ifdef CONFIG_SND_SOC_RT3261
+                               rt3261_headset_mic_detect(false);
+                               #endif
+                               printk("headset->isMic = %d\n",headset_info->isMic);            
+                       }       
+                       else if(adc_value >= HOOK_LEVEL_HIGH)   
+                       {       
+                               headset_info->isMic = 1;//have mic
+                               printk("headset->isMic = %d\n",headset_info->isMic);            
+                       }
+                       if(headset_info->isMic < 0)     
+                       {
+                               printk("codec is error\n");
+                               headset_info->heatset_irq_working = WAIT;
+                               if(pdata->headset_in_type == HEADSET_IN_HIGH)
+                                       irq_set_irq_type(headset_info->irq[HEADSET],IRQF_TRIGGER_LOW|IRQF_ONESHOT);
+                               else
+                                       irq_set_irq_type(headset_info->irq[HEADSET],IRQF_TRIGGER_HIGH|IRQF_ONESHOT);
+                               schedule_delayed_work(&headset_info->h_delayed_work[HEADSET], msecs_to_jiffies(0));     
+                               return IRQ_HANDLED;
+                       }
+                       //adc_value = adc_sync_read(headset_info->client);
+                       printk("headset adc value = %d\n",adc_value);
+                       if(headset_info->isMic) {
+                               if(adc_value > HOOK_DEFAULT_VAL || adc_value < HOOK_LEVEL_HIGH)
+                                       goto CHECK_AGAIN;
+                               mod_timer(&headset_info->hook_timer, jiffies + msecs_to_jiffies(1000));
+                       }       
+                       //#endif                
+                       headset_info->cur_headset_status = headset_info->isMic ? BIT_HEADSET:BIT_HEADSET_NO_MIC;
                }
-               break;
-       case HEADSET_IN_LOW:
-               if(level == 0)
-               {//in--High level
-                       DBG("---HEADSET_IN_LOW headset in LOW ---\n");
+               else
+               {
+                       headset_info->isMic= 0;//No microphone
                        headset_info->cur_headset_status = BIT_HEADSET_NO_MIC;
-                       headset_change_irqtype(HEADSET,IRQF_TRIGGER_RISING);//
-                       
-                       del_timer(&headset_info->headset_timer);//Start the timer, wait for switch to the headphone channel
-                       //      headset_info->headset_timer.expires = jiffies + 500;
-                       headset_info->headset_timer.expires = jiffies + 10;
-                       add_timer(&headset_info->headset_timer);
-               }
-               else if(level > 0)
-               {//out--High level
-                       DBG("---HEADSET_IN_LOW headset out LOW ---\n");
-                       
-                       del_timer(&headset_info->hook_timer);                           
-                       headset_info->cur_headset_status = ~(BIT_HEADSET|BIT_HEADSET_NO_MIC);
-                       headset_change_irqtype(HEADSET,IRQF_TRIGGER_FALLING);//
-                       rk28_send_wakeup_key();
-                       switch_set_state(&headset_info->sdev, headset_info->cur_headset_status);        
-                       DBG("headset_info->cur_headset_status = %d\n",headset_info->cur_headset_status);                        
                }
-               break;                  
-       default:
-               DBG("---- ERROR: on headset headset_in_type error -----\n");
-               break;                  
+               printk("headset->isMic = %d\n",headset_info->isMic);            
+               if(pdata->headset_in_type == HEADSET_IN_HIGH)
+                       irq_set_irq_type(headset_info->irq[HEADSET],IRQF_TRIGGER_FALLING);
+               else
+                       irq_set_irq_type(headset_info->irq[HEADSET],IRQF_TRIGGER_RISING);
        }
-       
+       else if(headset_info->headset_status == HEADSET_OUT)
+       {
+               headset_info->cur_headset_status = ~(BIT_HEADSET|BIT_HEADSET_NO_MIC);
+               del_timer(&headset_info->hook_timer);
+               if(headset_info->isMic)
+               {
+                       headset_info->hook_status = HOOK_UP;
+                       #ifdef CONFIG_SND_SOC_WM8994
+                       //rt5625_headset_mic_detect(false);
+                       wm8994_headset_mic_detect(false);
+                       #endif
+                       #ifdef CONFIG_SND_SOC_RT3261
+                       rt3261_headset_mic_detect(false);
+                       #endif
+               }       
+               if(pdata->headset_in_type == HEADSET_IN_HIGH)
+                       irq_set_irq_type(headset_info->irq[HEADSET],IRQF_TRIGGER_RISING);
+               else
+                       irq_set_irq_type(headset_info->irq[HEADSET],IRQF_TRIGGER_FALLING);                      
+       }       
+
+       rk28_send_wakeup_key();                 
+       switch_set_state(&headset_info->sdev, headset_info->cur_headset_status);        
+       DBG("headset notice android headset status = %d\n",headset_info->cur_headset_status);   
+
+//     schedule_delayed_work(&headset_info->h_delayed_work[HEADSET], msecs_to_jiffies(0));
+out:
+       headset_info->heatset_irq_working = IDLE;
+       return IRQ_HANDLED;
+}
+
+static int headset_change_irqtype(int type,unsigned int irq_type)
+{
+       int ret = 0;
+       free_irq(headset_info->irq[type],NULL);
 
-RE_ERROR:
-       mutex_unlock(&headset_info->mutex_lock[HEADSET]);       
+       DBG("%s: type is %s irqtype is %s\n",__FUNCTION__,      type?"hook":"headset",(irq_type == IRQF_TRIGGER_RISING)?"RISING":"FALLING");
+//     DBG("%s: type is %s irqtype is %s\n",__FUNCTION__,      type?"hook":"headset",(irq_type == IRQF_TRIGGER_LOW)?"LOW":"HIGH");
+       switch(type)
+       {
+       case HEADSET:
+               ret = request_threaded_irq(headset_info->irq[type],NULL, headset_interrupt, irq_type, "headset_input", NULL);
+               if (ret<0) 
+                       DBG("headset_change_irqtype: request irq failed\n");            
+               break;
+       default:
+               ret = -1;
+               break;
+       }
+       return ret;
 }
+//2
+static void headsetobserve_work(struct work_struct *work)
+{
+       struct rk_headset_pdata *pdata = headset_info->pdata;
+       DBG("In the headsetobserve_work headset_status is %s\n",headset_info->headset_status?"in":"out");
 
+       if(headset_info->heatset_irq_working == WAIT && headset_info->headset_status == HEADSET_IN)
+       {
+               printk("wait for codec\n");
+               headset_info->heatset_irq_working = IDLE;
+               headset_info->headset_status = HEADSET_OUT;     
+               
+               free_irq(headset_info->irq[HEADSET],NULL);      
+               msleep(100);
+               if(pdata->headset_in_type == HEADSET_IN_HIGH)
+                       headset_info->irq_type[HEADSET] = IRQF_TRIGGER_HIGH|IRQF_ONESHOT;
+               else
+                       headset_info->irq_type[HEADSET] = IRQF_TRIGGER_LOW|IRQF_ONESHOT;
+               if(request_threaded_irq(headset_info->irq[HEADSET], NULL,headset_interrupt, headset_info->irq_type[HEADSET], "headset_input", NULL) < 0)
+                       printk("headset request_threaded_irq error\n");
+               return; 
+       }
+/*     
+       if(pdata->headset_in_type == HEADSET_IN_HIGH && headset_info->headset_status == HEADSET_IN)
+               headset_change_irqtype(HEADSET,IRQF_TRIGGER_FALLING);
+       else if(pdata->headset_in_type == HEADSET_IN_LOW && headset_info->headset_status == HEADSET_IN)
+               headset_change_irqtype(HEADSET,IRQF_TRIGGER_RISING);
+
+       if(pdata->headset_in_type == HEADSET_IN_HIGH && headset_info->headset_status == HEADSET_OUT)
+               headset_change_irqtype(HEADSET,IRQF_TRIGGER_RISING);
+       else if(pdata->headset_in_type == HEADSET_IN_LOW && headset_info->headset_status == HEADSET_OUT)
+               headset_change_irqtype(HEADSET,IRQF_TRIGGER_FALLING);
+*/             
+}
+//4
 static void hook_adc_callback(struct adc_client *client, void *client_param, int result)
 {
-       int level = 0;
+       int level = result;
        struct headset_priv *headset = (struct headset_priv *)client_param;
-       struct rk_headset_pdata *pdata = headset_info->pdata;
+       struct rk_headset_pdata *pdata = headset->pdata;
        static unsigned int old_status = HOOK_UP;
 
-       DBG("---hook_adc_callback---, result = %d, flag = %d\n", result, headset->adc_callback_status);
-
-       level = result;
+       DBG("hook_adc_callback read adc value: %d\n",level);
 
        if(level < 0)
        {
-               printk("%s:get adc level err!\n",__FUNCTION__);
+               printk("%s:get adc level err = %d!\n",__FUNCTION__,level);
                return;
        }
 
-       switch(headset->adc_callback_status)
+       if(headset->headset_status == HEADSET_OUT
+               || headset->heatset_irq_working == BUSY
+               || headset->heatset_irq_working == WAIT
+               || pdata->headset_in_type?gpio_get_value(pdata->Headset_gpio) == 0:gpio_get_value(pdata->Headset_gpio) > 0)
        {
-
-               case HEADSET_TIMER:
-
-                       if(level >= 0 && level < HOOK_LEVEL_LOW)
-                       {
-                               headset->isMic= 0;//No microphone
-                               headset_info->cur_headset_status = BIT_HEADSET_NO_MIC;
-                               printk("headset->isMic = %d\n",headset->isMic);         
-                       }       
-                       else if(level >= HOOK_LEVEL_HIGH)       
-                       {       
-                               headset->isMic = 1;//have mic
-                               DBG("enable headset_hook irq\n");
-                               headset_info->cur_headset_status = BIT_HEADSET; 
-                               mod_timer(&headset_info->hook_timer, jiffies + msecs_to_jiffies(HOOK_ADC_SAMPLE_TIME));
-                               printk("headset->isMic = %d\n",headset->isMic);         
-                       }
+               DBG("Headset is out or waiting for headset is in or out,after same time check HOOK key\n");
+               return;
+       }       
        
-                       rk28_send_wakeup_key();
-                       switch_set_state(&headset_info->sdev, headset_info->cur_headset_status);
-                       DBG("headset_info->cur_headset_status = %d\n",headset_info->cur_headset_status);
-                       break;  
-
-               case HOOK_TIMER:
-                       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 or suspend\n");
-                               goto RE_ERROR;
-                       }
-                       #endif
+       old_status = headset->hook_status;
+       if(level < HOOK_LEVEL_LOW && level >= 0)        
+               headset->hook_status = HOOK_DOWN;
+       else if(level > HOOK_LEVEL_HIGH && level < HOOK_DEFAULT_VAL)
+               headset->hook_status = HOOK_UP;
+       else{
+               DBG("hook_adc_callback read adc value.........outside showly....: %d\n",level);
+               del_timer(&headset->hook_timer);
+               mod_timer(&headset->hook_timer, jiffies + msecs_to_jiffies(500));
+               return;
+       }
        
-                       old_status = headset_info->hook_status;
-                       if(level >= HOOK_LEVEL_HIGH)
-                               headset_info->hook_status = HOOK_UP;
-                       else if(level < HOOK_LEVEL_LOW && level >= 0)   
-                               headset_info->hook_status = HOOK_DOWN;
-                       if(old_status == headset_info->hook_status)
-                       {
-                               DBG("old_status == headset_info->hook_status\n");
-                               goto RE_ERROR;
-                       }       
+       if(old_status == headset->hook_status)
+       {
+       //      DBG("Hook adc read old_status == headset->hook_status hook_time = %d\n",headset->hook_time);
+               return;
+       }       
        
-                       if(level < HOOK_LEVEL_LOW && level >= 0)
-                       {
-                               DBG("---HOOK Down ---\n");
-                               //headset_change_irqtype(HOOK,IRQF_TRIGGER_RISING);//
-                               input_report_key(headset_info->input_dev,pdata->hook_key_code,headset_info->hook_status);
-                               input_sync(headset_info->input_dev);
-                       }
-                       else if(level >= HOOK_LEVEL_HIGH)
-                       {
-                               DBG("---HOOK Up ---\n");                
-                               //headset_change_irqtype(HOOK,IRQF_TRIGGER_FALLING);//
-                               input_report_key(headset_info->input_dev,pdata->hook_key_code,headset_info->hook_status);
-                               input_sync(headset_info->input_dev);
-                       }
-                       mutex_unlock(&headset_info->mutex_lock[HOOK]);
-                       break;  
-               default:
-                       printk("adc callback flag status error!!! default case\n");
-                       break;
-       }
-       return;
-
-RE_ERROR:
-       mutex_unlock(&headset_info->mutex_lock[HOOK]);
+       DBG("HOOK status is %s , adc value = %d hook_time = %d\n",headset->hook_status?"down":"up",level,headset->hook_time);   
+       if(headset->headset_status == HEADSET_OUT
+               || headset->heatset_irq_working == BUSY
+               || headset->heatset_irq_working == WAIT
+               || (pdata->headset_in_type?gpio_get_value(pdata->Headset_gpio) == 0:gpio_get_value(pdata->Headset_gpio) > 0))
+               DBG("headset is out,HOOK status must discard\n");
+       else
+       {
+               if(headset->hook_status==HOOK_DOWN)
+               DBG("hook_adc_callback read adc ------------HOOK_DOWN\n");
+               else
+               DBG("hook_adc_callback read adc ------------HOOK_UP\n");
+               input_report_key(headset->input_dev,pdata->hook_key_code,headset->hook_status);
+               input_sync(headset->input_dev);
+       }       
 }
-
+//3
 static void hook_timer_callback(unsigned long arg)
 {
        struct headset_priv *headset = (struct headset_priv *)(arg);
-       DBG("hook_timer_callback\n");
-       adc_async_read(headset->client);
-       headset->adc_callback_status = HOOK_TIMER;      
-       mod_timer(&headset->hook_timer, jiffies + msecs_to_jiffies(HOOK_ADC_SAMPLE_TIME));
-}
-
-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,headset->headset_status=%d\n",headset->headset_status);     
-
-       if(headset->headset_status == HEADSET_OUT)
-       {
-               printk("Headset is out\n");
-               goto out;
-       }
-       #ifdef CONFIG_SND_SOC_WM8994
-       if(wm8994_set_status() != 0)
-       {
-       //      printk("wait wm8994 set the MICB2\n");
-       //      headset_info->headset_timer.expires = jiffies + 500;
-               headset_info->headset_timer.expires = jiffies + 10;
-               add_timer(&headset_info->headset_timer);        
-               goto out;
-       }
-       #endif
-
+//     DBG("hook_timer_callback\n");
+       if(headset->headset_status == HEADSET_OUT
+               || headset->heatset_irq_working == BUSY
+               || headset->heatset_irq_working == WAIT)
+               return;
        adc_async_read(headset->client);
-       headset->adc_callback_status = HEADSET_TIMER;   
-out:
-       return;
+       mod_timer(&headset->hook_timer, jiffies + msecs_to_jiffies(headset->hook_time));
 }
 
 static ssize_t h2w_print_name(struct switch_dev *sdev, char *buf)
@@ -416,12 +449,14 @@ static int rockchip_headsetobserve_probe(struct platform_device *pdev)
        if (headset == NULL) {
                dev_err(&pdev->dev, "failed to allocate driver data\n");
                return -ENOMEM;
-       }       
+       }
+       headset_info = headset;
        headset->pdata = pdev->dev.platform_data;
        pdata = headset->pdata;
        headset->headset_status = HEADSET_OUT;
+       headset->heatset_irq_working = IDLE;
        headset->hook_status = HOOK_UP;
-       headset->adc_callback_status = HEADSET_TIMER;   
+       headset->hook_time = HOOK_ADC_SAMPLE_TIME;
        headset->cur_headset_status = 0;
        headset->sdev.name = "h2w";
        headset->sdev.print_name = h2w_print_name;
@@ -429,15 +464,13 @@ static int rockchip_headsetobserve_probe(struct platform_device *pdev)
        if (ret < 0)
                goto failed_free;
        
-       mutex_init(&headset->mutex_lock[HEADSET]);
-       mutex_init(&headset->mutex_lock[HOOK]);
+//     mutex_init(&headset->mutex_lock[HEADSET]);
+//     mutex_init(&headset->mutex_lock[HOOK]);
        
        INIT_DELAYED_WORK(&headset->h_delayed_work[HEADSET], headsetobserve_work);
 
        headset->isMic = 0;
-       setup_timer(&headset->headset_timer, headset_timer_callback, (unsigned long)headset);
-
-               
+//------------------------------------------------------------------           
        // Create and register the input driver. 
        headset->input_dev = input_allocate_device();
        if (!headset->input_dev) {
@@ -460,65 +493,46 @@ static int rockchip_headsetobserve_probe(struct platform_device *pdev)
                goto failed_free_dev;
        }
 
-
-//     headset->input_dev->keycode = headset->keycodes;
-//     headset->input_dev->keycodesize = sizeof(unsigned char);
-//     headset->input_dev->keycodemax = 2;
-       
-//     set_bit(KEY_MEDIA, headset->input_dev->keybit);
-//     clear_bit(0, headset->input_dev->keybit);
        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);
-
-//     headset->input_dev->evbit[0] = BIT_MASK(EV_KEY);
-       
-       headset_info = headset;
-       schedule_delayed_work(&headset->h_delayed_work[HEADSET], msecs_to_jiffies(500));        
-
-#ifdef CONFIG_HAS_EARLYSUSPEND
-       hs_early_suspend.suspend = NULL;
-       hs_early_suspend.resume = headset_early_resume;
-       hs_early_suspend.level = ~0x0;
-       register_early_suspend(&hs_early_suspend);
-#endif
-
-       //------------------------------------------------------------------
+//------------------------------------------------------------------
        if (pdata->Headset_gpio) {
-
                ret = pdata->headset_io_init(pdata->Headset_gpio, pdata->headset_gpio_info.iomux_name, pdata->headset_gpio_info.iomux_mode);
                if (ret) 
-                       goto failed_free_dev;
+                       goto failed_free;
 
                headset->irq[HEADSET] = gpio_to_irq(pdata->Headset_gpio);
 
                if(pdata->headset_in_type == HEADSET_IN_HIGH)
-                       headset->irq_type[HEADSET] = IRQF_TRIGGER_RISING;
+                       headset->irq_type[HEADSET] = IRQF_TRIGGER_HIGH|IRQF_ONESHOT;
                else
-                       headset->irq_type[HEADSET] = IRQF_TRIGGER_FALLING;
-               ret = request_irq(headset->irq[HEADSET], headset_interrupt, headset->irq_type[HEADSET], "headset_input", NULL);
+                       headset->irq_type[HEADSET] = IRQF_TRIGGER_LOW|IRQF_ONESHOT;
+               ret = request_threaded_irq(headset->irq[HEADSET], NULL,headset_interrupt, headset->irq_type[HEADSET], "headset_input", NULL);
                if (ret) 
-                       goto failed_free_dev;
+                       goto failed_free;
                enable_irq_wake(headset->irq[HEADSET]);
        }
        else
-               goto failed_free_dev;
+               goto failed_free;
 //------------------------------------------------------------------
-       
-       if(pdata->Hook_adc_chn>=0 && 2>=pdata->Hook_adc_chn)
+       if(pdata->Hook_adc_chn>=0 && 3>=pdata->Hook_adc_chn)
        {
-               printk("hook adc register\n");
                headset->client = adc_register(pdata->Hook_adc_chn, hook_adc_callback, (void *)headset);
                if(!headset->client) {
                        printk("hook adc register error\n");
                        ret = -EINVAL;
-                       goto failed_free_dev;
+                       goto failed_free;
                }
-               setup_timer(&headset->hook_timer,
-                               hook_timer_callback, (unsigned long)headset);           
+               setup_timer(&headset->hook_timer,hook_timer_callback, (unsigned long)headset);  
+               printk("headset adc default value = %d\n",adc_sync_read(headset->client));
        }
        
-//------------------------------------------------------------------
+#ifdef CONFIG_HAS_EARLYSUSPEND
+       hs_early_suspend.suspend = NULL;
+       hs_early_suspend.resume = headset_early_resume;
+       hs_early_suspend.level = ~0x0;
+       register_early_suspend(&hs_early_suspend);
+#endif
+
        return 0;       
        
 failed_free_dev:
@@ -533,21 +547,24 @@ failed_free:
 static int rockchip_headsetobserve_suspend(struct platform_device *pdev, pm_message_t state)
 {
        DBG("%s----%d\n",__FUNCTION__,__LINE__);
-       disable_irq(headset_info->irq[HEADSET]);
+//     disable_irq(headset_info->irq[HEADSET]);
+       del_timer(&headset_info->hook_timer);
        return 0;
 }
 
 static int rockchip_headsetobserve_resume(struct platform_device *pdev)
 {
        DBG("%s----%d\n",__FUNCTION__,__LINE__);        
-       enable_irq(headset_info->irq[HEADSET]);
+//     enable_irq(headset_info->irq[HEADSET]);
+       if(headset_info->isMic)
+               mod_timer(&headset_info->hook_timer, jiffies + msecs_to_jiffies(1500)); 
        return 0;
 }
 
 static struct platform_driver rockchip_headsetobserve_driver = {
        .probe  = rockchip_headsetobserve_probe,
-//     .resume =       rockchip_headsetobserve_resume, 
-//     .suspend =      rockchip_headsetobserve_suspend,        
+       .resume =       rockchip_headsetobserve_resume, 
+       .suspend =      rockchip_headsetobserve_suspend,        
        .driver = {
                .name   = "rk_headsetdet",
                .owner  = THIS_MODULE,
@@ -559,6 +576,7 @@ static int __init rockchip_headsetobserve_init(void)
        platform_driver_register(&rockchip_headsetobserve_driver);
        return 0;
 }
-module_init(rockchip_headsetobserve_init);
+late_initcall(rockchip_headsetobserve_init);
 MODULE_DESCRIPTION("Rockchip Headset Driver");
 MODULE_LICENSE("GPL");
+
index 550ba33ed9d9dac84c74cdec0e5fdcae77f64b4c..af97d6a89d53f2ed9fa4541add477988c6a4d460 100644 (file)
@@ -62,8 +62,10 @@ static struct snd_soc_codec *rt3261_codec;
 
 #define VERSION "RT3261_V1.0.0"
 
+#if defined (CONFIG_SND_SOC_RT5623)
 extern void rt5623_on(void);
 extern void rt5623_off(void);
+#endif
 
 struct rt3261_init_reg {
        u8 reg;
@@ -482,7 +484,7 @@ static int rt3261_readable_register(
 }
 
 /**
- * rt3261_headset_detect - Detect headset.
+ * rt3261_headset_mic_detect - Detect headset.
  * @codec: SoC audio codec device.
  * @jack_insert: Jack insert or not.
  *
@@ -490,43 +492,44 @@ static int rt3261_readable_register(
  *
  * Returns detect status.
  */
-int rt3261_headset_detect(struct snd_soc_codec *codec, int jack_insert)
+int rt3261_headset_mic_detect(int jack_insert)
 {
        int jack_type;
        int sclk_src;
 
        if(jack_insert) {
-               if (SND_SOC_BIAS_OFF == codec->dapm.bias_level) {
-                       snd_soc_write(codec, RT3261_PWR_ANLG1, 0x2004);
-                       snd_soc_write(codec, RT3261_MICBIAS, 0x3830);
-                       snd_soc_write(codec, RT3261_GEN_CTRL1 , 0x3701);
+               if (SND_SOC_BIAS_OFF == rt3261_codec->dapm.bias_level) {
+                       snd_soc_write(rt3261_codec, RT3261_PWR_ANLG1, 0x2004);
+                       snd_soc_write(rt3261_codec, RT3261_MICBIAS, 0x3830);
+                       snd_soc_write(rt3261_codec, RT3261_GEN_CTRL1 , 0x3701);
                }
-               sclk_src = snd_soc_read(codec, RT3261_GLB_CLK) &
+               sclk_src = snd_soc_read(rt3261_codec, RT3261_GLB_CLK) &
                        RT3261_SCLK_SRC_MASK;
-               snd_soc_update_bits(codec, RT3261_GLB_CLK,
+               snd_soc_update_bits(rt3261_codec, RT3261_GLB_CLK,
                        RT3261_SCLK_SRC_MASK, 0x3 << RT3261_SCLK_SRC_SFT);
-               snd_soc_update_bits(codec, RT3261_PWR_ANLG1,
+               snd_soc_update_bits(rt3261_codec, RT3261_PWR_ANLG1,
                        RT3261_PWR_LDO2, RT3261_PWR_LDO2);
-               snd_soc_update_bits(codec, RT3261_PWR_ANLG2,
+               snd_soc_update_bits(rt3261_codec, RT3261_PWR_ANLG2,
                        RT3261_PWR_MB1, RT3261_PWR_MB1);
-               snd_soc_update_bits(codec, RT3261_MICBIAS,
+               mdelay(400);
+               snd_soc_update_bits(rt3261_codec, RT3261_MICBIAS,
                        RT3261_MIC1_OVCD_MASK | RT3261_MIC1_OVTH_MASK |
                        RT3261_PWR_CLK25M_MASK | RT3261_PWR_MB_MASK,
                        RT3261_MIC1_OVCD_EN | RT3261_MIC1_OVTH_600UA |
                        RT3261_PWR_MB_PU | RT3261_PWR_CLK25M_PU);
-               snd_soc_update_bits(codec, RT3261_GEN_CTRL1,
+               snd_soc_update_bits(rt3261_codec, RT3261_GEN_CTRL1,
                        0x1, 0x1);
                msleep(100);
-               if (snd_soc_read(codec, RT3261_IRQ_CTRL2) & 0x8)
+               if (snd_soc_read(rt3261_codec, RT3261_IRQ_CTRL2) & 0x8)
                        jack_type = RT3261_HEADPHO_DET;
                else
                        jack_type = RT3261_HEADSET_DET;
-               snd_soc_update_bits(codec, RT3261_IRQ_CTRL2,
+               snd_soc_update_bits(rt3261_codec, RT3261_IRQ_CTRL2,
                        RT3261_MB1_OC_CLR, 0);
-               snd_soc_update_bits(codec, RT3261_GLB_CLK,
+               snd_soc_update_bits(rt3261_codec, RT3261_GLB_CLK,
                        RT3261_SCLK_SRC_MASK, sclk_src);
        } else {
-               snd_soc_update_bits(codec, RT3261_MICBIAS,
+               snd_soc_update_bits(rt3261_codec, RT3261_MICBIAS,
                        RT3261_MIC1_OVCD_MASK,
                        RT3261_MIC1_OVCD_DIS);
                
@@ -535,7 +538,7 @@ int rt3261_headset_detect(struct snd_soc_codec *codec, int jack_insert)
 
        return jack_type;
 }
-EXPORT_SYMBOL(rt3261_headset_detect);
+EXPORT_SYMBOL(rt3261_headset_mic_detect);
 
 static const char *rt3261_dacr2_src[] = { "TxDC_R", "TxDP_R" };
 
@@ -765,6 +768,7 @@ static int rt3261_hp_mute_put(struct snd_kcontrol *kcontrol,
        return 0;
 }
 
+#if defined (CONFIG_SND_SOC_RT5623)
 static int rt3261_modem_input_switch_get(struct snd_kcontrol *kcontrol,
                struct snd_ctl_elem_value *ucontrol)
 {
@@ -791,6 +795,7 @@ static int rt3261_modem_input_switch_put(struct snd_kcontrol *kcontrol,
 
        return 0;
 }
+#endif
 
 /* IN1/IN2 Input Type */
 static const char *rt3261_input_mode[] = {
@@ -851,9 +856,11 @@ static const char *rt3261_hp_mute_mode[] = {"off", "on",};
 
 static const SOC_ENUM_SINGLE_DECL(rt3261_hp_mute_enum, 0, 0, rt3261_hp_mute_mode);
 
+#if defined (CONFIG_SND_SOC_RT5623)
 static const char *rt3261_modem_input_switch_mode[] = {"off", "on",};
 
 static const SOC_ENUM_SINGLE_DECL(rt3261_modem_input_switch_enum, 0, 0, rt3261_modem_input_switch_mode);
+#endif
 
 #ifdef RT3261_REG_RW
 #define REGVAL_MAX 0xffff
@@ -1010,8 +1017,10 @@ static const struct snd_kcontrol_new rt3261_snd_controls[] = {
        SOC_ENUM_EXT("HP mute Switch", rt3261_hp_mute_enum,
                rt3261_hp_mute_get, rt3261_hp_mute_put),
 
+       #if defined (CONFIG_SND_SOC_RT5623)
        SOC_ENUM_EXT("Modem Input Switch", rt3261_modem_input_switch_enum,
                rt3261_modem_input_switch_get, rt3261_modem_input_switch_put),
+       #endif
 };
 
 /**
@@ -2863,14 +2872,9 @@ static int rt3261_set_bias_level(struct snd_soc_codec *codec,
                break;
 
        case SND_SOC_BIAS_PREPARE:
-               snd_soc_update_bits(codec, RT3261_PWR_ANLG2,
-                       RT3261_PWR_MB1 | RT3261_PWR_MB2,
-                       RT3261_PWR_MB1 | RT3261_PWR_MB2);
                break;
 
        case SND_SOC_BIAS_STANDBY:
-               snd_soc_update_bits(codec, RT3261_PWR_ANLG2,
-                       RT3261_PWR_MB1 | RT3261_PWR_MB2, 0);
                if (SND_SOC_BIAS_OFF == codec->dapm.bias_level) {
                        snd_soc_update_bits(codec, RT3261_PWR_ANLG1,
                                RT3261_PWR_VREF1 | RT3261_PWR_MB |
@@ -2930,6 +2934,7 @@ static int rt3261_probe(struct snd_soc_codec *codec)
        rt3261_proc_init();
        #endif
 
+       #if defined (CONFIG_SND_SOC_RT5623)
        //for rt5623 MCLK use
        iis_clk = clk_get_sys("rk29_i2s.2", "i2s");
        if (IS_ERR(iis_clk)) {
@@ -2942,6 +2947,7 @@ static int rt3261_probe(struct snd_soc_codec *codec)
                rk30_mux_api_set(GPIO0D0_I2S22CHCLK_SMCCSN0_NAME, GPIO0D_I2S2_2CH_CLK);
                clk_put(iis_clk);
        }
+       #endif
        
        rt3261_reset(codec);
        snd_soc_update_bits(codec, RT3261_PWR_ANLG1,
@@ -3144,7 +3150,9 @@ static int __devinit rt3261_i2c_probe(struct i2c_client *i2c,
        if(rt3261->io_init)
                rt3261->io_init(pdata->codec_en_gpio, pdata->codec_en_gpio_info.iomux_name, pdata->codec_en_gpio_info.iomux_mode);
 
+       #if defined (CONFIG_SND_SOC_RT5623)
        rt3261->modem_is_open = 0;
+       #endif
 
        i2c_set_clientdata(i2c, rt3261);
        DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
index b6b6cc4c8a12d776cf3379cc6cfa47b123e02623..5f4b3e887d018e88ba2184380623d4ea244eb1c2 100644 (file)
@@ -2069,7 +2069,7 @@ enum {
 #define RT3261_HEADSET_DET     BIT(1)
 #define RT3261_HEADPHO_DET     BIT(2)
 
-int rt3261_headset_detect(struct snd_soc_codec *codec, int jack_insert);
+int rt3261_headset_mic_detect(int jack_insert);
 
 /* System Clock Source */
 enum {
index 5f00df43b5ee768145f2ea6ff2c396ba13bc46a4..c10c97db7744bb26e7da54bc7b342f85d23160c7 100644 (file)
@@ -169,6 +169,53 @@ static int rt3261_voice_hw_params(struct snd_pcm_substream *substream,
        return 0;\r
 }\r
 \r
+static const struct snd_soc_dapm_widget rt3261_dapm_widgets[] = {\r
+       SND_SOC_DAPM_MIC("Mic Jack", NULL),\r
+       SND_SOC_DAPM_MIC("Headset Jack", NULL), \r
+};\r
+\r
+static const struct snd_soc_dapm_route audio_map[]={\r
+\r
+       /* Mic Jack --> MIC_IN*/\r
+       {"micbias1", NULL, "Mic Jack"},\r
+       {"MIC1", NULL, "micbias1"},\r
+       \r
+       // HP MIC\r
+       {"micbias1", NULL, "Headset Jack"},\r
+       {"MIC3", NULL, "micbias1"},\r
+} ;\r
+\r
+static const struct snd_kcontrol_new rk_controls[] = {\r
+       SOC_DAPM_PIN_SWITCH("Mic Jack"),\r
+       SOC_DAPM_PIN_SWITCH("Headset Jack"),\r
+};\r
+\r
+/*\r
+ * Logic for a rt3261 as connected on a rockchip board.\r
+ */\r
+static int rk29_rt3261_init(struct snd_soc_pcm_runtime *rtd)\r
+{\r
+       struct snd_soc_codec *codec = rtd->codec;\r
+       struct snd_soc_dapm_context *dapm = &codec->dapm;\r
+\r
+       DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);\r
+\r
+       snd_soc_add_controls(codec, rk_controls,\r
+                       ARRAY_SIZE(rk_controls));\r
+\r
+       /* Add specific widgets */\r
+       snd_soc_dapm_new_controls(dapm, rt3261_dapm_widgets,\r
+                                 ARRAY_SIZE(rt3261_dapm_widgets));\r
+       /* Set up specific audio path audio_mapnects */\r
+       snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));\r
+\r
+       snd_soc_dapm_enable_pin(dapm, "Mic Jack");\r
+       snd_soc_dapm_enable_pin(dapm, "Headset Jack");\r
+       snd_soc_dapm_sync(dapm);\r
+\r
+       return 0;\r
+}\r
+\r
 static struct snd_soc_ops rk29_ops = {\r
        .hw_params = rk29_hw_params,\r
 };\r
@@ -185,6 +232,7 @@ static struct snd_soc_dai_link rk29_dai[] = {
                .platform_name = "rockchip-audio",\r
                .cpu_dai_name = "rk29_i2s.0",\r
                .codec_dai_name = "rt3261-aif1",\r
+               .init = rk29_rt3261_init,\r
                .ops = &rk29_ops,\r
        },\r
        {\r
@@ -194,6 +242,7 @@ static struct snd_soc_dai_link rk29_dai[] = {
                .platform_name = "rockchip-audio",\r
                .cpu_dai_name = "rk29_i2s.0",\r
                .codec_dai_name = "rt3261-aif2",\r
+               .init = rk29_rt3261_init,\r
                .ops = &rt3261_voice_ops,\r
        },\r
 };\r