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)


相关推荐

  • kotlin与java的区别[通俗易懂]

    kotlin与java的区别[通俗易懂]Kotlin简介:Kotlin是一个基于JVM的新的编程语言,由JetBrains开发。Kotlin可以编译成Java字节码,也可以编译成JavaScript,方便在没有JVM的设备上运行。JetBrains,作为目前广受欢迎的JavaIDEIntelliJ的提供商,在Apache许可下已经开源其Kotlin编程语言。Kotlin已正式成为Android官方开发语言。通过上面的简介,我们对Kotlin也有了大概了认知,Kotlin作为新的一种语言,可以运行在JVM上面,那么它

  • app漏洞检测方法有哪些_安卓app漏洞挖掘

    app漏洞检测方法有哪些_安卓app漏洞挖掘根据国内专业PP漏洞检测平台爱内测(www.detect.cn)介绍,目前关于APP漏洞检测有以下6种功能检测方法: 组件安全检测对四大组件和WebView的规范使用检测分析,发现因为程序中不规范使用导致的组件漏洞。 代码安全检测对dex和so库以及第三方加载库的代码的安全处理进行检测分析,发现代码被反编译和激活成功教程的漏洞。 内存安全检测检测APP运行过程中的内存处理和保护机制进行检测分析…

    2022年10月28日
  • pycharm选择解释器_python高级编程

    pycharm选择解释器_python高级编程一、IDE配置解释器二、配置pip镜像按照【配置永久生效】全局配置文件Window系统下,文件夹路径中输入%APPDATA%,若没有pip目录创建,并在里面创建文件pip.ini,内容如下[global]timeout=6000index-url=https://pypi.mirrors.ustc.edu.cn/simple/tr…

  • linux centos安装wine qq,ubuntu安装wine QQ「建议收藏」

    linux centos安装wine qq,ubuntu安装wine QQ「建议收藏」题外话:在使用win7,8的时候,发现如果硬盘存有大量文件的时候,笔记本自带的渣渣机械硬盘读取会很慢。而win10在硬盘读取方面的优化,确实比前几个版本好。但是,随之出现的问题是,内存不够用。后来上手linux,才发现这才是真爱。装过ubuntu,centos。总结ubuntu更适合日常的使用。顺带说一句,16.04TLS,装入很多大型IDE和虚拟机的时候,4G也是有点抗不住。开始正题:首先,安装…

  • STL 源代码剖析 算法 stl_algo.h — merge sort「建议收藏」

    STL 源代码剖析 算法 stl_algo.h — merge sort

  • 3G网络结构[通俗易懂]

    3G网络结构[通俗易懂]在2G(GSM)技术之后,为了适应数据流业务的发展,2.5G(GPRS)技术日益兴起。但是速率很低,随后才发展到3G(UMTS)通信系统。3G网络结构图如下所示:更详细一些的架构图:MSC/VLR和GMSC属于电路域,GGSN和SGSN属于分组域。1,UE(UserEquipment)UE是用户终端设备,它主要包括射频处理单元、基带处理单元、协议栈模

发表回复

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

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