文章目录
- 选择GPIO
- 修改设备树
- 修改驱动源码probe:
- 增加外部中断以及定时器服务函数。
- 命令行测试中断
- 确定按键的输入子系统的event
- 使用hexdump命令测试按键实际效果
- 测试应用程序
- 完整的驱动代码
我使用的是荣品的pro-rv1126。
选择GPIO
结合原理图
决定使用UART1接口
接了一个独立按键模块,默认上拉,按下时低电平。
修改设备树
选择的这个GPIO默认是UART1,所以要先注释掉设备树中的描述。
编辑文件:rp_rv1126_sdk/kernel/arch/arm/boot/dts/rongpin/rv1126_1109_common.dtsi
/*&uart1 {pinctrl-names = "default";pinctrl-0 = <&uart1m0_xfer>;status = "okay";
};*/
在下面的文件中还需要增加内容。
编辑文件:rp_rv1126_sdk/kernel/arch/arm/boot/dts/pro-rv1126.dts
...//rpgpio initrp_gpio {status = "okay";compatible = "rp_gpio";gpio0b7{gpio_num = <&gpio0 RK_PB7 IRQ_TYPE_EDGE_FALLING>;gpio_function = <2>;}...
...
修改驱动源码probe:
rv1126的gpio采用的是gpiolib架构,工程师可以不必查阅寄存器即可完成配置,在kernal/drivers/rongpin/rp_gpio.c
中修改。
static int rp_gpio_probe(struct platform_device *pdev) {struct device_node *np = pdev->dev.of_node;struct device_node *child_np;struct device *dev = &pdev->dev;static struct proc_dir_entry *root_entry_gpio;enum of_gpio_flags gpio_flags;int ret = 0;int gpio_cnt = 0; char gpio_name_num[GPIO_NUM_MAX];int gpio_in_cnt = 0;int cnt =0;gpio_data = devm_kzalloc(&pdev->dev, sizeof(struct rp_gpio_data),GFP_KERNEL);if (!gpio_data) {dev_err(&pdev->dev, "failed to allocate memory\n");return -ENOMEM;}gpio_data->gpio_dts_num = of_get_child_count(np);printk("rp_gpio prepare build %d gpio\n",gpio_data->gpio_dts_num);if (gpio_data->gpio_dts_num == 0){dev_info(&pdev->dev, "no gpio defined\n");}/* create node */root_entry_gpio = proc_mkdir("rp_gpio", NULL);for_each_child_of_node(np, child_np){/* parse dts */gpio_data->rp_gpio_num[gpio_cnt].gpio_num = of_get_named_gpio_flags(child_np, "gpio_num", 0, &gpio_flags);if (!gpio_is_valid(gpio_data->rp_gpio_num[gpio_cnt].gpio_num)){return -1;} gpio_data->rp_gpio_num[gpio_cnt].gpio_name = (char*)child_np -> name;gpio_data->rp_gpio_num[gpio_cnt].action = gpio_flags;gpio_data->rp_gpio_num[gpio_cnt].gpio_ctrl = gpio_cnt;of_property_read_u32(child_np, "gpio_function", &(gpio_data->rp_gpio_num[gpio_cnt].gpio_function));printk("rp_gpio request %s\n",gpio_data->rp_gpio_num[gpio_cnt].gpio_name);switch(gpio_data->rp_gpio_num[gpio_cnt].gpio_function) {case GPIO_FUNCTION_INPUT : /* init input gpio */ret = gpio_request(gpio_data->rp_gpio_num[gpio_cnt].gpio_num, "gpio_num");if (ret < 0){printk("gpio%d request error\n",gpio_data->rp_gpio_num[gpio_cnt].gpio_num);}else{printk("success request gpio %d in\n",gpio_data->rp_gpio_num[gpio_cnt].gpio_num);//gpio_set_value(gpio_data->rp_gpio_num[gpio_cnt].gpio_num,!gpio_data->rp_gpio_num[gpio_cnt].action);gpio_direction_input(gpio_data->rp_gpio_num[gpio_cnt].gpio_num);event_flag = gpio_flags;of_property_read_u32(child_np, "send_mode", &(gpio_data->rp_gpio_num[gpio_cnt].send_mode));of_property_read_u32(child_np, "gpio_event", &(gpio_data->rp_gpio_num[gpio_cnt].gpio_event));gpio_in_cnt++;}break;#if 1 /* add code for liefyuan */case GPIO_FUNCTION_IRQ : /* init input gpio */ret = gpio_request(gpio_data->rp_gpio_num[gpio_cnt].gpio_num, "gpio_num");if (ret < 0){printk("gpio%d request error\n",gpio_data->rp_gpio_num[gpio_cnt].gpio_num);}else{printk("success request gpio %d irq\n",gpio_data->rp_gpio_num[gpio_cnt].gpio_num);//gpio_set_value(gpio_data->rp_gpio_num[gpio_cnt].gpio_num,!gpio_data->rp_gpio_num[gpio_cnt].action);printk("gpio_to_irq(gpio_data->rp_gpio_num[gpio_cnt].gpio_num) = %d\n",gpio_to_irq(gpio_data->rp_gpio_num[gpio_cnt].gpio_num));irq_gpio = gpio_data->rp_gpio_num[gpio_cnt].gpio_num;gpio_direction_input(gpio_data->rp_gpio_num[gpio_cnt].gpio_num);ret = request_irq(gpio_to_irq(gpio_data->rp_gpio_num[gpio_cnt].gpio_num),button_irq_handler,//IRQ_TYPE_EDGE_FALLING,IRQF_TRIGGER_FALLING|IRQF_TRIGGER_RISING,"key_irq",NULL);//1、分配一个input_dev结构体buttons_dev = input_allocate_device();if(!buttons_dev){printk("input_allocate_device error!\n");return -ENOMEM;}buttons_dev->name = "input_key";buttons_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP);input_set_capability(buttons_dev, EV_KEY, KEY_0);ret = input_register_device(buttons_dev);if (ret) {printk("register input device failed!\r\n");return ret;}//初始化定时器,用于按键消抖timer_setup(&buttons_timer,my_buttons_timer_function,0);buttons_timer.expires = jiffies + msecs_to_jiffies(20);add_timer(&buttons_timer);}break;#endifcase GPIO_FUNCTION_OUTPUT : /* init output gpio */ret = gpio_request(gpio_data->rp_gpio_num[gpio_cnt].gpio_num, "gpio_num");if (ret < 0){printk("gpio%d request error\n",gpio_data->rp_gpio_num[gpio_cnt].gpio_num);//return ret;}else{gpio_direction_output(gpio_data->rp_gpio_num[gpio_cnt].gpio_num,!gpio_data->rp_gpio_num[gpio_cnt].action);printk("success request gpio%d out\n",gpio_data->rp_gpio_num[gpio_cnt].gpio_num);}break;case GPIO_FUNCTION_FLASH :ret = gpio_request(gpio_data->rp_gpio_num[gpio_cnt].gpio_num, "gpio_num");if (ret < 0){printk("gpio%d request error\n",gpio_data->rp_gpio_num[gpio_cnt].gpio_num);//return ret;}else{gpio_direction_output(gpio_data->rp_gpio_num[gpio_cnt].gpio_num,!gpio_data->rp_gpio_num[gpio_cnt].action);printk("success request gpio%d flash\n",gpio_data->rp_gpio_num[gpio_cnt].gpio_num);gpio_in_cnt++;}break;}sprintf(gpio_name_num,gpio_data->rp_gpio_num[gpio_cnt].gpio_name,gpio_cnt);proc_create(gpio_name_num, 0666 , root_entry_gpio , &gpio_ops);gpio_cnt++;}if (gpio_in_cnt > 0){/* init timer */
#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 14, 0)) /* old linux version timer api */init_timer(&(gpio_data->mytimer));gpio_data->mytimer.expires = jiffies + msecs_to_jiffies(10000);gpio_data->mytimer.function = send_event;add_timer(&(gpio_data->mytimer));
#elsetimer_setup(&(gpio_data->mytimer), send_event, 0);gpio_data->mytimer.expires = jiffies + msecs_to_jiffies(10000);add_timer(&(gpio_data->mytimer));
#endif /* init struct input_dev */ gpio_data->input = devm_input_allocate_device(dev);gpio_data->input->name = "gpio_event"; /* pdev->name; */gpio_data->input->phys = "gpio_event/input1";gpio_data->input->dev.parent = dev;gpio_data->input->id.bustype = BUS_HOST;gpio_data->input->id.vendor = 0x0001;gpio_data->input->id.product = 0x0001;gpio_data->input->id.version = 0x0100;for(cnt = 0; cnt < gpio_cnt; cnt++){if (gpio_data->rp_gpio_num[cnt].gpio_function == 1){input_set_capability(gpio_data->input, EV_KEY, gpio_data->rp_gpio_num[cnt].gpio_event);}}ret = input_register_device(gpio_data->input);}gpio_wq = create_singlethread_workqueue("gpio_wq");INIT_WORK(&gpio_work, gpio_work_func);platform_set_drvdata(pdev, gpio_data); return 0;
}
代码中的case GPIO_FUNCTION_IRQ
是新增加的,主要是申请IO、设置IO方向、注册中断函数、配置输入子系统、初始化定时器。其中定时器是用来消抖的。
按键信号通过输入子系统传递到应用程序。
增加外部中断以及定时器服务函数。
unsigned irq_gpio;
static struct input_dev *buttons_dev;
static struct timer_list buttons_timer;static irqreturn_t button_irq_handler(int irq, void *dev_id)
{mod_timer(&buttons_timer, jiffies+msecs_to_jiffies(20));return IRQ_HANDLED;
}//定时器中断处理函数
static void my_buttons_timer_function(struct timer_list* list)
{int gpio_value = 0;gpio_value = gpio_get_value(irq_gpio);if(gpio_value == 0){input_report_key(buttons_dev, KEY_0, 1);input_sync(buttons_dev);}if(gpio_value == 1){input_report_key(buttons_dev, KEY_0, 0);input_sync(buttons_dev);}
}
命令行测试中断
确定按键的输入子系统的event
编写应用程序之前,先使用命令cat /proc/bus/input/devices
确定驱动使用的输入子系统的事件号。
使用命令:cat /proc/bus/input/devices
:
[root@RV1126_RV1109:/]# cat /proc/bus/input/devices
I: Bus=0019 Vendor=0000 Product=0000 Version=0000
N: Name="rk805 pwrkey"
P: Phys=rk805_pwrkey/input0
S: Sysfs=/devices/platform/ff3f0000.i2c/i2c-0/0-0020/rk805-pwrkey/input/input0
U: Uniq=
H: Handlers=event0
B: PROP=0
B: EV=3
B: KEY=100000 0 0 0I: Bus=0018 Vendor=dead Product=beef Version=28bb
N: Name="goodix-ts"
P: Phys=input/ts
S: Sysfs=/devices/virtual/input/input1
U: Uniq=
H: Handlers=event1
B: PROP=2
B: EV=b
B: KEY=40000800 40 0 0 0
B: ABS=2658000 0I: Bus=0019 Vendor=0001 Product=0001 Version=0100
N: Name="gpio_event"
P: Phys=gpio_event/input1
S: Sysfs=/devices/platform/rp_power/input/input2
U: Uniq=
H: Handlers=event2
B: PROP=0
B: EV=3
B: KEY=100000 0 0 0I: Bus=0000 Vendor=0000 Product=0000 Version=0000
N: Name="input_key"
P: Phys=
S: Sysfs=/devices/virtual/input/input3
U: Uniq=
H: Handlers=event3
B: PROP=0
B: EV=100003
B: KEY=800I: Bus=0019 Vendor=0001 Product=0001 Version=0100
N: Name="adc-keys"
P: Phys=adc-keys/input0
S: Sysfs=/devices/platform/adc-keys/input/input4
U: Uniq=
H: Handlers=event4
B: PROP=0
B: EV=3
B: KEY=800 600 0 0 2I: Bus=0000 Vendor=0000 Product=0000 Version=0000
N: Name="rockchip,rk809-codec Headphones"
P: Phys=ALSA
S: Sysfs=/devices/platform/rk809-sound/sound/card1/input5
U: Uniq=
H: Handlers=event5
B: PROP=0
B: EV=21
B: SW=4I: Bus=0003 Vendor=046d Product=c52f Version=0111
N: Name="Logitech USB Receiver"
P: Phys=usb-ffe00000.usb-1.3/input0
S: Sysfs=/devices/platform/ffe00000.usb/usb1/1-1/1-1.3/1-1.3:1.0/0003:046D:C52F.0001/input/input6
U: Uniq=
H: Handlers=event6
B: PROP=0
B: EV=17
B: KEY=ffff0000 0 0 0 0 0 0 0 0
B: REL=143
B: MSC=10I: Bus=0003 Vendor=046d Product=c52f Version=0111
N: Name="Logitech USB Receiver Consumer Control"
P: Phys=usb-ffe00000.usb-1.3/input1
S: Sysfs=/devices/platform/ffe00000.usb/usb1/1-1/1-1.3/1-1.3:1.1/0003:046D:C52F.0002/input/input7
U: Uniq=
H: Handlers=event7
B: PROP=0
B: EV=1f
B: KEY=300ff 0 0 0 0 483ffff 17aff32d bf544446 0 0 1 130ff3 8b17c000 677bfa d9415fed 9ed680 4400 0 10000002
B: REL=40
B: ABS=1 0
B: MSC=10
结合代码中关于输入设备结构体参数的描述:
//1、分配一个input_dev结构体
buttons_dev = input_allocate_device();
if(!buttons_dev)
{printk("input_allocate_device error!\n");return -ENOMEM;
}
buttons_dev->name = "input_key";
buttons_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP);
input_set_capability(buttons_dev, EV_KEY, KEY_0);
名字是:“input_key”
所以可以知道:
I: Bus=0000 Vendor=0000 Product=0000 Version=0000
N: Name="input_key"
P: Phys=
S: Sysfs=/devices/virtual/input/input3
U: Uniq=
H: Handlers=event3
B: PROP=0
B: EV=100003
B: KEY=800
就是按键事件对应的就是:/dev/input/event3
使用hexdump命令测试按键实际效果
使用hexdump /dev/input/eventX
命令辅助调试
[root@RV1126_RV1109:/]# hexdump /dev/input/event3
0000000 028b 0000 4ed0 0009 0001 000b 0001 0000
0000010 028b 0000 4ed0 0009 0000 0000 0000 0000
0000020 028b 0000 05ae 000d 0001 000b 0000 0000
0000030 028b 0000 05ae 000d 0000 0000 0000 0000
按键按下释放有数据打印,说明驱动基本上是通了!
另外在上电打印信息与设备树代码对比:
测试应用程序
由上面可以知道自定义的那个按键的节点是/dev/input/event3
由此可以编写一个应用层的测试程序。
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>int main(int argc, char **argv)
{int fd = 0;struct input_event buttons_event;unsigned long cur_ms = 0;data = data;fd = open("/dev/input/event3", O_RDWR);if (fd < 0)printf("can't open!\n");while (1){read(fd, &buttons_event, sizeof(struct input_event));// if(buttons_event.type == EV_SYN)
// continue;cur_ms = (buttons_event.time.tv_sec * 1000) + (buttons_event.time.tv_usec/1000);//打印时间,事件类型,事件码,事件值printf("cur_ms:%ld type:0x%x code:%d value:%d\n",cur_ms,buttons_event.type,buttons_event.code,buttons_event.value);}close(fd);return 0;
}
完整的驱动代码
最后完整的rp_gpio.c
/* ****************************
*rpdzkj power contral driver *
* Platform : Rockchip Android *
* Version : v2.0.1 *
* Update Date : 20220124 *
* author : jeff *
*********************************/#include <linux/module.h>
#include <linux/err.h>
#include <linux/gpio.h>
#include <linux/kernel.h>
#include <linux/of_gpio.h>
#include <linux/of_platform.h>
#include <linux/delay.h>
#include <linux/input.h>
#include <linux/proc_fs.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <asm/uaccess.h>
#include <linux/string.h>
#include <linux/uaccess.h>
#include <linux/irq.h>
#include <linux/of_irq.h>
#include <linux/io.h>
#include <linux/interrupt.h>
#include <linux/version.h>#define GPIO_NUM_MAX 40#define GPIO_FUNCTION_OUTPUT 0
#define GPIO_FUNCTION_INPUT 1
#define GPIO_FUNCTION_IRQ 2
#define GPIO_FUNCTION_FLASH 3static int flash_flag = 0;
static int flash_counter = 0;struct rp_gpio {int gpio_num; //gpui numint gpio_irq;int action; //gpio flagint gpio_event; //input onlyint send_mode; //input onlyint gpio_function; //gpio function,i/oint gpio_ctrl;char *gpio_name;
};struct rp_gpio_data {struct rp_gpio rp_gpio_num[GPIO_NUM_MAX];struct input_dev *input;struct timer_list mytimer;int gpio_dts_num;
};static struct rp_gpio_data *gpio_data = NULL;
static int event_flag = 0;
static int open_now = 0;
static char* file_name = NULL;static struct workqueue_struct *gpio_wq;
static struct work_struct gpio_work;/************************************************************************/
unsigned irq_gpio;
static struct input_dev *buttons_dev;
static struct timer_list buttons_timer;static irqreturn_t button_irq_handler(int irq, void *dev_id)
{mod_timer(&buttons_timer, jiffies+msecs_to_jiffies(20));return IRQ_HANDLED;
}//定时器中断处理函数
static void my_buttons_timer_function(struct timer_list* list)
{int gpio_value = 0;gpio_value = gpio_get_value(irq_gpio);if(gpio_value == 0){input_report_key(buttons_dev, KEY_0, 1);input_sync(buttons_dev);}if(gpio_value == 1){input_report_key(buttons_dev, KEY_0, 0);input_sync(buttons_dev);}
}
/*****************************************************************************/static int gpio_open(struct inode *inode, struct file *file)
{struct dentry* dent = file->f_path.dentry;int i = 0;file_name = (char*)(dent->d_name.name);for (i = 0; i < gpio_data->gpio_dts_num; i++){if(!strcmp(file_name,gpio_data->rp_gpio_num[i].gpio_name)){open_now = i;}}return 0;
}static ssize_t gpio_write(struct file *file, const char *buffer,size_t count, loff_t *data)
{char buf[2]={0};char s1[]="1";if(copy_from_user(&buf[0],buffer,1)){printk("failed to copy data to kernel space\n");return -EFAULT; }if(!strcmp(buf,s1)){gpio_set_value(gpio_data->rp_gpio_num[open_now].gpio_num,1);
// printk("%s write 1 succeed\n",gpio_data->rp_gpio_num[open_now].gpio_name);}else{ gpio_set_value(gpio_data->rp_gpio_num[open_now].gpio_num,0);
// printk("%s write 0 succeed\n",gpio_data->rp_gpio_num[open_now].gpio_name);}return count;
}static ssize_t gpio_read(struct file *file, char __user * buffer, size_t count, loff_t *data)
{int gpio_val = 0;int len = 0;char s[10] = {0};if(*data)return 0;gpio_val = gpio_get_value(gpio_data->rp_gpio_num[open_now].gpio_num);
// printk("get %s value %d\n",gpio_data->rp_gpio_num[open_now].gpio_name,gpio_val);len = sprintf(s+len, "%d\n",gpio_val); return simple_read_from_buffer(buffer, count, data, s, 2);
}static const struct file_operations gpio_ops = {.owner = THIS_MODULE,.open = gpio_open,.write = gpio_write,.read = gpio_read,
};static void gpio_work_func(struct work_struct *work){int gpio_value = 0;int i = 0;flash_counter++;for(i = 0; i <= gpio_data->gpio_dts_num; i++) {switch(gpio_data->rp_gpio_num[i].gpio_function) {case GPIO_FUNCTION_INPUT :gpio_value = gpio_get_value(gpio_data->rp_gpio_num[i].gpio_num);if(gpio_value == 1){input_report_key(gpio_data->input, gpio_data->rp_gpio_num[i].gpio_event, 1);input_sync(gpio_data->input);}if(gpio_value == 0){input_report_key(gpio_data->input, gpio_data->rp_gpio_num[i].gpio_event, 0);input_sync(gpio_data->input);}//printk("\n%s gpio num %d %d\n",__func__,gpio_data->rp_gpio_num[i].gpio_num,gpio_value);//printk("\n%s send event %d\n",__func__,gpio_data->rp_gpio_num[i].gpio_event);break;case GPIO_FUNCTION_FLASH :if (10 == flash_counter){gpio_set_value(gpio_data->rp_gpio_num[i].gpio_num,!flash_flag);}break;}}if (10 == flash_counter){flash_flag = !flash_flag;flash_counter = 0;}}#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 14, 0))
static void send_event(unsigned long data){
#else
static void send_event(struct timer_list* list){
#endifqueue_work(gpio_wq, &gpio_work);mod_timer(&(gpio_data->mytimer), jiffies + msecs_to_jiffies(200));
}static int rp_gpio_probe(struct platform_device *pdev) {struct device_node *np = pdev->dev.of_node;struct device_node *child_np;struct device *dev = &pdev->dev;static struct proc_dir_entry *root_entry_gpio;enum of_gpio_flags gpio_flags;int ret = 0;int gpio_cnt = 0; char gpio_name_num[GPIO_NUM_MAX];int gpio_in_cnt = 0;int cnt =0;gpio_data = devm_kzalloc(&pdev->dev, sizeof(struct rp_gpio_data),GFP_KERNEL);if (!gpio_data) {dev_err(&pdev->dev, "failed to allocate memory\n");return -ENOMEM;}gpio_data->gpio_dts_num = of_get_child_count(np);printk("rp_gpio prepare build %d gpio\n",gpio_data->gpio_dts_num);if (gpio_data->gpio_dts_num == 0){dev_info(&pdev->dev, "no gpio defined\n");}/* create node */root_entry_gpio = proc_mkdir("rp_gpio", NULL);for_each_child_of_node(np, child_np){/* parse dts */gpio_data->rp_gpio_num[gpio_cnt].gpio_num = of_get_named_gpio_flags(child_np, "gpio_num", 0, &gpio_flags);if (!gpio_is_valid(gpio_data->rp_gpio_num[gpio_cnt].gpio_num)){return -1;} gpio_data->rp_gpio_num[gpio_cnt].gpio_name = (char*)child_np -> name;gpio_data->rp_gpio_num[gpio_cnt].action = gpio_flags;gpio_data->rp_gpio_num[gpio_cnt].gpio_ctrl = gpio_cnt;of_property_read_u32(child_np, "gpio_function", &(gpio_data->rp_gpio_num[gpio_cnt].gpio_function));printk("rp_gpio request %s\n",gpio_data->rp_gpio_num[gpio_cnt].gpio_name);switch(gpio_data->rp_gpio_num[gpio_cnt].gpio_function) {case GPIO_FUNCTION_INPUT : /* init input gpio */ret = gpio_request(gpio_data->rp_gpio_num[gpio_cnt].gpio_num, "gpio_num");if (ret < 0){printk("gpio%d request error\n",gpio_data->rp_gpio_num[gpio_cnt].gpio_num);}else{printk("success request gpio %d in\n",gpio_data->rp_gpio_num[gpio_cnt].gpio_num);//gpio_set_value(gpio_data->rp_gpio_num[gpio_cnt].gpio_num,!gpio_data->rp_gpio_num[gpio_cnt].action);gpio_direction_input(gpio_data->rp_gpio_num[gpio_cnt].gpio_num);event_flag = gpio_flags;of_property_read_u32(child_np, "send_mode", &(gpio_data->rp_gpio_num[gpio_cnt].send_mode));of_property_read_u32(child_np, "gpio_event", &(gpio_data->rp_gpio_num[gpio_cnt].gpio_event));gpio_in_cnt++;}break;#if 1 /* add code for liefyuan */case GPIO_FUNCTION_IRQ : /* init input gpio */ret = gpio_request(gpio_data->rp_gpio_num[gpio_cnt].gpio_num, "gpio_num");if (ret < 0){printk("gpio%d request error\n",gpio_data->rp_gpio_num[gpio_cnt].gpio_num);}else{printk("success request gpio %d irq\n",gpio_data->rp_gpio_num[gpio_cnt].gpio_num);//gpio_set_value(gpio_data->rp_gpio_num[gpio_cnt].gpio_num,!gpio_data->rp_gpio_num[gpio_cnt].action);printk("gpio_to_irq(gpio_data->rp_gpio_num[gpio_cnt].gpio_num) = %d\n",gpio_to_irq(gpio_data->rp_gpio_num[gpio_cnt].gpio_num));irq_gpio = gpio_data->rp_gpio_num[gpio_cnt].gpio_num;gpio_direction_input(gpio_data->rp_gpio_num[gpio_cnt].gpio_num);ret = request_irq(gpio_to_irq(gpio_data->rp_gpio_num[gpio_cnt].gpio_num),button_irq_handler,//IRQ_TYPE_EDGE_FALLING,IRQF_TRIGGER_FALLING|IRQF_TRIGGER_RISING,"key_irq",NULL);//1、分配一个input_dev结构体buttons_dev = input_allocate_device();if(!buttons_dev){printk("input_allocate_device error!\n");return -ENOMEM;}buttons_dev->name = "input_key";buttons_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP);input_set_capability(buttons_dev, EV_KEY, KEY_0);ret = input_register_device(buttons_dev);if (ret) {printk("register input device failed!\r\n");return ret;}//初始化定时器,用于按键消抖timer_setup(&buttons_timer,my_buttons_timer_function,0);buttons_timer.expires = jiffies + msecs_to_jiffies(20);add_timer(&buttons_timer);}break;#endifcase GPIO_FUNCTION_OUTPUT : /* init output gpio */ret = gpio_request(gpio_data->rp_gpio_num[gpio_cnt].gpio_num, "gpio_num");if (ret < 0){printk("gpio%d request error\n",gpio_data->rp_gpio_num[gpio_cnt].gpio_num);//return ret;}else{gpio_direction_output(gpio_data->rp_gpio_num[gpio_cnt].gpio_num,!gpio_data->rp_gpio_num[gpio_cnt].action);printk("success request gpio%d out\n",gpio_data->rp_gpio_num[gpio_cnt].gpio_num);}break;case GPIO_FUNCTION_FLASH :ret = gpio_request(gpio_data->rp_gpio_num[gpio_cnt].gpio_num, "gpio_num");if (ret < 0){printk("gpio%d request error\n",gpio_data->rp_gpio_num[gpio_cnt].gpio_num);//return ret;}else{gpio_direction_output(gpio_data->rp_gpio_num[gpio_cnt].gpio_num,!gpio_data->rp_gpio_num[gpio_cnt].action);printk("success request gpio%d flash\n",gpio_data->rp_gpio_num[gpio_cnt].gpio_num);gpio_in_cnt++;}break;}sprintf(gpio_name_num,gpio_data->rp_gpio_num[gpio_cnt].gpio_name,gpio_cnt);proc_create(gpio_name_num, 0666 , root_entry_gpio , &gpio_ops);gpio_cnt++;}if (gpio_in_cnt > 0){/* init timer */
#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 14, 0)) /* old linux version timer api */init_timer(&(gpio_data->mytimer));gpio_data->mytimer.expires = jiffies + msecs_to_jiffies(10000);gpio_data->mytimer.function = send_event;add_timer(&(gpio_data->mytimer));
#elsetimer_setup(&(gpio_data->mytimer), send_event, 0);gpio_data->mytimer.expires = jiffies + msecs_to_jiffies(10000);add_timer(&(gpio_data->mytimer));
#endif /* init struct input_dev */ gpio_data->input = devm_input_allocate_device(dev);gpio_data->input->name = "gpio_event"; /* pdev->name; */gpio_data->input->phys = "gpio_event/input1";gpio_data->input->dev.parent = dev;gpio_data->input->id.bustype = BUS_HOST;gpio_data->input->id.vendor = 0x0001;gpio_data->input->id.product = 0x0001;gpio_data->input->id.version = 0x0100;for(cnt = 0; cnt < gpio_cnt; cnt++){if (gpio_data->rp_gpio_num[cnt].gpio_function == 1){input_set_capability(gpio_data->input, EV_KEY, gpio_data->rp_gpio_num[cnt].gpio_event);}}ret = input_register_device(gpio_data->input);}gpio_wq = create_singlethread_workqueue("gpio_wq");INIT_WORK(&gpio_work, gpio_work_func);platform_set_drvdata(pdev, gpio_data); return 0;
}static int rp_gpio_remove(struct platform_device *pdev)
{return 0;
}static const struct of_device_id rp_gpio_of_match[] = {{ .compatible = "rp_gpio" },{ }
};static struct platform_driver rp_gpio_driver = {.probe = rp_gpio_probe,.remove = rp_gpio_remove,.driver = {.name = "rp_gpio",.of_match_table = of_match_ptr(rp_gpio_of_match),},
};module_platform_driver(rp_gpio_driver);
MODULE_LICENSE("GPL");