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

文章目录

  • 选择GPIO
  • 修改设备树
  • 修改驱动源码probe:
  • 增加外部中断以及定时器服务函数。
  • 命令行测试中断
    • 确定按键的输入子系统的event
    • 使用hexdump命令测试按键实际效果
  • 测试应用程序
  • 完整的驱动代码

我使用的是荣品的pro-rv1126。

选择GPIO

结合原理图
【RV1126】按键中断--使用输入子系统事件方式_第1张图片决定使用UART1接口
【RV1126】按键中断--使用输入子系统事件方式_第2张图片
接了一个独立按键模块,默认上拉,按下时低电平。
【RV1126】按键中断--使用输入子系统事件方式_第3张图片

修改设备树

选择的这个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 init
	rp_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;
		#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++;
	}
	
	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));
#else
		timer_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 0

I: 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 0

I: 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 0

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

I: 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 2

I: 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=4

I: 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=10

I: 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

按键按下释放有数据打印,说明驱动基本上是通了!

另外在上电打印信息与设备树代码对比:
【RV1126】按键中断--使用输入子系统事件方式_第4张图片

测试应用程序

由上面可以知道自定义的那个按键的节点是/dev/input/event3由此可以编写一个应用层的测试程序。

#include 
#include 
#include 

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 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#define GPIO_NUM_MAX 40

#define GPIO_FUNCTION_OUTPUT 0
#define GPIO_FUNCTION_INPUT 1
#define GPIO_FUNCTION_IRQ 2
#define GPIO_FUNCTION_FLASH 3

static int flash_flag = 0;
static int flash_counter = 0;

struct rp_gpio {
	int gpio_num;		//gpui num
	int gpio_irq;
	int action;			//gpio flag
	int gpio_event;		//input only
	int send_mode;		//input only
	int gpio_function;	//gpio function,i/o
	int 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){
#endif

	queue_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;
		#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++;
	}
	
	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));
#else
		timer_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");

你可能感兴趣的:(RV1126,嵌入式Linux驱动,linux)