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;
intflag;
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
请问能帮忙解决一下吗? 大佬写的简明易懂,学习了!
页:
[1]