海思GPIO中断学习

最近学习海思 调试wk2168驱动 先记录一下 等调试完成再来补全心得
转载于:https://www.cnblogs.com/zhuangquan/p/13801801.html

#include <linux/delay.h>
#include <linux/gpio.h>
#include <linux/interrupt.h>
#include <linux/module.h>
//模块参数,GPIO组号、组内偏移、方向、输出时的输出初始值
static unsigned int gpio_chip_num = 11;
module_param(gpio_chip_num, uint, S_IRUGO);
MODULE_PARM_DESC(gpio_chip_num, "gpio chip num");
 
static unsigned int gpio_offset_num = 2;
module_param(gpio_offset_num, uint, S_IRUGO);
MODULE_PARM_DESC(gpio_offset_num, "gpio offset num");
 
static unsigned int gpio_dir = 1;
module_param(gpio_dir, uint, S_IRUGO);
MODULE_PARM_DESC(gpio_dir, "gpio dir");
 
static unsigned int gpio_out_val = 1;
module_param(gpio_out_val, uint, S_IRUGO);
MODULE_PARM_DESC(gpio_out_val, "gpio out val");
 
//模块参数,中断触发类型
/*
 * 0 - disable irq
 * 1 - rising edge triggered
 * 2 - falling edge triggered
 * 3 - rising and falling edge triggered
 * 4 - high level triggered
 * 8 - low level triggered
 */
static unsigned int gpio_irq_type = 4;
module_param(gpio_irq_type, uint, S_IRUGO);
MODULE_PARM_DESC(gpio_irq_type, "gpio irq type");
 
spinlock_t lock;
 
static int gpio_dev_test_in(unsigned int gpio_num)
{
        //设置方向为输入
        if (gpio_direction_input(gpio_num)) {
                pr_err("[%s %d]gpio_direction_input fail!\n",
                                __func__, __LINE__);
                return -EIO;
        }
        //读出GPIO输入值
        pr_info ("[%s %d]gpio%d_%d in %d\n", __func__, __LINE__,
                        gpio_num / 8, gpio_num % 8,
                        gpio_get_value(gpio_num));
 
        return 0;
}
//中断处理函数
static irqreturn_t gpio_dev_test_isr(int irq, void *dev_id)
{
        pr_info("[%s %d]\n", __func__, __LINE__);
 
        return IRQ_HANDLED;
}
 
static int gpio_dev_test_irq(unsigned int gpio_num)
{
        unsigned int irq_num;
        unsigned int irqflags = 0;
        //设置方向为输入
        if (gpio_direction_input(gpio_num)) {
                pr_err("[%s %d]gpio_direction_input fail!\n",
                                __func__, __LINE__);
                return -EIO;
        }
 
        switch (gpio_irq_type) {
                case 1:
                        irqflags = IRQF_TRIGGER_RISING;
                        break;
                case 2:
                        irqflags = IRQF_TRIGGER_FALLING;
                        break;
                case 3:
                        irqflags = IRQF_TRIGGER_RISING |
                                IRQF_TRIGGER_FALLING;
                        break;
                case 4:
                        irqflags = IRQF_TRIGGER_HIGH;
                        break;
                case 8:
                        irqflags = IRQF_TRIGGER_LOW;
                        break;
                default:
                        pr_info("[%s %d]gpio_irq_type error!\n",
                                        __func__, __LINE__);
                        return -1;
        }
 
        pr_info("[%s %d]gpio_irq_type = %d\n", __func__, __LINE__, gpio_irq_type);
 
        /* IRQF_SHARED:这个中断标志经常能遇见,这个标志意思就是多个中断处理程序之间可以共享中断线,概括起来就是没有这个标志就只能独自一个人占用,标志了,就是很多人可以占用这个中断号来 */
        irqflags |= IRQF_SHARED;
        //根据GPIO编号映射中断号
        irq_num = gpio_to_irq(gpio_num);
        //注册中断
        /*
            irq_num:由gpio_to_irq()函数获取的中断号
            gpio_dev_test_isr:中断触发函数
            irqflags:中断触发类型
            "gpio_dev_test":设置中断名称,通常是设备驱动程序的名称  在cat /proc/interrupts中可以看到此名称。
            dev_id:最后一个参数,看到第三个参数中IRQF_SHARED时候,你会不会有这样的疑问,假如现在我要释放当前共享的指定这个中断程序时候,我如何释放?会不会把其他占用也会删除掉。
                    这就是第五个参数的意义,如果中断线是共享的,那么就必须传递能够代表当前设备的唯一信息。
 
            函数返回值:成功返回0。如果返回非0,就表示有错误发生,这个时候你可以考虑当前中断是否被占用了,所以可以加上IRQF_SHARED标志
        */
        if (request_irq(irq_num, gpio_dev_test_isr, irqflags,
                                "gpio_dev_test", &gpio_irq_type)) {
                pr_info("[%s %d]request_irq error!\n", __func__, __LINE__);
                return -1;
        }
 
        return 0;
}
 
