From 7451a831e63aa77878d7025926ef4f39b00fb999 Mon Sep 17 00:00:00 2001 From: =?utf8?q?=E9=82=B1=E5=BB=BA=E6=96=8C?= Date: Tue, 28 Jun 2011 10:32:21 +0800 Subject: [PATCH] rk29_phone: fix hook key irq. if headset have not hook key then not reported keydown --- arch/arm/mach-rk29/board-rk29-a22.c | 1 + arch/arm/mach-rk29/board-rk29-phonesdk.c | 1 + drivers/headset_observe/rk_headset.c | 229 +++++++++++++++-------- drivers/headset_observe/rk_headset.h | 2 +- sound/soc/codecs/wm8994.c | 210 ++++++++++++++------- 5 files changed, 296 insertions(+), 147 deletions(-) diff --git a/arch/arm/mach-rk29/board-rk29-a22.c b/arch/arm/mach-rk29/board-rk29-a22.c index 68f14f77102f..f665242e6156 100755 --- a/arch/arm/mach-rk29/board-rk29-a22.c +++ b/arch/arm/mach-rk29/board-rk29-a22.c @@ -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 = { diff --git a/arch/arm/mach-rk29/board-rk29-phonesdk.c b/arch/arm/mach-rk29/board-rk29-phonesdk.c index 8e5b2fd2866d..f87c1d675563 100755 --- a/arch/arm/mach-rk29/board-rk29-phonesdk.c +++ b/arch/arm/mach-rk29/board-rk29-phonesdk.c @@ -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 = { diff --git a/drivers/headset_observe/rk_headset.c b/drivers/headset_observe/rk_headset.c index 64d870c10298..5fcccad31090 100755 --- a/drivers/headset_observe/rk_headset.c +++ b/drivers/headset_observe/rk_headset.c @@ -39,7 +39,7 @@ #include /* Debug */ -#if 0 +#if 1 #define DBG(x...) printk(x) #else #define DBG(x...) do { } while (0) @@ -51,21 +51,30 @@ #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); diff --git a/drivers/headset_observe/rk_headset.h b/drivers/headset_observe/rk_headset.h index c1f7a91862ec..51e2655d3fbc 100755 --- a/drivers/headset_observe/rk_headset.h +++ b/drivers/headset_observe/rk_headset.h @@ -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 }; diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c index d7cb1914566c..92a32e1ca161 100755 --- a/sound/soc/codecs/wm8994.c +++ b/sound/soc/codecs/wm8994.c @@ -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); -- 2.34.1