z3j6w9 发表于 2017-6-9 15:19:03

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:20:03

本帖最后由 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");

z3j6w9 发表于 2017-6-9 15:23:18

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

raindy_s 发表于 2017-6-23 11:18:58

谢谢分享! 收藏了!

MontyFeng 发表于 2019-1-10 14:33:32

楼主,我按照你所说的进行操作步骤,代码与你给的一样,在进行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
请问能帮忙解决一下吗?

HaerLearn3288 发表于 2019-10-7 11:21:32

大佬写的简明易懂,学习了!
页: [1]
查看完整版本: firefly-rk3288实现的按键中断