【RV1126】按键中断--使用输入子系统事件方式

news/2024/11/29 8:33:59/

文章目录

  • 选择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");

http://www.ppmy.cn/news/380575.html

相关文章

算法leetcode|57. 插入区间(rust重拳出击)

文章目录 57. 插入区间&#xff1a;样例 1&#xff1a;样例 2&#xff1a;样例 3&#xff1a;样例 4&#xff1a;样例 5&#xff1a;提示&#xff1a; 分析&#xff1a;题解&#xff1a;rust&#xff1a;go&#xff1a;c&#xff1a;python&#xff1a;java&#xff1a; 57. 插…

Armbian 系统 23.05 发布

导读Armbian 社区今天发布了用于 ARM 和 RISC-V 单板计算机以及其他平台的 Armbian 23.05&#xff08;代号 Suni&#xff09;操作系统。 在 Armbian 23.02 发布三个月后&#xff0c;Armbian 23.05 版本首次在完全重构的构建框架上创建&#xff0c;并基于即将发布的 Debian 12“…

etcd基本使用

目录 CRUD1、基本的put/get/del2、获取当前所有的key3、获取/删除带有前缀的键 lease使用1、创建lease&#xff0c;续租lease&#xff0c;撤销lease2、将lease attach到key上 watch使用watch、watch_oncereplacedeletewatch_prefix、watch_prefix_oncecancel_watchadd_watch_ca…

【每日一题Day237】LC1375二进制字符串前缀一致的次数 | 技巧题

二进制字符串前缀一致的次数【LC1375】 给你一个长度为 n 、下标从 1 开始的二进制字符串&#xff0c;所有位最开始都是 0 。我们会按步翻转该二进制字符串的所有位&#xff08;即&#xff0c;将 0 变为 1&#xff09;。 给你一个下标从 1 开始的整数数组 flips &#xff0c;其…

Java的垃圾回收机制详解

目录 1、C语言与Java语言垃圾回收区别 2、System.gc() 3、面试题引入Java垃圾回收 3.1 jvm怎么确定哪些对象应该进行回收 3.1.1 引用计数法 3.1.2 可达性分析算法 3.2 jvm会在什么时候进行垃圾回收的动作 3.2 jvm到底是怎么回收垃圾对象的 4、来回收算法 4.1 标记-清…

Qt6之样式表2

一、样式选择器类型 一般情况下组件最终都会产生父子、子孙等关系&#xff0c;此时样式选择器类型非常重要&#xff0c;它决定着你的类型是否互相直接独立、互相影响和便捷高效的快速设置样式。 1、如下图常见的一个工具栏&#xff0c;切换时鼠标划过是灰色&#xff0c;选中后是…

电动汽车车载充电机 (OBC) 与车载 DC/DC 转换器技术

电动汽车车载充电机 (OBC) 与车载 DC/DC 转换器技术一、高性能电动汽车车载充电机(OBC) 电路二、双向充电机(Bi-OBC &#xff09;技术方案三、车载DC/DC 转换器电路拓扑比较四、充电桩电力电子变换器 电动汽车车载充电机 (OBC) 与车载 DC/DC 转换器技术&#xff1a;https://pan…

18款美规奔驰S500升级车载冰箱系统,提升舒适性

凉爽餐饮随时唾手可得–后排冷藏箱让乘客能够随时享受美味。它完美集成于后排扶手中&#xff0c;容积约为8.5升。