GPIO按键驱动分析(包括矩阵按键)

一 Gpio_keys.c分析

 

1.      input device的注册是怎么样的,调用了哪些公用的函数

 

首先使用了late_initcall宏定义对驱动模型进行加载,在gpio_keys_init()函数中,使用了平台驱动注册函数platform_driver_register()来进行注册,其中参数结构体

static struct platform_driver gpio_keys_device_driver= {

     .probe           =gpio_keys_probe,

     .remove        = gpio_keys_remove,

     .driver           = {

            .name     = "gpio-keys",

            .owner   = THIS_MODULE,

            .pm = &gpio_keys_pm_ops,

            .of_match_table =of_match_ptr(gpio_keys_of_match),

      }

};

在注册过程中调用了gpio_keys_probe()函数完成了input device的注册。在gpio_keys_probe()函数中主要完成了以下事情:

a)      定义结构体 struct input_dev *input,并使用 input =input_allocate_device(input)将input申请为输入设备。

b)      配置input信息

input->name =pdata->name ? :pdev->name;

input->phys="gpio-keys/input0";

      input->dev.parent=&pdev->dev;

      input->open=gpio_keys_open;     

input->close =gpio_keys_close;

input->id.bustype =BUS_HOST;

      input->id.vendor =0x0001;

      input->id.product=0x0001;

      input->id.version=0x0100;

c)      通过error =input_register_device(input)函数向kernel注册一个输入设备。

 

此外,gpio_keys_probe()中还调用了gpio_keys_setup_key()函数对gpio进行配置。

 

 

2.      GPIO的申请,初始化,以及如何控制,中断服务的注册,中断如何处理的。

 

在gpio_keys_setup_key()函数中,先使用gpio_is_valid来测试端口是否合法,然后使用gpio_request_one进行GPIO的申请,同时将引脚配置成输入,通过irq =gpio_to_irq(button_irq)将引脚设为外部中断,同时获得的中断号赋值给bdata_irq,然后设置外部中断服务函数isr = gpio_keys_gpio_isr以及配置中断处理标志irqflag为上升沿触发和下降沿触发,。最后通过  error =request_any_context_irq(bdata->irq, isr, irqflags,desc, bdata)来完成中断服务的注册。在对input进行配置时,由input->open =gpio_keys_open;      、input->close=gpio_keys_close可知通过gpio_keys_open/gpio_keys_close

函数可以对GPIO端口进行打开和关闭,对GPIO端口进行控制。

该程序中具体的中断流程如下:

1.      首先完成中断的配置以及注册

2.      按键按下时,触发外部中断,调用中断服务程序gpio_keys_gpio_isr,使用定时器进行消抖,然后调用工作队列中的gpio_keys_work_func()函数

3.      通过gpio_keys_gpio_report_events()函数中的gpio_get_value_cansleep(button_gpio)函数来对按键进行扫描,获得按键值,使用input_event传递事件信息,最后使用input_sync()完成事件的同步。

 

最后使用intgpio_keys_remove()中完成卸载,该函数主要是删除定时器,取消工作队列的工作,释放申请的引脚, 通过input_unregister_device(input)注销输入设备, 最后通过kfree(ddata)释放之前申请的数据内存空间。

 

 

二.Matrix_keypad.c分析

Matrix_keypad.c驱动程序首先使用了module_platform_driver(matrix_keypad_driver)

进行平台驱动注册和注销函数,先看平台驱动注册函数的参数结构体:

static struct platform_drivergpio_keys_device_driver = {

     .probe           =gpio_keys_probe,

     .remove        = gpio_keys_remove,

     .driver           = {

            .name     = "gpio-keys",

            .owner   = THIS_MODULE,

            .pm = &gpio_keys_pm_ops,

            .of_match_table =of_match_ptr(gpio_keys_of_match),

      }

};

在注册的时候就会去执行gpio_keys_probe函数,在注销的时候就会执行gpio_keys_remove的函数,然后gpio_keys_pm_ops,这个由宏static SIMPLE_DEV_PM_OPS(gpio_keys_pm_ops,gpio_keys_suspend,gpio_keys_resume)最终会调用gpio_keys_remove和gpio_keys_suspend函数控制电源的进入工作状态或者低功耗状态。

 

gpio_keys_probe()分析:

在gpio_keys_probe()函数中主要完成了以下任务:

a)      为键盘分配内存空间,定义结构体 struct input_dev *input,并使用 input =input_allocate_device(input)将input申请为输入设备。

b)      对keypad和input进行配置

c)      调用matrix_keypad_init_gpio()函数完成对GPIO端口的初始化。

d)      使用input_register_device对设备进行注册。

 

GPIO设置Matrix_keypad_init_gpio()分析

在该函数中,对GPIO端口进行初始化,由三列GPIO和两行GPIO端口构成有6个按键的矩阵键盘,先对三列GPIO进行request申请,并使用gpio_dorection_output将三列GPIO端口配置成输出端,输出为高电平。然后对两行GPIO进行request申请,并使用gpio_dorection_input配置成输入端口。并使用request_irq(gpoi_to_irq(pdata.row_gpio[i])将两行GPIO端口设置为外部中断,并向内核完成中断的注册。

 

中断流程分析:

当按键按下时,按键触发中断进入中断服务程序matrix_keypad_interrupt()函数中,该函数主要完成了INIT_DELAYED_WORK工作队列中按键扫描matrix_keypad_scan()任务。

 

Matrix_keypad_scan()分析:

先使用for()循环对每一列GPIO端口进行选择,使用activate_col()函数将每一列GPIO配置成输出端,且输出为高电平,然后嵌套for循环对已经配置成输入的两行GPIO进行逐个分析,当有按键按下时,由row_asserted(pdata,row)?(1<

你可能感兴趣的:(LINUX)