MT6357的耳机插入过程中accdet机制及代码分析
文章目录前言一、设备树及原理图二、accdet机制三、mt6357-accdet.c 代码分析3.1 mtk_accdet_irq_handler_thread代码分析3.2 eint_work_callback分析3.3 accdet_work_callback3.4 dis_micbias_timerhandler3.5 dis_micbias_work_callback3.6 delay_init_timerhandler和delay_init_work_callback如有错误请指正谢谢前言有关mt6357的accdet相关的一些mode及一些配置的设置我这里还不是很清楚只能先按照代码简单的分析如涉及到寄存器相关的修改还需要仔细斟酌。一、设备树及原理图mt6357.dtsipmic_accdet:pmic_accdet{compatiblemediatek,mt6357-accdet;accdet-namemt63xx-accdet;accdet-mic-vol6;accdet-plugout-debounce1;accdet-mic-mode1;headset-mode-setting0x5000x50010x1f00x8000x8000x200x44;headset-eint-level-pol4;headset-use-ap-eint0;headset-eint-num0;headset-eint-trig-mode0;headset-key-mode0;headset-three-key-threshold080220400;headset-three-key-threshold-CDD0121192600;headset-four-key-threshold058121192400;io-channelspmic_auxadc AUXADC_ACCDET;io-channel-namespmic_accdet;nvmempmic_efuse;nvmem-namesmt63xx-accdet-efuse;statusokay;};原理图如下注意红框里的两个电阻需要去除不然插入4段耳机micbias1打开accdet也不会得到约0.7V的分压即AB 比较器会一直是00 而不是01即不会检测到4段耳机。二、accdet机制三、mt6357-accdet.c 代码分析probe函数staticintaccdet_probe(structplatform_device*pdev){/* register pmic interrupt *///这个中断是当耳机插入后不管三段还是四段耳机都会触发后续会中断分析mtk_accdet_irq_handler_thread这个中断函数retdevm_request_threaded_irq(pdev-dev,accdet-accdet_irq/*accdet-accdet_eint0、accdet-accdet_eint1*/,NULL,mtk_accdet_irq_handler_thread,IRQF_TRIGGER_HIGH|IRQF_ONESHOT,ACCDET_IRQ,accdet);/* setup timer 这个是插入耳机后开启micbias电压(约2.5V)micbias定时6s是否要关闭的定时器中断*/timer_setup(micbias_timer,dis_micbias_timerhandler,0);micbias_timer.expiresjiffiesMICBIAS_DISABLE_TIMER;//这个定时器执行的delay_init_timerhandler里面主要是对一些配置进行初始化如micbias的输出电压设置timer_setup(accdet_init_timer,delay_init_timerhandler,0);accdet_init_timer.expiresjiffiesACCDET_INIT_WAIT_TIMER;//accdet_work_callback这个func后面会详细分析主要是对3段还是4段耳机的判断具体是查看AB比较INIT_WORK(accdet-accdet_work,accdet_work_callback);//dis_micbias_work_callback这个func是micbias关闭的具体函数上面定时器到时会对这个线程func进行唤醒INIT_WORK(accdet-dis_micbias_work,dis_micbias_work_callback);//这个是耳机的插入拔出检测后面会进行分析INIT_WORK(accdet-eint_work,eint_work_callback);}根据上述probe函数我们列出了一些我们感兴趣的函数mtk_accdet_irq_handler_thread3.1eint_work_callback3.2accdet_work_callback3.3dis_micbias_timerhandler3.4dis_micbias_work_callback3.5delay_init_timerhandler3.6这个不是重点如果需要修改初始化的内容需要改动到这些地方3.1 mtk_accdet_irq_handler_thread代码分析插入耳机后不论三段还是四段耳机会触发这个中断staticirqreturn_tmtk_accdet_irq_handler_thread(intirq,void*data){//直接分析这个accdet_irq_handle();returnIRQ_HANDLED;}voidaccdet_irq_handle(void){u32 eintID0;u32 irq_status0,acc_sts0,eint_sts0;unsignedintmoisture_vol0;//下面这些是获取一些状态eintIDget_triggered_eint();irq_statusaccdet_read(ACCDET_IRQ_ADDR);acc_stsaccdet_read(ACCDET_MEM_IN_ADDR);eint_stsaccdet_read(ACCDET_EINT0_MEM_IN_ADDR);if((irq_statusACCDET_IRQ_MASK_SFT)(eintID0)){printk(%s zzh \n,__func__);clear_accdet_int();//accdet_queue_work这个函数很重要//主要是会将accdet_work_callback函数列入工作队列//详细分析见3.3//accdet_work_callback这个func主要是判断是通过AB判断 是3段耳机 还是4段耳机 然后上报给Android系统是否带麦的图标就是这里触发的accdet_queue_work();clear_accdet_int_check();}elseif(eintID!NO_PMIC_EINT){//一般会先走这个中断pr_info(%s() zzh IRQ:0x%x, eint-%s trig. cur_eint_state:%d\n,__func__,irq_status,(eintIDPMIC_EINT0)?0:((eintIDPMIC_EINT1)?1:BI),accdet-cur_eint_state);/* check EINT0 status */accdet-eint_idaccdet_read_bits(ACCDET_EINT0_MEM_IN_ADDR,ACCDET_EINT0_MEM_IN_SFT,ACCDET_EINT0_MEM_IN_MASK);eint_polarity_reverse(eintID);clear_accdet_eint(eintID);clear_accdet_eint_check(eintID);//然后会执行到这个func触发pmic_eint_queue_work(eintID);}else{pr_notice(%s no interrupt detected!\n,__func__);}}staticintpmic_eint_queue_work(inteintID){intret0;if(HAS_CAP(accdet-data-caps,ACCDET_PMIC_EINT0)){if(eintIDPMIC_EINT0){if(accdet-cur_eint_stateEINT_PLUG_IN){accdet_set_debounce(eint_state000,ACCDET_EINT0_DEB_IN_256);accdet_set_debounce(accdet_state011,cust_pwm_deb-debounce3);accdet-cur_eint_stateEINT_PLUG_OUT;}else{accdet_set_debounce(eint_state000,ACCDET_EINT0_DEB_OUT_012);if(accdet-eint_id!M_PLUG_OUT){//插入会走这里这个状态会被改变为EINT_PLUG_INaccdet-cur_eint_stateEINT_PLUG_IN;//这个就是开启了micbias电压的定时器定时6smod_timer(micbias_timer,jiffiesMICBIAS_DISABLE_TIMER);}}//这里就会将eint_work_callback函数排入工作队列具体这一段做了什么见3.2retqueue_work(accdet-eint_workqueue,accdet-eint_work);}elsepr_notice(%s invalid EINT ID!\n,__func__);}//还有一些其他类似的判断就不看了这里只看核心的部分。。。returnret;}3.2 eint_work_callback分析staticvoideint_work_callback(structwork_struct*work){if(accdet-cur_eint_stateEINT_PLUG_IN){//耳机插入就走这个判断mutex_lock(accdet-res_lock);//这个标志位应该是处理事件的标志位在多个线程中都会有使用accdet-eint_sync_flagtrue;mutex_unlock(accdet-res_lock);__pm_wakeup_event(accdet-timer_lock,jiffies_to_msecs(7*HZ));printk(%s zzh EINT_PLUG_IN\n,__func__);//这个初始化应该是一些范围值的初始化accdet_init();...enable_accdet(0);}else{//耳机拔出就走这个判断printk(%s zzh EINT_PLUG_OUT\n,__func__);mutex_lock(accdet-res_lock);accdet-eint_sync_flagfalse;accdet-thing_in_flagfalse;mutex_unlock(accdet-res_lock);del_timer_sync(micbias_timer);/* disable accdet_sw_en0 */accdet_clear_bits(ACCDET_CMP_PWM_IDLE_ADDR,ACCDET_CMP_PWM_IDLE_SFT,0x7,0x7);disable_accdet();//这个会上报一个事件给到Androidheadset_plug_out();//这个是修改极性的函数详细见极性相关的部分accdet_for_plug_highlow();}if(HAS_CAP(accdet-data-caps,ACCDET_AP_GPIO_EINT))enable_irq(accdet-gpioirq);}总的来说这个工作函数主要是做一些耳机插入初始化和耳机拔出上报Android系统层的工作3.3 accdet_work_callbackstaticvoidaccdet_work_callback(structwork_struct*work){//获取先前的cable 类型u32 pre_cable_typeaccdet-cable_type;__pm_stay_awake(accdet-wake_lock);//这个func会对耳机的类型进行判断check_cable_type();mutex_lock(accdet-res_lock);if(accdet-eint_sync_flag){if(pre_cable_type!accdet-cable_type){printk(%s zzh pre_cable_type ! accdet-cable_type \n,__func__);//这个就是上报耳机是否带麦的事件具体看if里的判断//同时如果检测到是带耳机的事件HEADSET_MIC 1会把micbias的disable定时器给关掉send_status_event(accdet-cable_type,1);}else{printk(%s zzh pre_cable_type accdet-cable_type \n,__func__);}}mutex_unlock(accdet-res_lock);__pm_relax(accdet-wake_lock);}/* * 关于三四段耳机的插入判断主要是在这个func里进行判断重要 * 如果是三段耳机这个函数会执行一次加上之前的总共触发两次如果是4段耳机这个函数会执行两次中断加上之前的总共触发3次 */staticinlinevoidcheck_cable_type(void){u32 cur_AB0;cur_ABaccdet_read(ACCDET_MEM_IN_ADDR)ACCDET_STATE_MEM_IN_OFFSET;cur_ABcur_ABACCDET_STATE_AB_MASK;accdet-button_status0;printk(%s zzh accdet-accdet_status %d, cur_AB 0x%x, eint_sync_flag %d \n,__func__,accdet-accdet_status,cur_AB,accdet-eint_sync_flag);//最开始accdet-accdet_status PLUG_OUTcur_AB ACCDET_STATE_AB_00//如果是4段耳机且accdet端的电压符合0.4V~1.7V之间会跑第二次//此时accdet_status HOOK_SWITCHcur_AB ACCDET_STATE_AB_01switch(accdet-accdet_status){casePLUG_OUT:if(cur_ABACCDET_STATE_AB_00){mutex_lock(accdet-res_lock);if(accdet-eint_sync_flag){//是不带耳机的accdet-cable_typeHEADSET_NO_MIC;//accdet_status类型是HOOK_SWITCHaccdet-accdet_statusHOOK_SWITCH;}elsepr_notice(accdet hp has been plug-out\n);mutex_unlock(accdet-res_lock);}elseif(...){...}...caseMIC_BIAS:if(cur_ABACCDET_STATE_AB_00){mutex_lock(accdet-res_lock);if(accdet-eint_sync_flag){accdet-button_status1;accdet-accdet_statusHOOK_SWITCH;//这个func应该就是上报耳机的按键事件的func未确认这里就不分析了multi_key_detection(cur_AB);}elsepr_notice(accdet hp has been plug-out\n);mutex_unlock(accdet-res_lock);}elseif(...){...}...caseHOOK_SWITCH:if(cur_ABACCDET_STATE_AB_00){}elseif(cur_ABACCDET_STATE_AB_01){mutex_lock(accdet-res_lock);if(accdet-eint_sync_flag){multi_key_detection(cur_AB);//第二次会走这个到这里就会触发上报了因为cable_type与pre_cable_type已经不一样了accdet-accdet_statusMIC_BIAS;accdet-cable_typeHEADSET_MIC;}elsepr_notice(accdet hp has been plug-out\n);mutex_unlock(accdet-res_lock);}elseif(...){...}...}}3.4 dis_micbias_timerhandler在3.1小节中的pmic_eint_queue_work中会触发这个定时器具体的内容会在6s后执行但是见3.3小节中的accdet_work_callback中的send_status_event(accdet-cable_type, 1);1表示的是HEADSET_MIC在send_status_event中会把这个定时器给关掉即当检测到是带麦的耳机后会执行send_status_event(accdet-cable_type, 1)此时会把该定时器关掉micbias的电压。这里看一下是如何disable这个micbias的staticvoiddis_micbias_timerhandler(structtimer_list*t){intret0;//这里会将一个工作函数列入工作队列中这个工作函数我们会在3.5小节讲解retqueue_work(accdet-dis_micbias_workqueue,accdet-dis_micbias_work);if(!ret)pr_notice(Error: %s (%d)\n,__func__,ret);}3.5 dis_micbias_work_callback这里主要是disable_accdet控制寄存器关闭micbiasstaticvoiddis_micbias_work_callback(structwork_struct*work){u32 cur_AB0,eintID0;printk(%s zzh \n,__func__);/* check EINT0 status, if plug out, * not need to disable accdet here */eintIDaccdet_read_bits(ACCDET_EINT0_MEM_IN_ADDR,ACCDET_EINT0_MEM_IN_SFT,ACCDET_EINT0_MEM_IN_MASK);if(eintIDM_PLUG_OUT){pr_notice(%s Plug-out, no dis micbias\n,__func__);return;}/* if modify_vref_volt called, not need to dis micbias again */if(dis_micbias_donetrue){pr_notice(%s modify_vref_volt called\n,__func__);return;}//这里再次检查这个AB 比较器是否为 带麦耳机插入cur_ABaccdet_read(ACCDET_MEM_IN_ADDR)ACCDET_STATE_MEM_IN_OFFSET;cur_ABcur_ABACCDET_STATE_AB_MASK;/* if 3pole disable accdet * if 20k 4pole, disable accdet will disable accdet * plug out interrupt. The behavior will same as 3pole */if((accdet-cable_typeHEADSET_NO_MIC)||(cur_ABACCDET_STATE_AB_00)||(cur_ABACCDET_STATE_AB_11)){/* disable accdet_sw_en0 * disable accdet_hwmode_en0 *//* setting pwm idle; */accdet_clear_bits(ACCDET_CMP_PWM_IDLE_ADDR,ACCDET_CMP_PWM_IDLE_SFT,0x7,0x7);printk(%s zzh \n,__func__);disable_accdet();}}3.6 delay_init_timerhandler和delay_init_work_callbackstaticvoiddelay_init_timerhandler(structtimer_list*t){intret0;retqueue_work(accdet-delay_init_workqueue,accdet-delay_init_work);if(!ret)pr_notice(Error: %s (%d)\n,__func__,ret);}staticvoiddelay_init_work_callback(structwork_struct*work){//下面这几个函数都是probe执行时 设置一些配置accdet_init();accdet_init_debounce();accdet_init_once();pr_info(%s() done\n,__func__);}如有错误请指正谢谢

相关新闻

笔记本KVM虚拟机VFIO显卡直通完整教程

笔记本KVM虚拟机VFIO显卡直通完整教程

1. 项目概述在Linux环境下运行Windows应用程序一直是许多用户的痛点,尤其是对于游戏玩家和专业软件用户而言。传统的兼容层方案如Wine和Proton虽然取得了一定进展,但在性能和兼容性方面仍存在局限。而虚拟机方案虽然兼容性更好,却常因图形性能…

2026/7/22 16:10:27 阅读更多 →
Alfred高效工作流:从基础搜索到深度定制

Alfred高效工作流:从基础搜索到深度定制

1. Alfred 核心功能解析 Alfred作为macOS平台上的效率神器,其核心价值在于将分散的系统操作整合为统一的指令入口。我使用Alfred五年多,最深体会是它彻底改变了我的工作流结构——通过CommandSpace这组全局快捷键,可以瞬间唤醒搜索框&#x…

2026/7/22 16:10:27 阅读更多 →
C/C++内存管理进阶:从栈堆原理到智能指针实战

C/C++内存管理进阶:从栈堆原理到智能指针实战

1. 项目概述:为什么内存管理是C/C的“成人礼”干了这么多年C/C开发,我越来越觉得,内存管理这门手艺,是区分“会用C”和“懂C”的一道分水岭。新手入门,往往被语法、循环、类这些概念吸引,写得飞起。但一到项…

2026/7/24 4:02:01 阅读更多 →

最新新闻

C++继承机制详解:从访问控制到多态与虚函数实战

C++继承机制详解:从访问控制到多态与虚函数实战

1. 项目概述:为什么C的继承如此重要?如果你写过一段时间的C,尤其是从C语言转过来的,大概率会对“继承”这个概念又爱又恨。爱的是,它让代码复用变得前所未有的方便,你可以基于一个已有的“基类”派生出新的…

2026/7/24 4:14:17 阅读更多 →
分布式AI推理集群优化与CANN架构实践

分布式AI推理集群优化与CANN架构实践

1. 分布式AI推理集群的核心价值与挑战在AI模型规模指数级增长的今天,单设备推理的局限性日益凸显。以典型的NLP模型为例,1750亿参数的GPT-3模型在单张A100显卡上需要近10秒才能完成一次推理响应,这完全无法满足实时交互场景的需求。而通过多设…

2026/7/24 4:14:17 阅读更多 →
外贸工厂老板亲自下场学SEO,3个月节省20万推广费

外贸工厂老板亲自下场学SEO,3个月节省20万推广费

做了十几年外贸工厂,我一直觉得自己只需要管生产、管品质、管交期。流量的事,交给平台、交给展会、交给花钱就能解决的事。去年我才发现,原来钱不是解决问题的唯一方式——有些事,花时间比花钱更划算。我是外贸老板,工…

2026/7/24 4:14:17 阅读更多 →
基于知识图谱与AI大模型的古诗词数字化系统开发

基于知识图谱与AI大模型的古诗词数字化系统开发

1. 项目概述:当古诗词遇上知识图谱与AI大模型这个毕业设计项目将中华古诗词文化与现代计算机技术进行了深度融合,通过Python技术栈构建了一个包含知识图谱可视化、情感分析、智能问答和AI写诗功能的综合系统。作为一名做过类似项目的开发者,我…

2026/7/24 4:14:17 阅读更多 →
智能文献分析系统:NLP技术如何革新学术研究

智能文献分析系统:NLP技术如何革新学术研究

1. 项目概述:文献综述的智能化革命在学术研究领域,文献综述往往是最耗时却又最基础的工作环节。传统模式下,研究者需要手动检索海量文献、筛选有效信息、归纳研究脉络——这个过程动辄消耗数周甚至数月时间。而"书匠策AI"的出现&am…

2026/7/24 4:14:17 阅读更多 →
为什么深圳越来越多品牌选择“动态商标”?AI正在重新定义视觉识别

为什么深圳越来越多品牌选择“动态商标”?AI正在重新定义视觉识别

如果你最近关注过深圳的品牌动态,可能会发现一个有趣的变化:越来越多的企业不再满足于一个“一成不变”的商标。大疆的螺旋桨会随视频节奏加速旋转,腾讯的企鹅在元宇宙中化为跳动的数字粒子,OPPO的“微笑商标”在不同场景下呈现从…

2026/7/24 4:13:17 阅读更多 →

日新闻

用Highcharts 创建可拖拽三维散点立方体3D图表

用Highcharts 创建可拖拽三维散点立方体3D图表

该案例基于Highcharts scatter3d 三维散点图实现空间立方体散点可视化,核心特色:三维 X/Y/Z 三轴空间,所有散点分布在 0~10 立方体空间内;散点使用径向渐变实现立体 3D 圆球质感;支持鼠标 / 触屏拖拽画布,…

2026/7/24 0:00:29 阅读更多 →
AppCertDlls:进程创建路径上的 DLL 入口

AppCertDlls:进程创建路径上的 DLL 入口

AppCertDlls:进程创建路径上的 DLL 入口 AppCertDlls 位于 HKLM\System\CurrentControlSet\Control\Session Manager\AppCertDlls。本文的程序功能是只读列出这个键在 64 位和 32 位注册表视图中的全部值,并显示每条值的来源、名称、类型和可安全显示的数…

2026/7/24 0:00:29 阅读更多 →
我的编程之路:第一篇博客

我的编程之路:第一篇博客

大家好,我是一名编程初学者,同时这也是我编程学习之路上的第一篇博客。在这里,我想要向大家介绍我的一些想法和规划。a.自我介绍我是一个刚刚接触编程的新手,目前在学习c语言,我对编程世界充满了强烈的好奇。当然&…

2026/7/24 0:00:29 阅读更多 →

周新闻

Go语言静态资源打包方案对比与实践指南

Go语言静态资源打包方案对比与实践指南

1. 项目背景与核心需求在Go语言开发中,我们经常需要处理静态资源文件的打包问题。无论是Web应用的模板文件、前端资源,还是配置文件、证书等,都需要随程序一起分发。传统做法是将这些文件与编译后的二进制文件放在同一目录下,但这…

2026/7/24 3:59:20 阅读更多 →
Go语言实现高性能LDAP认证服务的架构与实践

Go语言实现高性能LDAP认证服务的架构与实践

1. 项目背景与核心价值LDAP(轻量级目录访问协议)作为企业级身份认证的黄金标准,已经服务了超过80%的财富500强公司。我在金融科技领域实施统一认证体系时,发现传统Java方案存在启动慢、内存占用高等痛点。而Go语言凭借其协程并发模…

2026/7/24 1:23:39 阅读更多 →
【AI面试官实战指南】:用ChatGPT模拟10类高频技术岗面试,3天提升应答精准度92%

【AI面试官实战指南】:用ChatGPT模拟10类高频技术岗面试,3天提升应答精准度92%

更多请点击: https://intelliparadigm.com 第一章:AI面试官实战指南的核心价值与适用场景 AI面试官并非替代人类HR的“黑箱工具”,而是以可解释、可审计、可迭代的方式,赋能招聘全链路的关键基础设施。其核心价值在于将主观经验沉…

2026/7/23 17:49:47 阅读更多 →

月新闻