一.keypad基本原理

col作为输出,row作为输入检测,低电平有效
col A~D轮流输出低电平,通过rol 1~4上的低电平可以检测是哪个按键按下了但是存在这样的问题,A1,A2,B1同时按下,会造成B2按下的假象,称为鬼影(这3个键导通,colB打开,row2处也会检测到低电平)

可以通过增加二极管的方式防止鬼影问题

二.keypad porting

  • 1.dws中GPIO设置,mtk将ROW作为输出,COL作为输入检测,preloader的keypad.c文件中对keypad进行了设置

    •   KCOL:input + pull enable + pull up
    • KROW:output + pull disable + pulldown

  • 2.dws keypad设置,mtk6750最多支持2*2按键矩阵,通过下拉框选择相应的按键,按键name、对应键值[Key_code_linux]在Keypad_YuSu.cmp这个文件中有定义

  • 3.添加新的按键参考FAQ13931

三.keypad代码分析

生成的keypad设备树节点信息如下,kpd-hw-init-map将键盘矩阵以一维数组(键值)的格式表示,一共72个

keypad@10010000 {compatible = "mediatek,mt6755-keypad", "mediatek,kp";reg = <0x10010000 0x1000>;interrupts = <0x0 0xa4 0x2>;mediatek,kpd-key-debounce = <0x400>;mediatek,kpd-sw-pwrkey = <0x74>;mediatek,kpd-hw-pwrkey = <0x8>;mediatek,kpd-sw-rstkey = <0x73>;mediatek,kpd-hw-rstkey = <0x11>;mediatek,kpd-use-extend-type = <0x0>;mediatek,kpd-hw-map-num = <0x48>;mediatek,kpd-hw-init-map = <0x72 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0>;mediatek,kpd-pwrkey-eint-gpio = <0x0>;mediatek,kpd-pwkey-gpio-din = <0x0>;mediatek,kpd-hw-dl-key0 = <0x11>;mediatek,kpd-hw-dl-key1 = <0x0>;mediatek,kpd-hw-dl-key2 = <0x8>;mediatek,kpd-hw-recovery-key = <0x11>;mediatek,kpd-hw-factory-key = <0x0>;status = "okay";};

static int kpd_pdrv_probe(struct platform_device *pdev)
{int i, r;int err = 0;struct clk *kpd_clk = NULL;
//获取clk,这里kpd-clk是通过ccf设置的kpd_clk = devm_clk_get(&pdev->dev, "kpd-clk");if (!IS_ERR(kpd_clk)) {int ret_prepare, ret_enable;ret_prepare = clk_prepare(kpd_clk);if (ret_prepare)kpd_print("clk_prepare returned %d\n", ret_prepare);ret_enable = clk_enable(kpd_clk);if (ret_enable)kpd_print("clk_enable returned %d\n", ret_prepare);} else {kpd_print("get kpd-clk fail, but not return, maybe kpd-clk is set by ccf.\n");}
//reg重映射kp_base = of_iomap(pdev->dev.of_node, 0);if (!kp_base) {kpd_info("KP iomap failed\n");return -ENODEV;};
//irq映射kp_irqnr = irq_of_parse_and_map(pdev->dev.of_node, 0);if (!kp_irqnr) {kpd_info("KP get irqnr failed\n");return -ENODEV;}
//申请input设备kpd_input_dev = input_allocate_device();if (!kpd_input_dev) {kpd_print("input allocate device fail.\n");return -ENOMEM;}
//input设备初始化kpd_input_dev->name = KPD_NAME;kpd_input_dev->id.bustype = BUS_HOST;kpd_input_dev->id.vendor = 0x2454;kpd_input_dev->id.product = 0x6500;kpd_input_dev->id.version = 0x0010;kpd_input_dev->open = kpd_open;
//解析dts中keypad节点的信息,赋值给kpd_dts_data结构体kpd_get_dts_info(pdev->dev.of_node);
//分配内存空间,用于存放键值和按键状态寄存器kpd_memory_setting();
//input设备支持EV_KEY事件__set_bit(EV_KEY, kpd_input_dev->evbit);
//powerkey连接PMIC,kpd_keymap[8]设置为空
#if defined(CONFIG_KPD_PWRKEY_USE_EINT) || defined(CONFIG_KPD_PWRKEY_USE_PMIC)__set_bit(kpd_dts_data.kpd_sw_pwrkey, kpd_input_dev->keybit);kpd_keymap[8] = 0;
#endif//powerkey列除[8]外,其余都清空    if (!kpd_dts_data.kpd_use_extend_type) {for (i = 17; i < KPD_NUM_KEYS; i += 9)    /* only [8] works for Power key */kpd_keymap[i] = 0;}//设置设备支持的键值for (i = 0; i < KPD_NUM_KEYS; i++) {if (kpd_keymap[i] != 0)__set_bit(kpd_keymap[i], kpd_input_dev->keybit);}
//reset按键if (kpd_dts_data.kpd_sw_rstkey)__set_bit(kpd_dts_data.kpd_sw_rstkey, kpd_input_dev->keybit);
kpd_input_dev->dev.parent = &pdev->dev;//注册input设备r = input_register_device(kpd_input_dev);if (r) {kpd_info("register input device failed (%d)\n", r);input_free_device(kpd_input_dev);return r;}/* register device (/dev/mt6575-kpd) */kpd_dev.parent = &pdev->dev;r = misc_register(&kpd_dev);if (r) {kpd_info("register device failed (%d)\n", r);input_unregister_device(kpd_input_dev);return r;}
//初始化wake_lockwake_lock_init(&kpd_suspend_lock, WAKE_LOCK_SUSPEND, "kpd wakelock");//设置按键消抖并申请中断处理kpd_set_debounce(kpd_dts_data.kpd_key_debounce);r = request_irq(kp_irqnr, kpd_irq_handler, IRQF_TRIGGER_NONE, KPD_NAME, NULL);if (r) {kpd_info("register IRQ failed (%d)\n", r);misc_deregister(&kpd_dev);input_unregister_device(kpd_input_dev);return r;}

#ifndef KPD_EARLY_PORTING    /*add for avoid early porting build err the macro is defined in custom file */long_press_reboot_function_setting();    /* /API 4 for kpd long press reboot function setting */
#endifhrtimer_init(&aee_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);aee_timer.function = aee_timer_func;
//添加文件属性err = kpd_create_attr(&kpd_pdrv.driver);if (err) {kpd_info("create attr file fail\n");kpd_delete_attr(&kpd_pdrv.driver);return err;}kpd_info("%s Done\n", __func__);return 0;
}

