对 于 GPIO 按 键 , 我 们 并 不 需 要 去 写 驱 动 程 序 , 使 用 内 核 自 带 的 驱 动 程 序drivers/input/keyboard/gpio_keys.c 就可以,然后你需要做的只是修改设备树指定引脚及键值。
但是自己编写相关的内容则可以更好的学习到这些功能。
编程思路
在设备树里指定相关的引脚,这里使用的是GPIO7_B1。然后使用pinctrl对引脚进行读取,读取函数需要在中断中进行。
中断的注册是通过一系列设备树函数设定的。
执行过程:
设置树相关的配置:
/ {
mybutton {
compatible = "mybtn,btn_drv";
gpios = <&gpio7 9 GPIO_ACTIVE_LOW>;
pinctrl-names = "default";
pinctrl-0 = <&my_btn>;
};
&pinctrl {
mybutton {
my_btn: my-btn {
rockchip,pins = <7 9 RK_FUNC_GPIO &pcfg_pull_up>;
};
};
};
};
在arch/arm/boot/dts/rk3288-firefly-port.dtsi中,有100ask的设备节点,这个就是用gpio-key编写的。
需要把它注释掉,不然注册中断的时候会冲突。
//100ask extend board.
button@1 {
gpios = <&gpio7 9 GPIO_ACTIVE_LOW>;
linux,code = <KEY_A>;
label = "GPIO KEY_A";
linux,input-type = <1>;
gpio-key,wakeup = <1>;
debounce-interval = <100>;
pinctrl-names = "default";
pinctrl-0 = <&keyabtn>;
};
代码编写思路
- 从设备树中获取GPIO号
- 从GPIO获取中断号
- 申请中断
- 编写中断函数
相关函数
//计算设备树中节点np下的gpios属性的个数
static inline int of_gpio_count(struct device_node *np);
//获取gpio flags的参数,这里的返回值应该是gpio号。
static inline int of_get_gpio_flags(struct device_node *np, int index, enum of_gpio_flags *flags);
//把gpio号转换成gpio_desc
struct gpio_desc *gpio_to_desc(unsigned gpio);
//把gpio号转换成irq号
static inline int pio_to_irq(unsigned gpio);
//注册中断函数,irq申请的中断号,handler处理函数,flags触发条件,name中断总线中的名字,dev设备指针
static inline int __must_check
request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags, const char *name, void *dev);
源码
button_irq.c
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/platform_device.h>
#include <linux/device.h>
#include <linux/sched.h>
#include <linux/wait.h>
#include <linux/uaccess.h>
#include <linux/irqreturn.h>
#include <linux/gpio/consumer.h>
#include <linux/of_gpio.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
struct gpio_key {
int gpio;
struct gpio_desc *gpiod;
int flag;
int irq;
};
static struct gpio_key *myBtn_key;
static irqreturn_t myBtn_irq_request(int irq, void *dev_id)
{
struct gpio_key *gpio_key = dev_id;
int val;
val = gpiod_get_value(gpio_key->gpiod);
printk(KERN_WARNING"key %d %d\n", gpio_key->gpio, val);
return IRQ_HANDLED;
}
static int my_button_probe(struct platform_device *pdev)
{
struct device_node *node = pdev->dev.of_node;
int count;
enum of_gpio_flags flag;
int i, err;
count = of_gpio_count(node);
if(!count) {
printk("%s,there isn't any gpio availiable\n", __FUNCTION__);
return -1;
}
myBtn_key = (struct gpio_key*)kzalloc(sizeof(struct gpio_key)*count, GFP_KERNEL);
if(!myBtn_key) {
printk("%s,kzalloc malloc failed\n", __FUNCTION__);
return -1;
}
for(i=0;i<count;i++) {
myBtn_key[i].gpio = of_get_gpio_flags(node, i, &flag);
if(myBtn_key[i].gpio < 0) {
printk("%s, of_get_gpio_flags failed\n", __FUNCTION__);
return -1;
}
myBtn_key[i].gpiod = gpio_to_desc(myBtn_key[i].gpio);
myBtn_key[i].flag = flag & OF_GPIO_ACTIVE_LOW;
myBtn_key[i].irq = gpio_to_irq(myBtn_key[i].gpio);
err = request_irq(myBtn_key[i].irq, myBtn_irq_request, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
"myBtn_key", &myBtn_key[i]);
}
return 0;
}
static int my_button_remove(struct platform_device *pdev)
{
struct device_node *node= pdev->dev.of_node;
int count;
int i;
count = of_gpio_count(node);
for(i=0;i<count;i++) {
free_irq(myBtn_key[i].irq, &myBtn_key[i]);
}
kfree(myBtn_key);
return 0;
}
static struct of_device_id mybuttons[] = {
{ .compatible = "mybtn,btn_drv" },
{ },
};
static struct platform_driver my_button_driver = {
.probe = my_button_probe,
.remove = my_button_remove,
.driver = {
.name = "button_dirver",
.of_match_table = mybuttons,
},
};
static int gpio_button_init(void)
{
int err;
err = platform_driver_register(&my_button_driver);
printk(KERN_WARNING"my button dirver init\n");
return 0;
}
static void gpio_button_exit(void)
{
platform_driver_unregister(&my_button_driver);
printk(KERN_WARNING"my button dirver exit\n");
}
module_init(gpio_button_init);
module_exit(gpio_button_exit);
MODULE_LICENSE("GPL");
button_irq.dts
/ {
mybutton {
compatible = "mybtn,btn_drv";
gpios = <&gpio7 9 GPIO_ACTIVE_LOW>;
pinctrl-names = "default";
pinctrl-0 = <&my_btn>;
};
&pinctrl {
mybutton {
my_btn: my-btn {
rockchip,pins = <7 9 RK_FUNC_GPIO &pcfg_pull_up>;
};
};
};
};