firefly-rk3288实现的按键中断

目前在学习驱动,之前在书上看了linux的中断,现在手边正好有个震动马达和按键,就用现成了材料写了个按键中断的驱动程序,还有部分疑惑,希望在和大家学习交流的过程中,能有人指出我的不足。
首先是我的设备树配置,如下图所示,可以看到的是我使用的是GPIO7 A3和GPIO0 B5,一个控制马达,一个控制按键



按键原本接GND的我接的是VCC,因为我不会设置上拉(还是根本没有,这个希望有人能解答下,因为芯片手册不全,很苦恼)
驱动使用的是platform总先,通过of开头的函数可以获取到我们在设备树种定义的硬件信息

获取到GPIO后,我们就可以使用这个gpio号去申请中断了,申请的函数是request_irq(),申请中断后需要使能中断,就是单片机的mask

参数1是中断号,参数2是中断处理函数,参数3是中断触发方式,参数4是名字,参数5是传给中断处理函数的参数,这个时候我们就可以在中断处理函数中执行我们的操作了,这个地方的中断处理只是中断顶半部,因为这只是个按键操作,没有必要用到中断底半部,如果有比较耗时的操作,还是建议放到中断底半部去。

本帖最后由 z3j6w9 于 2017-6-9 15:22 编辑

#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/gpio.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/interrupt.h>
#include <asm/irq.h>

#ifdef CONFIG_OF
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/of_platform.h>
#endif

#define GPIO_LOW 0
#define GPIO_HIGH 1

static int gpio7_a3;
static int gpio0_b5;
static int global_major;
static int irq;
static struct class *motor_class;
static struct device *motor_device;

irqreturn_t motor_irq_handler(int irq, void *dev_id)
{
	int gpio_voltage = 0;
	static int cnt = 0;
	printk("%s \n", __FUNCTION__);
	gpio_voltage = gpio_get_value(gpio0_b5);
	if (gpio_voltage)
	{
		cnt++;
	}
	else
	{
		cnt = 0;
	}
	if (cnt == 8)
	{
		gpio_set_value(gpio7_a3, GPIO_HIGH);
		mdelay(50);
		gpio_set_value(gpio7_a3, GPIO_LOW);
		cnt = 0;
	}
	return IRQ_HANDLED;
}

static int MOTOR_probe(struct platform_device *pdev)
{
	int ret = -1;
	int  flag;
	struct gpio_desc *gpio_desc = NULL;
	struct device_node *motor_node = pdev->dev.of_node;

	printk(KERN_INFO "motor-probe\n");
	gpio7_a3 = of_get_named_gpio_flags(motor_node, "motor-out", 0, &flag);
	if (!gpio_is_valid(gpio7_a3))
	{
		printk("gpio7_a3 is invalid\n");
	}

	ret = gpio_request(gpio7_a3, "motor");
	if (0 != ret)
	{
		printk("free gpio7_a3\n");
		gpio_free(gpio7_a3);
		return -EIO;
	}

	gpio0_b5 = of_get_named_gpio(motor_node, "key-out", 0);
	if (!gpio_is_valid(gpio0_b5))
	{
		printk("gpio0_a7 is invalid.\n");
	}

	ret = gpio_request(gpio0_b5, "motor");
	if (0 != ret)
	{
		printk("free gpio0_b5\n");
		gpio_free(gpio0_b5);
		return -EIO;
	}

	gpio_direction_output(gpio7_a3, GPIO_LOW);
	//gpio_direction_input(gpio0_b5);
	irq = __gpio_to_irq(gpio0_b5);
	if (ENXIO == irq)
	{
		printk("Get irq failed. \n");
		return -EFAULT;
	}
	ret = request_irq(irq, motor_irq_handler, IRQF_TRIGGER_HIGH, "motor", &gpio0_b5);
	if (ret)
	{
		printk("Request irq failed.%s \n", __FUNCTION__);
		return -EFAULT;
	}

	enable_irq(irq);

#if 0

	for (i=0; i < 10; ++i)
	{
		gpio_set_value(gpio, GPIO_LOW);
		mdelay(5000);
		gpio_set_value(gpio, GPIO_HIGH);
		mdelay(5000);
	}
#endif

	return 0;
}

static int MOTOR_remove(struct platform_device *pdev)
{
	free_irq(irq, &gpio0_b5);
	return 0;
}

#ifdef CONFIG_OF
static const struct of_device_id of_motor_match[] = {
	{	.compatible = "vr, motor"},
	{				 },
};
#endif

static struct platform_driver motor_driver = {
	.probe = MOTOR_probe,
	.remove = MOTOR_remove,
	.driver = {
		.name = "motor",
		.owner = THIS_MODULE,
		.of_match_table = of_motor_match,
	},
};

ssize_t motor_read(struct file *filep, char __user *buf, size_t size, loff_t *offset)
{
	int gpio_value = 0;
	gpio_value = gpio_get_value(gpio0_b5);
	(void)copy_to_user(buf,&gpio_value,1);
	return 0;
}

ssize_t motor_write(struct file *filep, const char __user *buf, size_t size, loff_t *offset)
{
#if 1
	gpio_set_value(gpio7_a3, GPIO_HIGH);
	mdelay(10);
	gpio_set_value(gpio7_a3, GPIO_LOW);
#endif
	return 0;
}

int motor_open(struct inode *inode, struct file *filep)
{
	return 0;
}

int motor_release(struct inode *inode, struct file *filep)
{
	return 0;
}

static struct file_operations motor_fops = {
	.owner =   THIS_MODULE,
	.read  =   motor_read,
	.write =   motor_write,
	.open  =   motor_open,
	.release = motor_release,
};

static int __init MOTOR_init(void)
{
	printk("motor driver init \n");

	//int devno = MKDEV(global_major, 0);
	//int ret = 0;
	/*
	if (global_major)
	{
		ret = register_chrdev_region(devno, 1, "motor");
	}
	else
	{
		ret = alloc_chrdev_region(&devno, 0, 1, "motor");
	}
	*/

	/*system will auto allocate major*/
	global_major = register_chrdev(0, "motor", &motor_fops);

	/*create class*/
	motor_class = class_create(THIS_MODULE, "motordrv");

	/*create device for app*/
	motor_device = device_create(motor_class, NULL, MKDEV(global_major, 0),NULL,"motor");

	//if (ret < 0)
	//	return ret;
	platform_driver_register(&motor_driver);
	return 0;
}

static void __exit MOTOR_exit(void)
{
	device_destroy(motor_class,MKDEV(global_major, 0));
	class_destroy(motor_class);
	//unregister_chrdev_region(MKDEV(global_major, 0), 1);
	unregister_chrdev(global_major, "motor");
	platform_driver_unregister(&motor_driver);
}

subsys_initcall(MOTOR_init);
module_exit(MOTOR_exit);

MODULE_LICENSE("GPL");

不知道为啥不能上传.c文件,只好贴一下代码了,还好代码比较少。

谢谢分享! 收藏了!

楼主,我按照你所说的进行操作步骤,代码与你给的一样,在进行platform_driver_register后,遇到了如下问题:
[ 7243.851937] platform_driver_register success!
[ 7243.852583] rockchip_rt5631_audio_probe…
[ 7243.853074] rockchip-rt5631 rockchip-rt5631.31: ASoC: CODEC (null) not registered
[ 7243.853179] rockchip_rt5631_audio_probe() register card failed:-517
[ 7243.853392] platform rockchip-rt5631.31: Driver rockchip-rt5631 requests probe deferral
请问能帮忙解决一下吗?

大佬写的简明易懂,学习了!