设备树
在根节点下的节点:
key_add_input_dev{
compatible = "100ask,my_key";
pinctrl-names = "default";
pinctrl-0 = <&my_key_add_input_dev1 &my_key_add_input_dev2>;
key_add_input_dev1{
label = "key_add_input_dev1";
key-gpios = <&gpio5 1 GPIO_ACTIVE_LOW>;
interrupt-parent = <&gpio5>;
interrupts = <1 IRQ_TYPE_EDGE_FALLING>;
linux,code = <KEY_1>;
};
key_add_input_dev2{
label = "key_add_input_dev2";
key-gpios = <&gpio4 14 GPIO_ACTIVE_LOW>;
interrupt-parent = <&gpio4>;
interrupts = <14 IRQ_TYPE_EDGE_FALLING>;
linux,code = <KEY_2>;
};
};
pinctrl:
&iomuxc {
....
my_key_add_input_dev2: my_key_add_input_dev2{
fsl,pins = <
MX6UL_PAD_NAND_CE1_B__GPIO4_IO14 0xF080
>;
};
....
}
&iomuxc_snvs {
...
my_key_add_input_dev1: my_key_add_input_dev1{
fsl,pins = <
MX6ULL_PAD_SNVS_TAMPER1__GPIO5_IO01 0x000110A0
>;
};
....
}
#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/sched.h>
#include <linux/pm.h>
#include <linux/slab.h>
#include <linux/sysctl.h>
#include <linux/proc_fs.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/input.h>
#include <linux/gpio_keys.h>
#include <linux/workqueue.h>
#include <linux/gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/of.h>
#include <linux/of_platform.h>
#include <linux/of_gpio.h>
#include <linux/of_irq.h>
#include <linux/spinlock.h>
#include <linux/timer.h>
#include <linux/jiffies.h>
#include<linux/delay.h>
struct mykey{
unsigned int key;
int irq;
unsigned int code;
unsigned int flag;//触发类型
const char* name;
int gpio;
struct timer_list timer;
irqreturn_t (*handler)(int , void *);
struct gpio_desc* gpio_desc;
};
static struct mykey keys[2];
static struct input_dev * g_input_dev;
//timer function
void timer_function(unsigned long data)
{
int value;
struct mykey* key = (struct mykey*)data;
value = gpio_get_value(key->gpio);
printk("%s code = %d value = %d\n",key->name, key->code, value);
printk("\n");
input_event(g_input_dev, EV_KEY, key->code, value);
input_sync(g_input_dev);
}
//irq handler
static irqreturn_t key_handler(int irq, void *dev_id)
{
struct mykey* key = (struct mykey*)dev_id;
key->timer.data = (unsigned long)dev_id;
mod_timer(&key->timer, jiffies + msecs_to_jiffies(20));//超时20ms
return IRQ_HANDLED;
}
static int my_key_probe(struct platform_device * pdev)
{
struct device_node *node = pdev->dev.of_node;
struct device_node * pp;
int key_nums;
int i = 0;
int ret;
printk("%s %s %d\n", __FILE__,__FUNCTION__, __LINE__);
//获取子节点的个数
key_nums = of_get_available_child_count(node);
if (key_nums == 0)
{
printk("not keys!/n");
return -1;
}
//找出节点中的所有子节点,并获取子节点信息
for_each_available_child_of_node(node, pp) {
//获取gpio
keys[i].gpio = of_get_named_gpio(pp, "key-gpios",0);
gpio_request(keys[i].gpio, keys[i].name);
gpio_direction_input(keys[i].gpio);
//获取按键的中断号
//keys[i].irq = irq_of_parse_and_map(pp, 0);
keys[i].gpio_desc = gpio_to_desc(keys[i].gpio);
keys[i].irq = gpiod_to_irq(keys[i].gpio_desc);
//获取按键的键码
of_property_read_u32(pp, "linux,code", &keys[i].code);
//获取触发类型
keys[i].flag = irq_get_trigger_type(keys[i].irq);
//获取label属性
keys[i].name = devm_kzalloc(&pdev->dev, sizeof(char)*20, GFP_KERNEL);
of_property_read_string(pp, "label", &keys[i].name);
printk("gpio = %d\n", keys[i].gpio);
printk("irq = %d\n", keys[i].irq);
printk("code = %d\n", keys[i].code);
printk("flag = %d\n", keys[i].flag);
printk("name = %s\n", keys[i].name);
printk("\n");
keys[i].handler = key_handler;
//ret = request_irq( keys[i].irq, keys[i].handler, keys[i].flag, keys[i].name, &keys[i]);
*//设置为上升沿时,正常,第一个按键和第二个按键,按下都只有一次中断*
* //ret = request_irq( keys[i].irq, keys[i].handler, IRQF_TRIGGER_RISING, keys[i].name, &keys[i]);*
* //设置为下降沿时,第一个按键按下有一次中断;第二个按键按下,会有两次中断*
* ret = request_irq( keys[i].irq, keys[i].handler, IRQF_TRIGGER_FALLING, keys[i].name, &keys[i]);*
if(ret < 0)
{
printk("request irq failed!\n");
return ret;
}
//初始化timer
init_timer(&keys[i].timer);
//设置timer
keys[i].timer.function = timer_function;
keys[i].timer.expires = jiffies + msecs_to_jiffies(20);
i++;
}
//分配input_dev
g_input_dev = devm_input_allocate_device(&pdev->dev);
if (!g_input_dev) {
dev_err(&pdev->dev, "failed to allocate input device\n");
return -ENOMEM;
}
//设置input_dev
g_input_dev->name = "input_dev_demo";
g_input_dev->phys = "input_dev_demo";
g_input_dev->dev.parent = &pdev->dev;
g_input_dev->id.bustype = BUS_HOST;
__set_bit(EV_KEY, g_input_dev->evbit);
//__set_bit(EV_REP, g_input_dev->evbit);
for(i = 0; i < key_nums; i++)
{
__set_bit(keys[i].code, g_input_dev->keybit);
}
//注册input_dev
ret = input_register_device(g_input_dev);
return 0;
}
static int my_key_remove(struct platform_device *pdev)
{
struct device_node *node = pdev->dev.of_node;
int key_nums;
int i = 0;
key_nums = of_get_available_child_count(node);
if (key_nums == 0)
{
printk("not keys!/n");
return -1;
}
for(i = 0; i < key_nums; i++)
{
gpio_free( keys[i].gpio);
free_irq( keys[i].irq, &keys[i]);
del_timer(& keys[i].timer);
}
input_unregister_device(g_input_dev);
input_free_device(g_input_dev);
return 0;
}
static const struct of_device_id my_key_of_match[] = {
{ .compatible = "100ask,my_key"},
{ },
};
static struct platform_driver my_gpio_key_driver = {
.probe = my_key_probe,
.remove = my_key_remove,
.driver = {
.name = "my_key",
.of_match_table = of_match_ptr(my_key_of_match),
}
};
static int __init gpio_keys_init(void)
{
printk("%s %s %d\n", __FILE__,__FUNCTION__, __LINE__);
return platform_driver_register(&my_gpio_key_driver);
}
static void __exit gpio_keys_exit(void)
{
printk("%s %s %d\n", __FILE__,__FUNCTION__, __LINE__);
platform_driver_unregister(&my_gpio_key_driver);
}
module_init(gpio_keys_init);
module_exit(gpio_keys_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("SSSS");
MODULE_DESCRIPTION("Keyboard driver for GPIOs");