本人使用的调试平台是荣品的rv1126开发板,最近在调试按键中断。经过查看原理图,发现竟然没有一个空闲的IO,所以使用UART1的RX作为按键中断引脚。 驱动部分: 因为UART1原先已经在设备树中已经有了定义,需要将 kernel/arch/arm/boot/dts/rongpin/rv1126_1109_common.dtsi 中的uart1去掉 //&uart1 { // pinctrl-names = "default"; // pinctrl-0 = <&uart1m0_xfer>; // status = "okay"; //}; 并在kernel/arch/arm/boot/dts/rp-rv1126.dts 中的rp_gpio,加入该IO: rp_gpio { status = "okay"; compatible = "rp_gpio"; gpio0b7{ gpio_num = <&gpio0 RK_PB7 IRQ_TYPE_EDGE_FALLING>; gpio_function = <2>; }; ...... 设备树修改完毕,下面开始编写代码。 rv1126的gpio采用的是gpiolib架构,工程师可以不必查阅寄存器即可完成配置,在kernal/drivers/rongpin/rp_gpio.c中修改。 1、修改probe: static int rp_gpio_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; struct device_node *child_np; 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; 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 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; #endif case 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++; } 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方向、注册中断函数、配置输入子系统、初始化定时器。其中定时器是用来消抖的。按键信号通过输入子系统传递到应用程序。 2、增加外部中断以及定时器服务函数。 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); } } 应用程序: 编写应用程序之前,先使用cat /proc/bus/input/devices 确定驱动使用了哪个输入子系统的event。 应用程序比较简单。 检测输入子系统信号采用一个线程,以下函数为线程函数: void *scan_key_main(void *data) { int fd = 0; struct input_event buttons_event; unsigned long cur_ms = 0; data = data; //fd = open("/dev/event0", O_RDWR | O_NONBLOCK); 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); } } 如果在调试过程中出现问题,可以使用hexdump /dev/input/eventX命令辅助调试。
标签:cnt,rp,RV1126,buttons,num,按键,gpio,data,调试 From: https://www.cnblogs.com/kn-zheng/p/17529074.html