/*
【背景知识】:
国标耳机插头信号定义: <<<【左声道】【右声道】【麦克】【地】
美标耳机插入信号定义: <<<【左声道】【右声道】【地】 【麦克】
【micbias】: 是用来在耳机有 Mic 的情况下,给 Mic 提供直流偏置,让其正常工作的。
他使用 PWM 控制,用于降低麦克的功耗, 在不用麦克的情况下,可以降低
轮询检测按键的功耗。
【PMCI ACCDET 模块】:是用来检测耳机类型及按键类型的。
【耳机附件检测原理】: Accessory detected<附件检测>
1.Accdet only
此方式是让耳机 micbias 常开下,依靠 PMIC 内部中断来检测耳机处于的状态的。但
此方式会带来耳机插入瞬间有 pop 杂音的出现。
2.Accdet+EINT 方式
此方式在耳机为插入时,micbias 是被 disable 的。利用中断让 AP 检测到有耳机插入后,
在中断中打开 micbias,从而达到省功耗和减小杂音的效果的。
待插入后,再检测耳机类型,检测走的路线还是通过 PMIC 的 accdet 内部中断。
耳机检测:
Plug in: HP_EINT 触发中断 -> 插入检测 -> ACCDET检测耳机类型
Plug out:HP_EINT 触发中断 -> 拔出检测
HP_EINT:插入拔出检测
ACCDET:检测耳机类型和按键
UP:0.09owner = THIS_MODULE;
accdet_cdev->ops = accdet_get_fops();
ret = cdev_add(accdet_cdev, accdet_devno, 1);
//////////////////////////////////////////////////////////////////////////
// 3. 创建 /sys 目录下的文件节点
accdet_class = class_create(THIS_MODULE, ACCDET_DEVNAME);
// if we want auto creat device node, we must call this
accdet_nor_device = device_create(accdet_class, NULL, accdet_devno, NULL, ACCDET_DEVNAME);
///////////////////////////////////////////////////////////////
// 4. 创建一个 input 输入设备, 用于上报耳机按键事件,创建一个定时器
// 每 6s 自动关闭 micbias,达到省电目的。同时设置 input 输入设备上
// 报的键值类型,并注册输入设备。
kpd_accdet_dev = input_allocate_device();
// 通过定时器每 6s 自动关闭 MICBIAS,达到省电目的,因为中断会唤醒使能
// micbias 检测耳机类型与 mic 及按键,如果没有 mic, 且不需要检测按键,则
// 可以直接关闭 micbias 偏置
init_timer(&micbias_timer);
micbias_timer.expires = jiffies + MICBIAS_DISABLE_TIMER;
micbias_timer.function = &disable_micbias;
disable_micbias(unsigned long a)
ret = queue_work(accdet_disable_workqueue, &accdet_disable_work);
/////////////////////////////////////////////////////////////////
// 调用工作队列
disable_micbias_callback//(struct work_struct *work)
// 如果插入的耳机没有 mic ,则直接关闭 PMIC 的 ACCDET 模块
if(cable_type == HEADSET_NO_MIC)
disable_accdet();
else if(cable_type == HEADSET_MIC)
// 如果要检测键,则重新设置 pwm
//define multi-key keycode
// 设置 input 输入设备上报的键值类型
__set_bit(EV_KEY, kpd_accdet_dev->evbit);
__set_bit(KEY_CALL, kpd_accdet_dev->keybit);
。。。
// 注册 input 输入设备
input_register_device(kpd_accdet_dev)
////////////////////////////////////////////////////////////////////////////
// 5. 注册工作队列,用于处理 ACCDET 模块识别按键流程 , 他会根据 PMIC 的状态,
// 判断是否有耳机插入,及耳机类型和按键类型,如果有按键,通过 input 上报
// 处理完后,同步更新 switch 模块的状态
accdet_workqueue = create_singlethread_workqueue("accdet");
INIT_WORK(&accdet_work, accdet_work_callback);
accdet_work_callback//(struct work_struct *work)
///////////////////////////////////////////////////////////////////////////////////
// 通过 PMCI ,来识别插入是否有耳机插入,及耳机类型或按键类型,如果有按键的话,
// 还需要判断长按、短按,然后通过 input 输入设备上报事件类型。
check_cable_type();
////////////////////////////////////////////////////////////////////////////////
// 获得 PMIC 的内部电压比较器的 AB 状态
// 1.77V-1.9V: 未插入耳机的状态(AB = B11)
// 0.4V-1.77V: 插入4段式(有 Mic)耳机时的状态(AB = B01)或者4段式按键松开状态
// 0-0.4V : 插入3段式耳机时的状态,或者4段式按键按下时的状态(AB = B00)
// 按键判断电压:
// 【0v <= MD < 0.09V <= UP< 0.24V <= DW < 0.5V】
/////////////////////////////////////////////////////////////////////////////////
current_status = ((pmic_pwrap_read(ACCDET_STATE_RG) & 0xc0)>>6); //A=bit1; B=bit0
//////////////////////////////////////////////////////////////////////////////////
// 状态机转换:根据 AB 寄存器的值,来切换状态机,更新耳机状态,检测按键,上报按键
switch(accdet_status)
case PLUG_OUT:
///////////////////////////////////////////////////////////////////////
// 当前状态 AB = 00 : 插入3段式耳机时的状态,或者4段式按键按下时的状态(AB = B00)
if(current_status == 0)
// 如果有使能 ACCDET_PIN_RECOGNIZATION 的话,则一直打开 micbias 检测按键
// 否则检测是否有 accdet 中断发生,如果有过,则更新当前耳机状态,耳机没有 mic
////////////////////////////////////////////////////////////////////////
// 当前状态 AB = 01:插入4段式(有 Mic)耳机时的状态(AB = B01)或者4段式按键松开状态
else if(current_status == 1)
// 发生了 accdet 中断,插入的是 4 段是耳机,更新状态
if(1 == eint_accdet_sync_flag)
accdet_status = MIC_BIAS;
cable_type = HEADSET_MIC;
// 打开 micbias 偏置,用于检测按键,使能 mic, 具体录不录间,取决于上层
///////////////////////////////////////////////////////////////////////
// 当前状态 AB = 11: 未插入耳机的状态(AB = B11)
else if(current_status == 3)
// 发生了 accdet 中断,耳机状态有变化,更新状态
if(1 == eint_accdet_sync_flag)
accdet_status = PLUG_OUT;
cable_type = NO_DEVICE;
// 如果使用的是中断+Accdet 检测耳机,则关闭 Accdet 模块
disable_accdet();
case MIC_BIAS:
if(current_status == 0)
// 首先读取 PMIC 的 Accdet 模块寄存器,判断有没有按键
// 长按短按事件判断
multi_key = multi_key_detection();
// 判断按键,唤醒线程,上报按键,按键是根据 accdet 电压判断的
switch (multi_key)
case SHORT_UP: 。。。
case SHORT_MD: 。。。
case SHORT_DW: 。。。
// 短按
notify_sendKeyEvent(int event)
wake_up(&send_event_wq);
/////////////////////////////////////////////////////
// 延迟通过 input 输入设备上报事件类型
sendKeyEvent(void *unuse)
while(1)
wait_event_interruptible(send_event_wq, (atomic_read(&send_event_flag) != 0));
wake_lock_timeout(&accdet_key_lock, 2*HZ); //set the wake lock.
// 根据不同的键值,通过 input 输入设备上报给系统
input_report_key(kpd_accdet_dev, KEY_ENDCALL, 1);
input_report_key(kpd_accdet_dev, KEY_ENDCALL, 0);
input_sync(kpd_accdet_dev)
case LONG_UP: 。。。
case LONG_MD: 。。。
case LONG_DW: 。。。
// 长按事件立即上报
send_key_event(int keycode,int flag)
// 1. 打电话状态,上报 KEY_VOLUMEDOWN/KEY_VOLUMEUP
// 2. 非打电话状态,上报 KEY_NEXTSONG/KEY_PREVIOUSSONG
default: 。。。
else if(current_status == 1) 。。。
else if(current_status == 3) 。。。
case HOOK_SWITCH:
if(current_status == 0) 。。。
else if(current_status == 1) 。。。
else if(current_status == 3)。。。
case STAND_BY:
if(current_status == 3)。。。
/////////////////////////////////////////////////////////
// 切换 switch 模块的状态,如果 PMIC 的 ACCDET 发生中断话
if(1 == eint_accdet_sync_flag)
switch_set_state((struct switch_dev *)&accdet_data, cable_type);
///////////////////////////////////////////////////////////////////////////////////////////
// 6. 创建一个按键上报线程,用于按键上报
init_waitqueue_head(&send_event_wq);
//start send key event thread
keyEvent_thread = kthread_run(sendKeyEvent, 0, "keyEvent_send");
/////////////////////////////////////////////////////////////////////////////////////////////
// 7. 针对第一次启动,初始化 accdet 模块硬件,及注册 ap 的耳机中断函数,在 ap 耳机中断函数中
// 0. 变更耳机中断电平,保证插入/拔出都有中断
// 1. 如果是耳机插入,则创建一个定时器,用于耳机插入 6s 后,检测耳机是否有 mic 及按键,没
// 有则关闭 micbias。
// 2. 调用 accdet_eint_work_callback() 函数,用于打开/关闭 accdet 模块。
if (g_accdet_first == 1)
///////////////////////////////////////////////////////////////////////////////////////////
// 初始化 PMIC 的 accdet 模块硬件,主要通过 pmic_pwrap_write() 写寄存器值
accdet_init();
/////////////////////////////////////////////////////////////////////////////////
// 如果使用的是 accdet+中断 检测模式,则创建两个工作队列
queue_work(accdet_workqueue, &accdet_work); //schedule a work for the first detection
accdet_eint_workqueue = create_singlethread_workqueue("accdet_eint");
//////////////////////////////////////////////////
// 插/拔耳机发生中断时,打开/关闭 accdet 模块
INIT_WORK(&accdet_eint_work, accdet_eint_work_callback);
///////////////////////////////////////////////////////////////
// 在发生 ap 耳机中断时,调用的回调函数,打开/关闭 accdet 模块
accdet_eint_work_callback(struct work_struct *work)
mt_eint_mask(CUST_EINT_ACCDET_NUM);
if (cur_eint_state == EINT_PIN_PLUG_IN)
// 使能 accdet 模块
else
// 除能 accdet 模块
mt_eint_unmask(CUST_EINT_ACCDET_NUM);
///////////////////////////////////////////////
// 注册耳机检测的 ap 中断引脚状态及处理函数
accdet_setup_eint();
// 1. 设置引脚状态
mt_set_gpio_mode(GPIO_ACCDET_EINT_PIN, GPIO_ACCDET_EINT_PIN_M_EINT);
mt_set_gpio_dir(GPIO_ACCDET_EINT_PIN, GPIO_DIR_IN);
mt_set_gpio_pull_enable(GPIO_ACCDET_EINT_PIN, GPIO_PULL_DISABLE); //To disable GPIO PULL.
mt_eint_set_hw_debounce(CUST_EINT_ACCDET_NUM, CUST_EINT_ACCDET_DEBOUNCE_CN);
// 2. 注册耳机中断处理函数
mt_eint_registration(CUST_EINT_ACCDET_NUM, CUST_EINT_ACCDET_TYPE, accdet_eint_func, 0);
//////////////////////////////////////////////////////////////////////////
// 耳机 ap 中断处理函数
accdet_eint_func(void)
//////////////////////////////////////////////////////
// 1. 如果上次耳机状态是插入,那么这次就是拔出耳机了,
// 则需要变更中断触发电平,保证拔出插入都有中断发生
if(cur_eint_state == EINT_PIN_PLUG_IN )
// 变更中断引脚的触发电平,这样保证拔出,插入都能中断
if (CUST_EINT_ACCDET_TYPE == CUST_EINTF_TRIGGER_HIGH)
mt_eint_set_polarity(CUST_EINT_ACCDET_NUM, (1));
else
mt_eint_set_polarity(CUST_EINT_ACCDET_NUM, (0));
// update the eint status
cur_eint_state = EINT_PIN_PLUG_OUT;
else
// 同上, 首先变更中断电平
。。。
////////////////////////////////////////
// 创建一个定时器,用于检测,在耳机插入后,
// 如果检测到没有 mic 且没有按键,则关闭 micbias
init_timer(&micbias_timer);
micbias_timer.expires = jiffies + MICBIAS_DISABLE_TIMER;
micbias_timer.function = &disable_micbias;
micbias_timer.data = ((unsigned long) 0 );
add_timer(&micbias_timer);
////////////////////////////////////////////////////////////////////
// 2. 调用 accdet_eint_work_callback() 函数,打开 accdet 模块,用于
// 检测耳机类型,有无 mic, 以及耳机按键事件
ret = queue_work(accdet_eint_workqueue, &accdet_eint_work);
// 3. 打开中断
mt_eint_unmask(CUST_EINT_ACCDET_NUM);
accdet_disable_workqueue = create_singlethread_workqueue("accdet_disable");
///////////////////////////////////////////////
// 创建一个工作队列,用于在没有 mic 且没按键的情况下关闭 micbias
INIT_WORK(&accdet_disable_work, disable_micbias_callback);
//////////////////////////////////////////////////////////////
// 在上面的定时器函数中调用的,用于在特定情况下关闭 micbias 省电
disable_micbias_callback//(struct work_struct *work)
// 如果插入的耳机没有 mic ,则直接关闭 PMIC 的 ACCDET 模块
if(cable_type == HEADSET_NO_MIC)
disable_accdet();
else if(cable_type == HEADSET_MIC)
// 如果要检测键,则重新设置 pwm
*/
// accdet_drv.c
static struct platform_driver accdet_driver = { | //mt_devs.c
.probe = accdet_probe, | struct platform_device accdet_device = {
/* .suspend = accdet_suspend, */ | .name ="Accdet_Driver",
/* .resume = accdet_resume, */ | .id = -1,
.remove = accdet_remove, | //.dev ={
.driver = { | //.release = accdet_dumy_release,
.name = "Accdet_Driver", | //}
#ifdef CONFIG_PM | };
.pm = &accdet_pm_ops, |
#endif |
}, |
};
module_init(accdet_mod_init);
accdet_mod_init()
ret = platform_driver_register(&accdet_driver);
static int accdet_probe(struct platform_device *dev)
{
int ret = 0;
#if defined(ACCDET_TS3A225E_PIN_SWAP)
if (ts3a225e_i2c_client == NULL)
{
ACCDET_DEBUG("[Accdet]ts3a225e_i2c_client is NULL!\n");
return -EPROBE_DEFER;
}
#endif
#ifdef SW_WORK_AROUND_ACCDET_REMOTE_BUTTON_ISSUE
//struct task_struct *keyEvent_thread = NULL;
//int error=0;
#endif
#if DEBUG_THREAD
struct platform_driver accdet_driver_hal = accdet_driver_func();
#endif
struct headset_key_custom* press_key_time = get_headset_key_custom_setting();
ACCDET_DEBUG("[Accdet]accdet_probe begin!\n");
//------------------------------------------------------------------
// 1,注册一个 switch 设备 below register accdet as switch class
//------------------------------------------------------------------
accdet_data.name = "h2w";
accdet_data.index = 0;
accdet_data.state = NO_DEVICE;
cust_headset_settings = get_cust_headset_settings();
ret = switch_dev_register(&accdet_data);
if(ret)
{
ACCDET_DEBUG("[Accdet]switch_dev_register returned:%d!\n", ret);
return 1;
}
//------------------------------------------------------------------
// 2,创建一个设备节点 Create normal device for auido use
//------------------------------------------------------------------
ret = alloc_chrdev_region(&accdet_devno, 0, 1, ACCDET_DEVNAME);
if (ret)
{
ACCDET_DEBUG("[Accdet]alloc_chrdev_region: Get Major number error!\n");
}
accdet_cdev = cdev_alloc();
accdet_cdev->owner = THIS_MODULE;
accdet_cdev->ops = accdet_get_fops();
ret = cdev_add(accdet_cdev, accdet_devno, 1);
if(ret)
{
ACCDET_DEBUG("[Accdet]accdet error: cdev_add\n");
}
accdet_class = class_create(THIS_MODULE, ACCDET_DEVNAME);
// if we want auto creat device node, we must call this
accdet_nor_device = device_create(accdet_class, NULL, accdet_devno, NULL, ACCDET_DEVNAME);
//------------------------------------------------------------------
// 3. 输入设备 Create input device
//------------------------------------------------------------------
kpd_accdet_dev = input_allocate_device();
if (!kpd_accdet_dev)
{
ACCDET_DEBUG("[Accdet]kpd_accdet_dev : fail!\n");
return -ENOMEM;
}
//INIT the timer to disable micbias.
// 通过定时器每 6s 关闭 MICBIAS
init_timer(&micbias_timer);
micbias_timer.expires = jiffies + MICBIAS_DISABLE_TIMER;
micbias_timer.function = &disable_micbias;
disable_micbias//(unsigned long a)
{
int ret = 0;
ret = queue_work(accdet_disable_workqueue, &accdet_disable_work);
// INIT_WORK(&accdet_disable_work, disable_micbias_callback);
disable_micbias_callback//(struct work_struct *work)
{
if(cable_type == HEADSET_NO_MIC) {
#ifdef ACCDET_PIN_RECOGNIZATION
show_icon_delay = 0;
cable_pin_recognition = 0;
ACCDET_DEBUG("[Accdet] cable_pin_recognition = %d\n", cable_pin_recognition);
pmic_pwrap_write(ACCDET_PWM_WIDTH, cust_headset_settings->pwm_width);
pmic_pwrap_write(ACCDET_PWM_THRESH, cust_headset_settings->pwm_thresh);
#endif
// setting pwm idle;
pmic_pwrap_write(ACCDET_STATE_SWCTRL, pmic_pwrap_read(ACCDET_STATE_SWCTRL)&~ACCDET_SWCTRL_IDLE_EN);
#ifdef ACCDET_PIN_SWAP
//accdet_FSA8049_disable(); //disable GPIOxxx for PIN swap
//ACCDET_DEBUG("[Accdet] FSA8049 disable!\n");
#endif
disable_accdet();
disable_accdet//(void)
{
int irq_temp = 0;
//sync with accdet_irq_handler set clear accdet irq bit to avoid set clear accdet irq bit after disable accdet
//disable accdet irq
pmic_pwrap_write(INT_CON_ACCDET_CLR, RG_ACCDET_IRQ_CLR);
clear_accdet_interrupt();
udelay(200);
mutex_lock(&accdet_eint_irq_sync_mutex);
while(pmic_pwrap_read(ACCDET_IRQ_STS) & IRQ_STATUS_BIT)
{
ACCDET_DEBUG("[Accdet]check_cable_type: Clear interrupt on-going....\n");
msleep(5);
}
irq_temp = pmic_pwrap_read(ACCDET_IRQ_STS);
irq_temp = irq_temp & (~IRQ_CLR_BIT);
pmic_pwrap_write(ACCDET_IRQ_STS, irq_temp);
//ACCDET_DEBUG("[Accdet]disable_accdet:Clear interrupt:Done[0x%x]!\n", pmic_pwrap_read(ACCDET_IRQ_STS));
mutex_unlock(&accdet_eint_irq_sync_mutex);
// disable ACCDET unit
ACCDET_DEBUG("accdet: disable_accdet\n");
pre_state_swctrl = pmic_pwrap_read(ACCDET_STATE_SWCTRL);
#ifdef ACCDET_EINT
pmic_pwrap_write(ACCDET_STATE_SWCTRL, 0);
pmic_pwrap_write(ACCDET_CTRL, ACCDET_DISABLE);
//disable clock and Analog control
//mt6331_upmu_set_rg_audmicbias1vref(0x0);
pmic_pwrap_write(TOP_CKPDN_SET, RG_ACCDET_CLK_SET);
#endif
#ifdef ACCDET_EINT_IRQ
pmic_pwrap_write(ACCDET_STATE_SWCTRL, ACCDET_EINT_PWM_EN);
pmic_pwrap_write(ACCDET_CTRL, pmic_pwrap_read(ACCDET_CTRL)&(~(ACCDET_ENABLE)));
//mt_set_gpio_out(GPIO_CAMERA_2_CMRST_PIN, GPIO_OUT_ZERO);
#endif
}
ACCDET_DEBUG("[Accdet] more than 5s MICBIAS : Disabled\n");
}
#ifdef ACCDET_PIN_RECOGNIZATION
else if(cable_type == HEADSET_MIC) {
pmic_pwrap_write(ACCDET_PWM_WIDTH, cust_headset_settings->pwm_width);
pmic_pwrap_write(ACCDET_PWM_THRESH, cust_headset_settings->pwm_thresh);
ACCDET_DEBUG("[Accdet]pin recog after 5s recover micbias polling!\n");
}
#endif
}
if(!ret)
{
ACCDET_DEBUG("[Accdet]disable_micbias:accdet_work return:%d!\n", ret);
}
}
micbias_timer.data = ((unsigned long) 0 );
//define multi-key keycode
__set_bit(EV_KEY, kpd_accdet_dev->evbit);
__set_bit(KEY_CALL, kpd_accdet_dev->keybit);
__set_bit(KEY_ENDCALL, kpd_accdet_dev->keybit);
__set_bit(KEY_NEXTSONG, kpd_accdet_dev->keybit);
__set_bit(KEY_PREVIOUSSONG, kpd_accdet_dev->keybit);
__set_bit(KEY_PLAYPAUSE, kpd_accdet_dev->keybit);
__set_bit(KEY_STOPCD, kpd_accdet_dev->keybit);
__set_bit(KEY_VOLUMEDOWN, kpd_accdet_dev->keybit);
__set_bit(KEY_VOLUMEUP, kpd_accdet_dev->keybit);
__set_bit(KEY_VOICECOMMAND, kpd_accdet_dev->keybit);
kpd_accdet_dev->id.bustype = BUS_HOST;
kpd_accdet_dev->name = "ACCDET";
if(input_register_device(kpd_accdet_dev))
{
ACCDET_DEBUG("[Accdet]kpd_accdet_dev register : fail!\n");
}else
{
ACCDET_DEBUG("[Accdet]kpd_accdet_dev register : success!!\n");
}
//------------------------------------------------------------------
// Create workqueue
//------------------------------------------------------------------
accdet_workqueue = create_singlethread_workqueue("accdet");
INIT_WORK(&accdet_work, accdet_work_callback);
accdet_work_callback//(struct work_struct *work)
{
wake_lock(&accdet_irq_lock);
check_cable_type();
// 通过 PMIC 来识别插入
check_cable_type//(void)
{
int current_status = 0;
int irq_temp = 0; //for clear IRQ_bit
int wait_clear_irq_times = 0;
#ifdef ACCDET_PIN_RECOGNIZATION
int pin_adc_value = 0;
#define PIN_ADC_CHANNEL 5
#endif
current_status = ((pmic_pwrap_read(ACCDET_STATE_RG) & 0xc0)>>6); //A=bit1; B=bit0
ACCDET_DEBUG("[Accdet]accdet interrupt happen:[%s]current AB = %d\n",
accdet_status_string[accdet_status], current_status);
button_status = 0;
pre_status = accdet_status;
//ACCDET_DEBUG("[Accdet]check_cable_type: ACCDET_IRQ_STS = 0x%x\n", pmic_pwrap_read(ACCDET_IRQ_STS));
IRQ_CLR_FLAG = FALSE;
switch(accdet_status)
{
case PLUG_OUT:
#ifdef ACCDET_PIN_RECOGNIZATION
pmic_pwrap_write(ACCDET_DEBOUNCE1, cust_headset_settings->debounce1);
#endif
if(current_status == 0)
{
#ifdef ACCDET_PIN_RECOGNIZATION
//micbias always on during detected PIN recognition
pmic_pwrap_write(ACCDET_PWM_WIDTH, cust_headset_settings->pwm_width);
pmic_pwrap_write(ACCDET_PWM_THRESH, cust_headset_settings->pwm_width);
ACCDET_DEBUG("[Accdet]PIN recognition micbias always on!\n");
ACCDET_DEBUG("[Accdet]before adc read, pin_adc_value = %d mv!\n", pin_adc_value);
msleep(500);
current_status = ((pmic_pwrap_read(ACCDET_STATE_RG) & 0xc0)>>6); //A=bit1; B=bit0
if (current_status == 0 && show_icon_delay != 0)
{
//accdet_auxadc_switch(1);//switch on when need to use auxadc read voltage
pin_adc_value = Accdet_PMIC_IMM_GetOneChannelValue(1);
ACCDET_DEBUG("[Accdet]pin_adc_value = %d mv!\n", pin_adc_value);
//accdet_auxadc_switch(0);
if (180 > pin_adc_value && pin_adc_value> 90) //90mv ilegal headset
{
//mt_set_gpio_out(GPIO_CAMERA_2_CMRST_PIN, GPIO_OUT_ONE);
//ACCDET_DEBUG("[Accdet]PIN recognition change GPIO_OUT!\n");
mutex_lock(&accdet_eint_irq_sync_mutex);
if(1 == eint_accdet_sync_flag) {
cable_type = HEADSET_NO_MIC;
accdet_status = HOOK_SWITCH;
cable_pin_recognition = 1;
ACCDET_DEBUG("[Accdet] cable_pin_recognition = %d\n", cable_pin_recognition);
}else {
ACCDET_DEBUG("[Accdet] Headset has plugged out\n");
}
mutex_unlock(&accdet_eint_irq_sync_mutex);
}
else
{
mutex_lock(&accdet_eint_irq_sync_mutex);
if(1 == eint_accdet_sync_flag) {
cable_type = HEADSET_NO_MIC;
accdet_status = HOOK_SWITCH;
}else {
ACCDET_DEBUG("[Accdet] Headset has plugged out\n");
}
mutex_unlock(&accdet_eint_irq_sync_mutex);
}
}
#else
mutex_lock(&accdet_eint_irq_sync_mutex);
if(1 == eint_accdet_sync_flag) {
cable_type = HEADSET_NO_MIC;
accdet_status = HOOK_SWITCH;
}else {
ACCDET_DEBUG("[Accdet] Headset has plugged out\n");
}
mutex_unlock(&accdet_eint_irq_sync_mutex);
#endif
}
else if(current_status == 1)
{
mutex_lock(&accdet_eint_irq_sync_mutex);
if(1 == eint_accdet_sync_flag) {
accdet_status = MIC_BIAS;
cable_type = HEADSET_MIC;
pmic_pwrap_write(ACCDET_DEBOUNCE3, cust_headset_settings->debounce3*30);//AB=11 debounce=30ms
}else {
ACCDET_DEBUG("[Accdet] Headset has plugged out\n");
}
mutex_unlock(&accdet_eint_irq_sync_mutex);
//ALPS00038030:reduce the time of remote button pressed during incoming call
//solution: reduce hook switch debounce time to 0x400
pmic_pwrap_write(ACCDET_DEBOUNCE0, button_press_debounce);
//recover polling set AB 00-01
#ifdef ACCDET_PIN_RECOGNIZATION
pmic_pwrap_write(ACCDET_PWM_WIDTH, REGISTER_VALUE(cust_headset_settings->pwm_width));
pmic_pwrap_write(ACCDET_PWM_THRESH, REGISTER_VALUE(cust_headset_settings->pwm_thresh));
#endif
//#ifdef ACCDET_LOW_POWER
//wake_unlock(&accdet_timer_lock);//add for suspend disable accdet more than 5S
//#endif
}
else if(current_status == 3)
{
ACCDET_DEBUG("[Accdet]PLUG_OUT state not change!\n");
#ifdef ACCDET_EINT
ACCDET_DEBUG("[Accdet] do not send plug out event in plug out\n");
#else
mutex_lock(&accdet_eint_irq_sync_mutex);
if(1 == eint_accdet_sync_flag) {
accdet_status = PLUG_OUT;
cable_type = NO_DEVICE;
}else {
ACCDET_DEBUG("[Accdet] Headset has plugged out\n");
}
mutex_unlock(&accdet_eint_irq_sync_mutex);
#endif
}
else
{
ACCDET_DEBUG("[Accdet]PLUG_OUT can't change to this state!\n");
}
break;
case MIC_BIAS:
//ALPS00038030:reduce the time of remote button pressed during incoming call
//solution: resume hook switch debounce time
pmic_pwrap_write(ACCDET_DEBOUNCE0, cust_headset_settings->debounce0);
if(current_status == 0)
{
mutex_lock(&accdet_eint_irq_sync_mutex);
if(1 == eint_accdet_sync_flag) {
while((pmic_pwrap_read(ACCDET_IRQ_STS) & IRQ_STATUS_BIT) && (wait_clear_irq_times<3))
{
ACCDET_DEBUG("[Accdet]check_cable_type: MIC BIAS clear IRQ on-going1....\n");
wait_clear_irq_times++;
msleep(5);
}
irq_temp = pmic_pwrap_read(ACCDET_IRQ_STS);
irq_temp = irq_temp & (~IRQ_CLR_BIT);
pmic_pwrap_write(ACCDET_IRQ_STS, irq_temp);
IRQ_CLR_FLAG = TRUE;
accdet_status = HOOK_SWITCH;
}else {
ACCDET_DEBUG("[Accdet] Headset has plugged out\n");
}
mutex_unlock(&accdet_eint_irq_sync_mutex);
button_status = 1;
if(button_status)
{
mutex_lock(&accdet_eint_irq_sync_mutex);
if(1 == eint_accdet_sync_flag) {
multi_key_detection(current_status);
}else {
ACCDET_DEBUG("[Accdet] multi_key_detection: Headset has plugged out\n");
}
mutex_unlock(&accdet_eint_irq_sync_mutex);
//accdet_auxadc_switch(0);
//recover pwm frequency and duty
pmic_pwrap_write(ACCDET_PWM_WIDTH, REGISTER_VALUE(cust_headset_settings->pwm_width));
pmic_pwrap_write(ACCDET_PWM_THRESH, REGISTER_VALUE(cust_headset_settings->pwm_thresh));
}
}
else if(current_status == 1)
{
mutex_lock(&accdet_eint_irq_sync_mutex);
if(1 == eint_accdet_sync_flag) {
accdet_status = MIC_BIAS;
cable_type = HEADSET_MIC;
ACCDET_DEBUG("[Accdet]MIC_BIAS state not change!\n");
}else {
ACCDET_DEBUG("[Accdet] Headset has plugged out\n");
}
mutex_unlock(&accdet_eint_irq_sync_mutex);
}
else if(current_status == 3)
{
#if defined ACCDET_EINT || defined ACCDET_EINT_IRQ
ACCDET_DEBUG("[Accdet]do not send plug ou in micbiast\n");
mutex_lock(&accdet_eint_irq_sync_mutex);
if(1 == eint_accdet_sync_flag) {
accdet_status = PLUG_OUT;
}else {
ACCDET_DEBUG("[Accdet] Headset has plugged out\n");
}
mutex_unlock(&accdet_eint_irq_sync_mutex);
#else
mutex_lock(&accdet_eint_irq_sync_mutex);
if(1 == eint_accdet_sync_flag) {
accdet_status = PLUG_OUT;
cable_type = NO_DEVICE;
}else {
ACCDET_DEBUG("[Accdet] Headset has plugged out\n");
}
mutex_unlock(&accdet_eint_irq_sync_mutex);
#endif
}
else
{
ACCDET_DEBUG("[Accdet]MIC_BIAS can't change to this state!\n");
}
break;
case HOOK_SWITCH:
if(current_status == 0)
{
mutex_lock(&accdet_eint_irq_sync_mutex);
if(1 == eint_accdet_sync_flag) {
//for avoid 01->00 framework of Headset will report press key info for Audio
//cable_type = HEADSET_NO_MIC;
//accdet_status = HOOK_SWITCH;
ACCDET_DEBUG("[Accdet]HOOK_SWITCH state not change!\n");
}else {
ACCDET_DEBUG("[Accdet] Headset has plugged out\n");
}
mutex_unlock(&accdet_eint_irq_sync_mutex);
}
else if(current_status == 1)
{
mutex_lock(&accdet_eint_irq_sync_mutex);
if(1 == eint_accdet_sync_flag) {
multi_key_detection(current_status);
accdet_status = MIC_BIAS;
cable_type = HEADSET_MIC;
}else {
ACCDET_DEBUG("[Accdet] Headset has plugged out\n");
}
mutex_unlock(&accdet_eint_irq_sync_mutex);
//accdet_auxadc_switch(0);
#ifdef ACCDET_PIN_RECOGNIZATION
cable_pin_recognition = 0;
ACCDET_DEBUG("[Accdet] cable_pin_recognition = %d\n", cable_pin_recognition);
pmic_pwrap_write(ACCDET_PWM_WIDTH, REGISTER_VALUE(cust_headset_settings->pwm_width));
pmic_pwrap_write(ACCDET_PWM_THRESH, REGISTER_VALUE(cust_headset_settings->pwm_thresh));
#endif
//ALPS00038030:reduce the time of remote button pressed during incoming call
//solution: reduce hook switch debounce time to 0x400
pmic_pwrap_write(ACCDET_DEBOUNCE0, button_press_debounce);
//#ifdef ACCDET_LOW_POWER
//wake_unlock(&accdet_timer_lock);//add for suspend disable accdet more than 5S
//#endif
}
else if(current_status == 3)
{
#ifdef ACCDET_PIN_RECOGNIZATION
cable_pin_recognition = 0;
ACCDET_DEBUG("[Accdet] cable_pin_recognition = %d\n", cable_pin_recognition);
mutex_lock(&accdet_eint_irq_sync_mutex);
if(1 == eint_accdet_sync_flag) {
accdet_status = PLUG_OUT;
}else {
ACCDET_DEBUG("[Accdet] Headset has plugged out\n");
}
mutex_unlock(&accdet_eint_irq_sync_mutex);
#endif
#if defined ACCDET_EINT || defined ACCDET_EINT_IRQ
ACCDET_DEBUG("[Accdet] do not send plug out event in hook switch\n");
mutex_lock(&accdet_eint_irq_sync_mutex);
if(1 == eint_accdet_sync_flag) {
accdet_status = PLUG_OUT;
}else {
ACCDET_DEBUG("[Accdet] Headset has plugged out\n");
}
mutex_unlock(&accdet_eint_irq_sync_mutex);
#else
mutex_lock(&accdet_eint_irq_sync_mutex);
if(1 == eint_accdet_sync_flag) {
accdet_status = PLUG_OUT;
cable_type = NO_DEVICE;
}else {
ACCDET_DEBUG("[Accdet] Headset has plugged out\n");
}
mutex_unlock(&accdet_eint_irq_sync_mutex);
#endif
}
else
{
ACCDET_DEBUG("[Accdet]HOOK_SWITCH can't change to this state!\n");
}
break;
case STAND_BY:
if(current_status == 3)
{
#if defined ACCDET_EINT || defined ACCDET_EINT_IRQ
ACCDET_DEBUG("[Accdet]accdet do not send plug out event in stand by!\n");
#else
mutex_lock(&accdet_eint_irq_sync_mutex);
if(1 == eint_accdet_sync_flag) {
accdet_status = PLUG_OUT;
cable_type = NO_DEVICE;
}else {
ACCDET_DEBUG("[Accdet] Headset has plugged out\n");
}
mutex_unlock(&accdet_eint_irq_sync_mutex);
#endif
}
else
{
ACCDET_DEBUG("[Accdet]STAND_BY can't change to this state!\n");
}
break;
default:
ACCDET_DEBUG("[Accdet]check_cable_type: accdet current status error!\n");
break;
}
if(!IRQ_CLR_FLAG)
{
mutex_lock(&accdet_eint_irq_sync_mutex);
if(1 == eint_accdet_sync_flag) {
while((pmic_pwrap_read(ACCDET_IRQ_STS) & IRQ_STATUS_BIT) && (wait_clear_irq_times<3))
{
ACCDET_DEBUG("[Accdet]check_cable_type: Clear interrupt on-going2....\n");
wait_clear_irq_times++;
msleep(5);
}
}
irq_temp = pmic_pwrap_read(ACCDET_IRQ_STS);
irq_temp = irq_temp & (~IRQ_CLR_BIT);
pmic_pwrap_write(ACCDET_IRQ_STS, irq_temp);
mutex_unlock(&accdet_eint_irq_sync_mutex);
IRQ_CLR_FLAG = TRUE;
//ACCDET_DEBUG("[Accdet]check_cable_type:Clear interrupt:Done[0x%x]!\n", pmic_pwrap_read(ACCDET_IRQ_STS));
}
else
{
IRQ_CLR_FLAG = FALSE;
}
ACCDET_DEBUG("[Accdet]cable type:[%s], status switch:[%s]->[%s]\n",
accdet_report_string[cable_type], accdet_status_string[pre_status],
accdet_status_string[accdet_status]);
}
#ifdef ACCDET_PIN_SWAP
#ifdef ACCDET_PIN_RECOGNIZATION
if (cable_pin_recognition == 1)
{
cable_pin_recognition = 0;
accdet_FSA8049_disable();
cable_type = HEADSET_NO_MIC;
accdet_status = PLUG_OUT;
}
#endif
#endif
mutex_lock(&accdet_eint_irq_sync_mutex);
if(1 == eint_accdet_sync_flag) {
switch_set_state((struct switch_dev *)&accdet_data, cable_type);
}else {
ACCDET_DEBUG("[Accdet] Headset has plugged out don't set accdet state\n");
}
mutex_unlock(&accdet_eint_irq_sync_mutex);
ACCDET_DEBUG( " [accdet] set state in cable_type status\n");
wake_unlock(&accdet_irq_lock);
}
//------------------------------------------------------------------
// wake lock
//------------------------------------------------------------------
wake_lock_init(&accdet_suspend_lock, WAKE_LOCK_SUSPEND, "accdet wakelock");
wake_lock_init(&accdet_irq_lock, WAKE_LOCK_SUSPEND, "accdet irq wakelock");
wake_lock_init(&accdet_key_lock, WAKE_LOCK_SUSPEND, "accdet key wakelock");
wake_lock_init(&accdet_timer_lock, WAKE_LOCK_SUSPEND, "accdet timer wakelock");
#if DEBUG_THREAD
if((ret = accdet_create_attr(&accdet_driver_hal.driver))!=0)
{
ACCDET_DEBUG("create attribute err = %d\n", ret);
}
#endif
pmic_register_interrupt_callback(12,accdet_int_handler); //PMIC ACCDET_EINT 中断处理函数
pmic_register_interrupt_callback(13,accdet_eint_int_handler); //PMIC ACCDET_NEGV 中断处理函数
long_press_time = press_key_time->headset_long_press_time;
ACCDET_DEBUG("[Accdet]accdet_probe : ACCDET_INIT\n");
// 只在第一次运行初始化
if (g_accdet_first == 1)
{
long_press_time_ns = (s64)long_press_time * NSEC_PER_MSEC;
eint_accdet_sync_flag = 1;
#ifdef ACCDET_EINT_IRQ
accdet_eint_workqueue = create_singlethread_workqueue("accdet_eint");
INIT_WORK(&accdet_eint_work, accdet_eint_work_callback);
accdet_disable_workqueue = create_singlethread_workqueue("accdet_disable");
INIT_WORK(&accdet_disable_work, disable_micbias_callback);
#endif
//Accdet Hardware Init
accdet_init();
accdet_pmic_Read_Efuse_HPOffset();
//INIT_WORK(&accdet_work, accdet_work_callback);
queue_work(accdet_workqueue, &accdet_work); //schedule a work for the first detection
#ifdef ACCDET_EINT
accdet_disable_workqueue = create_singlethread_workqueue("accdet_disable");
INIT_WORK(&accdet_disable_work, disable_micbias_callback);
accdet_eint_workqueue = create_singlethread_workqueue("accdet_eint");
INIT_WORK(&accdet_eint_work, accdet_eint_work_callback);
// AP 中断设置
accdet_setup_eint();
accdet_setup_eint//(void)
{
int ret;
#ifdef CONFIG_OF
u32 ints[2]={0,0};
struct device_node *node;
#endif
/*configure to GPIO function, external interrupt*/
ACCDET_DEBUG("[Accdet]accdet_setup_eint\n");
mt_set_gpio_mode(GPIO_ACCDET_EINT_PIN, GPIO_ACCDET_EINT_PIN_M_EINT);
mt_set_gpio_dir(GPIO_ACCDET_EINT_PIN, GPIO_DIR_IN);
mt_set_gpio_pull_enable(GPIO_ACCDET_EINT_PIN, GPIO_PULL_DISABLE); //To disable GPIO PULL.
#ifdef CONFIG_OF
node = of_find_compatible_node(NULL,NULL,"mediatek, ACCDET-eint");
if(node) {
of_property_read_u32_array(node,"debounce",ints,ARRAY_SIZE(ints));
gpiopin = ints[0];
headsetdebounce = ints[1];
mt_gpio_set_debounce(gpiopin,headsetdebounce);
accdet_irq = irq_of_parse_and_map(node,0);
ret = request_irq(accdet_irq,accdet_eint_func,IRQF_TRIGGER_NONE,"ACCDET-eint",NULL);
if(ret>0){
ACCDET_DEBUG("[Accdet]EINT IRQ LINE NOT AVAILABLE\n");
}else{
ACCDET_DEBUG("[Accdet]accdet set EINT finished, accdet_irq=%d, headsetdebounce=%d \n", accdet_irq, headsetdebounce);
}
}
else {
ACCDET_DEBUG("[Accdet]%s can't find compatible node\n", __func__);
}
#else
mt_eint_set_hw_debounce(CUST_EINT_ACCDET_NUM, CUST_EINT_ACCDET_DEBOUNCE_CN);
mt_eint_registration(CUST_EINT_ACCDET_NUM, CUST_EINT_ACCDET_TYPE, accdet_eint_func, 0);
ACCDET_DEBUG("[Accdet]accdet set EINT finished, accdet_eint_num=%d, accdet_eint_debounce_en=%d, accdet_eint_polarity=%d\n", CUST_EINT_ACCDET_NUM, CUST_EINT_ACCDET_DEBOUNCE_EN, CUST_EINT_ACCDET_TYPE);
mt_eint_unmask(CUST_EINT_ACCDET_NUM);
#endif
return 0;
}
#endif
g_accdet_first = 0;
}
ACCDET_DEBUG("[Accdet]accdet_probe done!\n");
//#ifdef ACCDET_PIN_SWAP
//pmic_pwrap_write(0x0400, 0x1000);
//ACCDET_DEBUG("[Accdet]accdet enable VRF28 power!\n");
//#endif
return 0;
}
{
//accdet.c
return mt_accdet_probe();
cust_headset_settings = get_cust_headset_settings();
accdet_data.name = "h2w";
accdet_data.index = 0;
accdet_data.state = NO_DEVICE;
ret = switch_dev_register(&accdet_data);
//------------------------------------------------------------------
// Create normal device for auido use
//------------------------------------------------------------------
ret = alloc_chrdev_region(&accdet_devno, 0, 1, ACCDET_DEVNAME);
if (ret)
{
ACCDET_DEBUG("[Accdet]alloc_chrdev_region: Get Major number error!\n");
}
accdet_cdev = cdev_alloc();
accdet_cdev->owner = THIS_MODULE;
accdet_cdev->ops = accdet_get_fops();
ret = cdev_add(accdet_cdev, accdet_devno, 1);
if(ret)
{
ACCDET_DEBUG("[Accdet]accdet error: cdev_add\n");
}
accdet_class = class_create(THIS_MODULE, ACCDET_DEVNAME);
// if we want auto creat device node, we must call this
accdet_nor_device = device_create(accdet_class, NULL, accdet_devno, NULL, ACCDET_DEVNAME);
//------------------------------------------------------------------
// Create input device
//------------------------------------------------------------------
kpd_accdet_dev = input_allocate_device();
if (!kpd_accdet_dev)
{
ACCDET_DEBUG("[Accdet]kpd_accdet_dev : fail!\n");
return -ENOMEM;
}
//INIT the timer to disable micbias.
init_timer(&micbias_timer);
micbias_timer.expires = jiffies + MICBIAS_DISABLE_TIMER;
micbias_timer.function = &disable_micbias;
micbias_timer.data = ((unsigned long) 0 );
//define multi-key keycode
__set_bit(EV_KEY, kpd_accdet_dev->evbit);
__set_bit(KEY_CALL, kpd_accdet_dev->keybit);
__set_bit(KEY_ENDCALL, kpd_accdet_dev->keybit);
__set_bit(KEY_NEXTSONG, kpd_accdet_dev->keybit);
__set_bit(KEY_PREVIOUSSONG, kpd_accdet_dev->keybit);
__set_bit(KEY_PLAYPAUSE, kpd_accdet_dev->keybit);
__set_bit(KEY_STOPCD, kpd_accdet_dev->keybit);
__set_bit(KEY_VOLUMEDOWN, kpd_accdet_dev->keybit);
__set_bit(KEY_VOLUMEUP, kpd_accdet_dev->keybit);
__set_bit(KEY_VOICECOMMAND, kpd_accdet_dev->keybit);
kpd_accdet_dev->id.bustype = BUS_HOST;
kpd_accdet_dev->name = "ACCDET";
if(input_register_device(kpd_accdet_dev))
{
ACCDET_DEBUG("[Accdet]kpd_accdet_dev register : fail!\n");
}else
{
ACCDET_DEBUG("[Accdet]kpd_accdet_dev register : success!!\n");
}
//INIT the timer to disable micbias.
// 通过定时器每 6s 关闭 MICBIAS
init_timer(&micbias_timer);
micbias_timer.expires = jiffies + MICBIAS_DISABLE_TIMER;
micbias_timer.function = &disable_micbias;
ret = queue_work(accdet_disable_workqueue, &accdet_disable_work);
disable_micbias_callback()
disable_accdet();
//sync with accdet_irq_handler set clear accdet irq bit to avoid set clear accdet irq bit after disable accdet
//disable accdet irq
clear_accdet_interrupt();
// 关闭 ACCDET
#ifdef ACCDET_EINT
pmic_pwrap_write(ACCDET_STATE_SWCTRL, 0);
// disables PWM of ACCDET comparator
pmic_pwrap_write(ACCDET_CTRL, ACCDET_DISABLE);
//disable clock and Analog control
//mt6331_upmu_set_rg_audmicbias1vref(0x0);
pmic_pwrap_write(TOP_CKPDN_SET, RG_ACCDET_CLK_SET);
#endif
accdet_workqueue = create_singlethread_workqueue("accdet");
INIT_WORK(&accdet_work, accdet_work_callback);
pmic_register_interrupt_callback(12,accdet_int_handler); //PMIC ACCDET_EINT 中断处理函数
pmic_register_interrupt_callback(13,accdet_eint_int_handler); //PMIC ACCDET_NEGV 中断处理函数
// 只在第一次运行初始化
if (g_accdet_first == 1)
{
eint_accdet_sync_flag = 1;
// Accdet Hardware Init
accdet_init();
// disable ACCDET unit
pre_state_swctrl = pmic_pwrap_read(ACCDET_STATE_SWCTRL);
pmic_pwrap_write(ACCDET_CTRL, ACCDET_DISABLE);
pmic_pwrap_write(ACCDET_STATE_SWCTRL, 0x0);
pmic_pwrap_write(TOP_CKPDN_SET, RG_ACCDET_CLK_SET);
queue_work(accdet_workqueue, &accdet_work); //schedule a work for the first detection
// 应该只执行一次
accdet_work_callback()
check_cable_type();
accdet_disable_workqueue = create_singlethread_workqueue("accdet_disable");
INIT_WORK(&accdet_disable_work, disable_micbias_callback); // 跟定时器一样的函数
accdet_eint_workqueue = create_singlethread_workqueue("accdet_eint");
INIT_WORK(&accdet_eint_work, accdet_eint_work_callback);
// AP 中断设置
accdet_setup_eint();
/*configure to GPIO function, external interrupt*/
ACCDET_DEBUG("[Accdet]accdet_setup_eint\n");
mt_set_gpio_mode(GPIO_ACCDET_EINT_PIN, GPIO_ACCDET_EINT_PIN_M_EINT);
mt_set_gpio_dir(GPIO_ACCDET_EINT_PIN, GPIO_DIR_IN);
mt_set_gpio_pull_enable(GPIO_ACCDET_EINT_PIN, GPIO_PULL_DISABLE); //To disable GPIO PULL.
mt_eint_set_hw_debounce(CUST_EINT_ACCDET_NUM, CUST_EINT_ACCDET_DEBOUNCE_CN);
// 设置 AP 中断处理函数
mt_eint_registration(CUST_EINT_ACCDET_NUM, CUST_EINT_ACCDET_TYPE, accdet_eint_func, 0);
accdet_eint_func()
if(cur_eint_state == EINT_PIN_PLUG_IN )
{
cur_eint_state = EINT_PIN_PLUG_OUT;
}
else
{
cur_eint_state = EINT_PIN_PLUG_IN;
mod_timer(&micbias_timer, jiffies + MICBIAS_DISABLE_TIMER);
}
ret = queue_work(accdet_eint_workqueue, &accdet_eint_work);
accdet_eint_work_callback()
if (cur_eint_state == EINT_PIN_PLUG_IN)
{
accdet_init();// do set pwm_idle on in accdet_init
//set PWM IDLE on
// 此处使能 MICBIAS ?
pmic_pwrap_write(ACCDET_STATE_SWCTRL, (pmic_pwrap_read(ACCDET_STATE_SWCTRL)|ACCDET_SWCTRL_IDLE_EN));
//enable ACCDET unit
enable_accdet(ACCDET_SWCTRL_EN);
}
else
{
disable_accdet();
headset_plug_out();
accdet_status = PLUG_OUT;
cable_type = NO_DEVICE;
}
// 再次使能 AP 中断
mt_eint_unmask(CUST_EINT_ACCDET_NUM);
// 使能 AP 中断
mt_eint_unmask(CUST_EINT_ACCDET_NUM);
g_accdet_first = 0;
}
}
// AP 中断使能 MICBIAS 之后,会走 Accdet 检测,PMIC 会产生中断,调用中断函数
accdet_int_handler()
accdet_irq_handler()
if((pmic_pwrap_read(ACCDET_IRQ_STS) & IRQ_STATUS_BIT)) {
//clear ACCDET IRQ in accdet register
clear_accdet_interrupt();
}
if (accdet_status == MIC_BIAS){
//accdet_auxadc_switch(1);
pmic_pwrap_write(ACCDET_PWM_WIDTH, REGISTER_VALUE(cust_headset_settings->pwm_width));
pmic_pwrap_write(ACCDET_PWM_THRESH, REGISTER_VALUE(cust_headset_settings->pwm_width));
}
accdet_workqueue_func();
while(((pmic_pwrap_read(ACCDET_IRQ_STS) & IRQ_STATUS_BIT) &&
(accdet_timeout_ns(cur_time, ACCDET_TIME_OUT)))) {
}