phonepad: update the headset driver from huawei project, make some code in

rt3261.c depend on CONFIG_SND_SOC_RT5623.
This commit is contained in:
宋秀杰
2012-09-04 20:12:52 +08:00
parent 5605fd2209
commit ab87cd4e19
4 changed files with 369 additions and 294 deletions

View File

@@ -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);
}
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);
}
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_NO_MIC;
headset_change_irqtype(HEADSET,IRQF_TRIGGER_RISING);//
#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);
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(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--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);
#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;
default:
DBG("---- ERROR: on headset headset_in_type error -----\n");
break;
else
{
headset_info->isMic= 0;//No microphone
headset_info->cur_headset_status = BIT_HEADSET_NO_MIC;
}
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);
}
RE_ERROR:
mutex_unlock(&headset_info->mutex_lock[HEADSET]);
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);
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_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(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;
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;
}
return;
RE_ERROR:
mutex_unlock(&headset_info->mutex_lock[HOOK]);
if(old_status == headset->hook_status)
{
// DBG("Hook adc read old_status == headset->hook_status hook_time = %d\n",headset->hook_time);
return;
}
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");
// 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 = 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
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,22 +493,39 @@ 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);
//------------------------------------------------------------------
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;
// headset->input_dev->evbit[0] = BIT_MASK(EV_KEY);
headset->irq[HEADSET] = gpio_to_irq(pdata->Headset_gpio);
if(pdata->headset_in_type == HEADSET_IN_HIGH)
headset->irq_type[HEADSET] = IRQF_TRIGGER_HIGH|IRQF_ONESHOT;
else
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;
enable_irq_wake(headset->irq[HEADSET]);
}
else
goto failed_free;
//------------------------------------------------------------------
if(pdata->Hook_adc_chn>=0 && 3>=pdata->Hook_adc_chn)
{
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;
}
setup_timer(&headset->hook_timer,hook_timer_callback, (unsigned long)headset);
printk("headset adc default value = %d\n",adc_sync_read(headset->client));
}
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;
@@ -483,42 +533,6 @@ static int rockchip_headsetobserve_probe(struct platform_device *pdev)
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;
headset->irq[HEADSET] = gpio_to_irq(pdata->Headset_gpio);
if(pdata->headset_in_type == HEADSET_IN_HIGH)
headset->irq_type[HEADSET] = IRQF_TRIGGER_RISING;
else
headset->irq_type[HEADSET] = IRQF_TRIGGER_FALLING;
ret = request_irq(headset->irq[HEADSET], headset_interrupt, headset->irq_type[HEADSET], "headset_input", NULL);
if (ret)
goto failed_free_dev;
enable_irq_wake(headset->irq[HEADSET]);
}
else
goto failed_free_dev;
//------------------------------------------------------------------
if(pdata->Hook_adc_chn>=0 && 2>=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;
}
setup_timer(&headset->hook_timer,
hook_timer_callback, (unsigned long)headset);
}
//------------------------------------------------------------------
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");

View 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__);

View 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 {

View File

@@ -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,
},
};