From ab87cd4e19c26961a16933db28e3fa6b653eb739 Mon Sep 17 00:00:00 2001 From: =?utf8?q?=E5=AE=8B=E7=A7=80=E6=9D=B0?= Date: Tue, 4 Sep 2012 20:12:52 +0800 Subject: [PATCH] phonepad: update the headset driver from huawei project, make some code in rt3261.c depend on CONFIG_SND_SOC_RT5623. --- .../headset_observe/rk_headset_irq_hook_adc.c | 532 +++++++++--------- sound/soc/codecs/rt3261.c | 52 +- sound/soc/codecs/rt3261.h | 2 +- sound/soc/rk29/rk29_rt3261.c | 49 ++ 4 files changed, 355 insertions(+), 280 deletions(-) diff --git a/drivers/headset_observe/rk_headset_irq_hook_adc.c b/drivers/headset_observe/rk_headset_irq_hook_adc.c index 53d4a170d60c..e954e264d56c 100755 --- a/drivers/headset_observe/rk_headset_irq_hook_adc.c +++ b/drivers/headset_observe/rk_headset_irq_hook_adc.c @@ -49,9 +49,10 @@ #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) @@ -61,16 +62,24 @@ #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"); + diff --git a/sound/soc/codecs/rt3261.c b/sound/soc/codecs/rt3261.c index 550ba33ed9d9..af97d6a89d53 100644 --- a/sound/soc/codecs/rt3261.c +++ b/sound/soc/codecs/rt3261.c @@ -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__); diff --git a/sound/soc/codecs/rt3261.h b/sound/soc/codecs/rt3261.h index b6b6cc4c8a12..5f4b3e887d01 100644 --- a/sound/soc/codecs/rt3261.h +++ b/sound/soc/codecs/rt3261.h @@ -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 { diff --git a/sound/soc/rk29/rk29_rt3261.c b/sound/soc/rk29/rk29_rt3261.c index 5f00df43b5ee..c10c97db7744 100644 --- a/sound/soc/rk29/rk29_rt3261.c +++ b/sound/soc/rk29/rk29_rt3261.c @@ -169,6 +169,53 @@ static int rt3261_voice_hw_params(struct snd_pcm_substream *substream, return 0; } +static const struct snd_soc_dapm_widget rt3261_dapm_widgets[] = { + SND_SOC_DAPM_MIC("Mic Jack", NULL), + SND_SOC_DAPM_MIC("Headset Jack", NULL), +}; + +static const struct snd_soc_dapm_route audio_map[]={ + + /* Mic Jack --> MIC_IN*/ + {"micbias1", NULL, "Mic Jack"}, + {"MIC1", NULL, "micbias1"}, + + // HP MIC + {"micbias1", NULL, "Headset Jack"}, + {"MIC3", NULL, "micbias1"}, +} ; + +static const struct snd_kcontrol_new rk_controls[] = { + SOC_DAPM_PIN_SWITCH("Mic Jack"), + SOC_DAPM_PIN_SWITCH("Headset Jack"), +}; + +/* + * Logic for a rt3261 as connected on a rockchip board. + */ +static int rk29_rt3261_init(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_codec *codec = rtd->codec; + struct snd_soc_dapm_context *dapm = &codec->dapm; + + DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__); + + snd_soc_add_controls(codec, rk_controls, + ARRAY_SIZE(rk_controls)); + + /* Add specific widgets */ + snd_soc_dapm_new_controls(dapm, rt3261_dapm_widgets, + ARRAY_SIZE(rt3261_dapm_widgets)); + /* Set up specific audio path audio_mapnects */ + snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map)); + + snd_soc_dapm_enable_pin(dapm, "Mic Jack"); + snd_soc_dapm_enable_pin(dapm, "Headset Jack"); + snd_soc_dapm_sync(dapm); + + return 0; +} + static struct snd_soc_ops rk29_ops = { .hw_params = rk29_hw_params, }; @@ -185,6 +232,7 @@ static struct snd_soc_dai_link rk29_dai[] = { .platform_name = "rockchip-audio", .cpu_dai_name = "rk29_i2s.0", .codec_dai_name = "rt3261-aif1", + .init = rk29_rt3261_init, .ops = &rk29_ops, }, { @@ -194,6 +242,7 @@ static struct snd_soc_dai_link rk29_dai[] = { .platform_name = "rockchip-audio", .cpu_dai_name = "rk29_i2s.0", .codec_dai_name = "rt3261-aif2", + .init = rk29_rt3261_init, .ops = &rt3261_voice_ops, }, }; -- 2.34.1