看下中断处理函数的内容:

static irqreturn_t kpd_irq_handler(int irq, void *dev_id)
{
//禁止中断,无需进行同步,防止死锁disable_irq_nosync(kp_irqnr);//调度tasklettasklet_schedule(&kpd_keymap_tasklet);return IRQ_HANDLED;
}

//定义tasklet,执行kpd_keymap_handler函数static DECLARE_TASKLET(kpd_keymap_tasklet, kpd_keymap_handler, 0);

static void kpd_keymap_handler(unsigned long data)
{int i, j;bool pressed;u16 new_state[KPD_NUM_MEMS], change, mask;u16 hw_keycode, linux_keycode;
//mtk通过5组寄存器来保存按键的状态,这里回读寄存器并保存为new_statekpd_get_keymap_state(new_state);
//激活锁唤醒系统,500ms后就释放掉wake_lock_timeout(&kpd_suspend_lock, HZ / 2);for (i = 0; i < KPD_NUM_MEMS; i++) {//每组中按键状态未改变则对比下一组,按位处理change = new_state[i] ^ kpd_keymap_state[i];if (!change)continue;for (j = 0; j < 16; j++) {//每组(16位)中对比按位查看是否状态发生改变mask = 1U << j;if (!(change & mask))continue;hw_keycode = (i << 4) + j;/* bit is 1: not pressed, 0: pressed */
//按键是否按下,寄存器中0表示按键处于按下状态                        pressed = !(new_state[i] & mask);if (kpd_show_hw_keycode)kpd_print("(%s) HW keycode = %u\n", pressed ? "pressed" : "released", hw_keycode);BUG_ON(hw_keycode >= KPD_NUM_KEYS);linux_keycode = kpd_keymap[hw_keycode];if (unlikely(linux_keycode == 0)) {kpd_print("Linux keycode = 0\n");continue;}kpd_aee_handler(linux_keycode, pressed);
//上报键值input_report_key(kpd_input_dev, linux_keycode, pressed);input_sync(kpd_input_dev);kpd_print("report Linux keycode = %u\n", linux_keycode);}}
//kpd_keymap_state保存new_state,用于下轮对比memcpy(kpd_keymap_state, new_state, sizeof(new_state));kpd_print("save new keymap state\n");//按键处理完毕,打开中断enable_irq(kp_irqnr);
}

转载于:https://www.cnblogs.com/ant-man/p/9204977.html

