mtk-keypad[通俗易懂]

mtk-keypad[通俗易懂]一.keypad基本原理col作为输出,row作为输入检测,低电平有效colA~D轮流输出低电平,通过rol1~4上的低电平可以检测是哪个按键按下了但是存在这样的问题,A1,A2,B1同时按下,会造成B2按下的假象,称为鬼影(这3个键导通,colB打开,row2处也会检测到低电平)可以通过增加二极管的方式防止鬼影问题二.keypadporti…

大家好,又见面了,我是你们的朋友全栈君。

一.keypad基本原理

mtk-keypad[通俗易懂]

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

mtk-keypad[通俗易懂]

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

二.keypad porting

  • 1.dws中GPIO设置,mtk将ROW作为输出,COL作为输入检测,preloader的keypad.c文件中对keypad进行了设置
    •   KCOL:input + pull enable + pull up
    •        KROW:output + pull disable + pulldown

mtk-keypad[通俗易懂]

mtk-keypad[通俗易懂]

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

mtk-keypad[通俗易懂]

  • 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_lock wake_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 */ #endif hrtimer_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);
//调度tasklet tasklet_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_state kpd_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

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/136276.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)
blank

相关推荐

  • linux重要开源软件

    linux重要开源软件1.yocto(开源工具,定制linux系统)2.buildroot(开源工具,定制linux系统)3.arago(ti公司专用开源工具,定制linux系统)4.linaro(交叉编译工具,直接使用)5.crosstool_ng(制作交叉编译工具的工具)6.qemu(开发板仿真工具,用于SoC开发)…

    2022年10月31日
  • hashmap底层实现原理和源码分析(python底层源码)

    HashMap是Java开发中常用的集合,那么从我们创建一个空集合到,put添加、get获取元素经历了那些步骤呢?说明:以下源码基于JDK1.7,32位0.HashMap底层的数据结构是数组加链表的形式,存储结构如下图:1.创建一个新的HashMap集合的构造函数://初始默认数组的大小staticfinalintDEFAULT_INITIAL_CAPACITY=1&lt;&lt;…

  • Spring Cloud原理详解[通俗易懂]

    Spring Cloud原理详解[通俗易懂]概述毫无疑问,SpringCloud是目前微服务架构领域的翘楚,无数的书籍博客都在讲解这个技术。不过大多数讲解还停留在对SpringCloud功能使用的层面,其底层的很多原理,很多人可能并不知晓。因此本文将通过大量的手绘图,给大家谈谈SpringCloud微服务架构的底层原理。实际上,SpringCloud是一个全家桶式的技术栈,包含了很多组件。本文先从其最核心的几个组件入手,来剖…

  • ACM之Java输入输出[通俗易懂]

    ACM之Java输入输出[通俗易懂]一、Java之ACM注意点1. 类名称必须采用public class Main方式命名2. 在有些OJ系统上,即便是输出的末尾多了一个“ ”,程序可能会输出错误,所以在我看来好多OJ系统做的是非常之垃圾3. 有些OJ上的题目会直接将OI上的题目拷贝过来,所以即便是题目中有输入和输出文件,可能也不需要,因为在OJ系统中一般是采用标准输入输出,不需要文件4. 在有多行数据输入的情况下

  • 详解mysql 主从复制原理

    详解mysql 主从复制原理

  • mysql jdbc下载(mysql下载哪个版本)

    https://dev.mysql.com/downloads/connector/j/

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号