static void gpio_dev_test_irq_exit(unsigned int gpio_num)
{
        unsigned long flags;
 
        pr_info("[%s %d]\n", __func__, __LINE__);
        //释放注册的中断
        spin_lock_irqsave(&lock, flags);
        free_irq(gpio_to_irq(gpio_num), &gpio_irq_type);
        spin_unlock_irqrestore(&lock, flags);
}
static int gpio_dev_test_out(unsigned int gpio_num, unsigned int gpio_out_val)
{
        //设置方向为输出,并输出一个初始值
        if (gpio_direction_output(gpio_num, !!gpio_out_val)) {
                pr_err("[%s %d]gpio_direction_output fail!\n",
                                __func__, __LINE__);
                return -EIO;
        }
 
        pr_info("[%s %d]gpio%d_%d out %d\n", __func__, __LINE__,
                                gpio_num / 8, gpio_num % 8, !!gpio_out_val);
        return 0;
}
 
static int __init gpio_dev_test_init(void)
{
        unsigned int gpio_num;
        int status = 0;
 
        pr_info("[%s %d]\n", __func__, __LINE__);
 
        //初始化自旋锁lock
        spin_lock_init(&lock);
 
        gpio_num = gpio_chip_num * 8 + gpio_offset_num;
        //注册要操作的GPIO编号
 
        /* 一般gpio_request封装了mem_request(),起保护作用,最后要调用mem_free之类的。主要是告诉内核这地址被占用了。当其它地方调用同一地址的gpio_request就会报告错误,该地址已被申请。在/proc/mem应该会有地址占用表描述。
        这种用法的保护作用前提是大家都遵守先申请再访问,有一个地方没遵守这个规则,这功能就失效了。好比进程互斥,必需大家在访问临界资源的时候都得先获取锁一样,其中一个没遵守约定,代码就废了。 */
        if (gpio_request(gpio_num, NULL)) {
                pr_err("[%s %d]gpio_request fail! gpio_num=%d \n", __func__, __LINE__, gpio_num);
                return -EIO;
        }
 
        status = gpio_dev_test_irq(gpio_num);
 
        if (status)
                gpio_free(gpio_num);
 
        return status;
}
 
 
static void __exit gpio_dev_test_exit(void)
{
        unsigned int gpio_num;
 
        pr_info("[%s %d]\n", __func__, __LINE__);
 
        gpio_num = gpio_chip_num * 8 + gpio_offset_num;
 
        if (gpio_irq_type)
                gpio_dev_test_irq_exit(gpio_num);
        //释放注册的GPIO编号
        gpio_free(gpio_num);
}
 
module_init(gpio_dev_test_init);
module_exit(gpio_dev_test_exit);
 
MODULE_DESCRIPTION("GPIO device test Driver sample");
MODULE_LICENSE("GPL");
 
/* cat /proc/devices    只显示驱动的主设备号,且是分类显示  arm-himix200-linux */
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值