mtk-keypad相关推荐

  1. MTK keypad调试,扩张键盘IC AW9523

    FROM:http://blog.csdn.net/aree/article/details/28683741 按键没有hal层 设备中断-------驱动------>内核按键码(SCANCO ...

  2. MTK keypad调试,扩张键盘IC AW9523

    按键没有hal层 设备中断-------驱动------>内核按键码(SCANCODE)-------*.kl--------> android keycode(char*)------- ...

  3. MTK Keypad驱动框架

    上一节,看完了http://blog.csdn.net/morixinguan/article/details/7717020,tpd驱动框架的实现. 那么这一节来分析下Keypad驱动框架的实现,其 ...

  4. mtk keypad

    驱动位置: kernel-3.18/drivers/input/keyboard/mediatek/kpd.c 问题1:侧键没有功能,或者反了 解决:没有功能的,可以直接短路主板上的对应焊点,如果有功 ...

  5. MT6755 平台手机皮套驱动实现

    是自己写注册一个input device,模仿keypad,在对应的中断处理函数中上报power key的键值. 具体实现代码如下: 在 alps/kernel-3.10/drivers/misc/m ...

  6. mtk dws工具中的keypad配置

    1. 需求 2. dws工具配置key配置 3. 编译调试 3.1 配置完keypad时,发现系统根本就没更新对应设置keyvalue值 通过对比out/下内核生成的dtsi确认, vi out/ta ...

  7. (转)MTK 消息分发及窗口管理

    一.总体结构 1. Software Architecture MediaTek Inc . (MTK) 2. MMI Architecture MTK 平台采用的是Pixtel Communicat ...

  8. MTK功能机ATA导入

    ATA自动测试为MTK在6260平台开发的自动测试PCBA功能是否正常的功能,支持LCM.Camera.Audio.BT.WIFI.SIM.T Card.Vibrator.ATV.FM.Keypad. ...

  9. android nvram读写,MTK Android平台Nvram与Gensor数据获取

    微信公众号:morixinguan 关注可了解更多的教程.问题或建议,请公众号留言; 如果你觉得本文对你有帮助,欢迎赞赏 ▲长按图片保存可分享至朋友圈 在MTK的机器中,如果不用特定的工具烧写MAC地 ...

  10. android MTK平台驱动设置

    1. LCD 1.1怎样新建一个LCD驱动 LCD模组主要包括LCD显示屏和驱动IC.比如LF040DNYB16a模组的驱动IC型号为NT35510.要在MT577平台上新建这个lcd的驱动,步骤如下 ...

最新文章

  1. 【机器学习】通俗的决策树算法讲解和应用
  2. Hibernate从零开始_07_多对多关系(中间表)
  3. 主题:log4j详解与实战
  4. tiptop 编译运行_tiptop客制规范总结
  5. Linux零拷贝的原理
  6. 解决Chrome浏览器高版本无法拖拽离线安装CRX格式插件的问题
  7. FastDFS 文件上传工具类
  8. 精通 RPM 之查询篇
  9. 基金回撤越大收益越高吗?
  10. 创建指南针View的例子
  11. windows_xp_sp3下的php环境安装配置
  12. smote算法 不平衡数据集处理方法
  13. gatedata graph digitier 基本使用
  14. 基于Java+SpringBoot+vue+elementui药品商城采购系统详细设计实现
  15. oracle normsinv函数,统计函数NormSDist和NormSInv函数实现
  16. 大学物理实验计算机仿真 光电效应,大学物理实验报告模版
  17. Sci-Hub十周年迎来解封!科研er的福音!附可用网址!
  18. python语言下同一个类下有多个函数,其中一个函数想调用另外一个函数里面的变量怎么调用
  19. MATLAB实现基于BP神经网络的手写数字识别+GUI界面+mnist数据集测试
  20. w7设置双显示器_Win7如何设置双显示器?设置双显示器的方法

热门文章

  1. Linux学习笔记(5)(标准输入输出)
  2. BMC的风扇控制 (Fan speed control)
  3. 微信视频文件过大,无法传输?教你一招快速压缩文件!
  4. linux debian iso下载,Debian GNU/Linux 9.8 “Stretch” live和DVD ISO现在可供下载
  5. 在线教育行业未来的发展趋势
  6. dae模型如何合并_PV3D学习笔记-导入DAE模型
  7. composer 指定PHP版本
  8. 24V-2A矿用本安电源设计
  9. MySQL 5.7中sync_binlog参数和半同步中after_commit和after_sync的区别
  10. 分布式计算(网络和网际互连)