linux设备驱动之gpio_keys

#ifndef _GPIO_KEYS_H
#define _GPIO_KEYS_H

struct gpio_keys_button {
        /* Configuration parameters */
        int code;               /* 输入事件的键值可以是EV_*或KEY_* */
        int gpio;               /* 对应的GPIO号 */
        int active_low;         /* 活动时是否为低,即按下的时候是否被拉低 */
        char *desc;             /* 一些注册信息   */
        int type;               /* 输入事件的类型,比如是拨码还是按键 */
        int wakeup;             /* 配置该输入信号作为系统唤醒源 */
        int debounce_interval;  /* 对于按键开关设置抖动时间,一般20ms */
};

struct gpio_keys_platform_data { /* gpio_keys 的平台私有数据,一般作为私有指针传给platform_device */
        struct gpio_keys_button *buttons;
        int nbuttons;
        unsigned int rep:1;             /* enable input subsystem auto repeat */
};

#endif

平台设备的注册:
在平台文件中包含gpio_keys所需的头文件
#include <linux/gpio_keys.h>
#include <linux/input.h>

#define GPIO_TO_KEY(gpio_num, ev_code, act_low, descr, wake)    \
{                                                               \
        .gpio   = gpio_num,                                     \
        .type   = EV_KEY,                                       \
        .code   = ev_code,                                      \
        .active_low = act_low,                          \
        .desc   = "btn "descr,                                  \
        .wakeup = wake,                                         \
        .debounce_interval = 15,                                \
}                                                               

#define M2M_BAORD_USER_KEY      GPIO_TO_PIN(3, 7)

static struct gpio_keys_button sbc_buttons[] = { 
        GPIO_TO_KEY(M2M_BAORD_USER_KEY, KEY_UP, 0, "user_bt1", 0), 
};

static struct gpio_keys_platform_data sbc_buttons_data = { 
        .buttons        = sbc_buttons,
        .nbuttons       = ARRAY_SIZE(sbc_buttons),
};

static struct platform_device sbc_buttons_device = { 
        .name   = "gpio-keys",            /* 如果使用内核驱动gpio-keys,则平台设备名必须为此,这是内核驱动模型所决定 */
        .id     = -1, 
        .num_resources = 0,
        .dev    = { 
                .platform_data = &sbc_buttons_data, /* 私有数据传递给驱动 */
        }   
};

上面定义了GPIO_TO_KEY宏来代替struct gpio_keys_button类型,方便定义多个按键。
最后需要在平台文件里显示注册gpio-keys到驱动设备链表里
platform_device_register(&sbc_buttons_device);
平台设备驱动:
内核里已经支持了标准的gpio_keys驱动,在drivers/input/keyboard目录下,对应刚才注册的gpip-keys设备,这里为gpio_keys.c
需要选择CONFIG_KEYBOARD_GPIO才会被编译
首先参考平台驱动结构体platform_driver

static struct platform_driver gpio_keys_device_driver = { 
        .probe          = gpio_keys_probe,
        .remove         = __devexit_p(gpio_keys_remove),
        .driver         = { 
                .name   = "gpio-keys", /* 驱动名,内核正式通过这个名字的匹配进行设备与驱动的探测和绑定 */
                .owner  = THIS_MODULE,
#ifdef CONFIG_PM
                .pm     = &gpio_keys_pm_ops,
#endif
        }   
};
现在的cpu集成度很高,基本作为一个驱动开发者,特别是在天朝,其实并没有太多的技术含量,soc的驱动在芯片厂商提供的SDK包中
基本已经包含了,国内一般在官方板的基础上进行裁剪添加,而作为驱动工程所,剩下的工作只需要熟悉驱动框架模型,以及各种总线接口时序,
可能驱动只需要改动几行代码就可以了,而基于SOC的platform设备驱动也是接触最多的。
probe函数主要流程,初始化input设备结构,根据gpio号申请并置为输入,然后根据GPIO号申请中断,并注册中断函数,中端方式为共享中断,边沿触发。
将设备与input设备绑定并注册input到内核输入框架。
中断产生后。
/* 向上层报告 */
 41 static void gpio_keys_report_event(struct work_struct *work)
 42 {
 43         struct gpio_button_data *bdata =
 44                 container_of(work, struct gpio_button_data, work);
 45         struct gpio_keys_button *button = bdata->button;
 46         struct input_dev *input = bdata->input;
 47         unsigned int type = button->type ?: EV_KEY;
 48         int state = (gpio_get_value(button->gpio) ? 1 : 0) ^ button->active_low;
 49         input_event(input, type, button->code, !!state);
 50         input_sync(input);
 51 }
 52 /* 若设置了抖动时间,定时器延时到后会调用进入函数 */
 53 static void gpio_keys_timer(unsigned long _data)
 54 {
 55         struct gpio_button_data *data = (struct gpio_button_data *)_data;
 56 
 57         schedule_work(&data->work);
 58 }
 59  /* 中断处理函数 */
 60 static irqreturn_t gpio_keys_isr(int irq, void *dev_id)
 61 {
 62         struct gpio_button_data *bdata = dev_id;
 63         struct gpio_keys_button *button = bdata->button;
 64 
 65         BUG_ON(irq != gpio_to_irq(button->gpio));
 66 
 67         if (button->debounce_interval)
 68                 mod_timer(&bdata->timer,
 69                         jiffies + msecs_to_jiffies(button->debounce_interval));
 70         else
 71                 schedule_work(&bdata->work);
 72 
 73         return IRQ_HANDLED;
 74 }


  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值