当前位置: 代码网 > 服务器>服务器>Linux > [IMX6ULL驱动开发]-Linux对中断的处理(三)

[IMX6ULL驱动开发]-Linux对中断的处理(三)

2024年08月06日 Linux 我要评论
前两篇文章主要是理论上的知识,此文章主要内容为代码上的编写以及思路等。

目录

设备树中的操作

中断控制器

设备树中使用中断

编程思路

设备树相关

驱动程序相关


设备树中的操作

中断控制器

我们首先要在设备树当中创建对应的中断节点,首先我们需要了解一下中断控制器这个概念,在硬件的概念上,中断控制器其实只有gic,但是在软件上,我们也可以把gpio看为一个中断控制器,所以,从软件层面上看,中断控制器包括gic、gpio1、gpio2等,一个gpio上可能连接多个外部设备,它们共用一个中断号,此gpio控制这些中断号。

gpio1 连接到 gic,gpio2 连接到 gic,所以 gpio1 的父亲是 gic,gpio2 的父亲是 gic。

假设gpio1总共控制32个中断外部设备,假设其中16个共用一个中断号,另外16个共用另一个中断号,那么gpio1总共会使用到gic的两个中断号,会涉及 gic 里的 2 个 hwirq。这些都会在设备树当中体现出来。

在设备树当中,如果存在属性:interrupt-controller,则表示该节点为中断控制器,除此之外,还需要另外一个属性,#interrupt-cells,表示使用这个中断控制器需要多少个cell

如果中断控制器存在级联关系,那么子级的中断控制器需要指定自己的父级中断控制器为哪个,比如上级的gpio中断控制器需要指定自己的 interrupt-parent 为gic。


设备树中使用中断

一个外设,使用哪一个中断控制器,使用中断控制器的哪个引脚,中断的触发方式在设备树中是如何体现出来的。

为了方便,通常interrupt-parent和interrupts两个属性可以合起来,使用 interrupts-extended来进行表示。


编程思路

设备树相关

在这里,我们需要使用两个按键来触发中断,我们首先查阅引脚图,来判断使用的引脚以及触发的方式。

我们可以依照这些信息编写出如下设备树信息:

gpio_key_interrupt { 
    compatible = "100ask_interrupt_test";
	gpios = <&gpio5 1 gpio_active_low
	 		 &gpio4 14 gpio_active_low >;
    };

但是这些还是不够完整的,我们需要使用pinctrl来指定这两个引脚的为gpio功能,表明自身是哪一个 gpio 模块里的哪一个引脚。

使用引脚配置工具按照如下方式指定,然后把对应生成代码拷贝到dts文件当中

gpio5 1引脚的配置如上 gpio4 14所示,但是需要注意的是,存在的节点gpio4为iomuxc,但是gpio5为iomuxc_snvs。

gpio_key_interrupt { 
    compatible = "100ask_interrupt_test";
    gpios = <&gpio5 1 gpio_active_low
	 		  &gpio4 14 gpio_active_low >;

    pinctrl-names = "default";
	pinctrl-0 = <&key1_interrupt 
 				 &key2_interrupt>; 
    };

设备树文件就完成了,把它编译后,放置于开发板的 /boot/ 目录下。


驱动程序相关

驱动程序的主要思路如下:

如下结构体为 platform_driver结构体的填充,主要就是完成probe函数,在该结构体的driver成员的of_match_table的类型为 of_device_id 结构体,我们需要再定义一个此结构体,然后填充此结构体的compatible属性,用来匹配设备树。

probe函数主要实现在设备树中获取对应的引脚信息,然后通过对应的引脚信息来创建中断,创建中断的时候,需要创建中断处理函数,在这里我们的中断处理函数负责读取当前按键的值

remove函数主要用来通过对应的中断号来清除对应的中断,在这里我们还需要释放kzalloc申请的内核态的堆区空间

如果内核没有打印日志信息,使用如下命令:

makefile如下

kern_dir = /home/book/100ask_imx6ull-sdk/linux-4.9.88

all:
	make -c $(kern_dir) m=`pwd` modules 
	

clean:
	make -c $(kern_dir) m=`pwd` modules clean
	rm -rf modules.order
	
obj-m	+= interrupt_test.o

#include <linux/module.h>

#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/miscdevice.h>
#include <linux/kernel.h>
#include <linux/major.h>
#include <linux/mutex.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/stat.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/tty.h>
#include <linux/kmod.h>
#include <linux/gfp.h>
#include <linux/gpio/consumer.h>
#include <linux/platform_device.h>
#include <linux/of_gpio.h>
#include <linux/of_irq.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/slab.h>


/* 中断结构体,存储按键中断的gpio等信息 */
struct key_gpio{

	int gpio;
	int irq;
	enum of_gpio_flags flag;
	

};

static struct key_gpio* ket_interrupt_res;


/* 中断函数 */
static irqreturn_t irq_handler(int irq	, void *dev_id)
{
	struct key_gpio* p_key_gpio = (struct key_gpio*)dev_id;
	int val;

	val = gpio_get_value(p_key_gpio->gpio);

	printk("key %d %d\n", p_key_gpio->irq , val);

 
	return irq_handled;

}



int interrupt_test_probe(struct platform_device *pdev)
{
	int count = 0;
	int i = 0;
	struct device_node *node = pdev->dev.of_node;
	enum of_gpio_flags flag;
	int err;

	/* 获取gpio中断个数 */
	count = of_gpio_count(node);

	ket_interrupt_res = kzalloc(count * sizeof(struct key_gpio), gfp_kernel);	
	if( !count )
	{
		printk("%s %s line %d, there isn't any gpio available\n", __file__, __function__, __line__);
		return -1;
	}

	for( i = 0 ; i < count ; i++ )
	{
		ket_interrupt_res[i].gpio = of_get_gpio_flags(node , i , &flag);

		if( ket_interrupt_res[i].gpio < 0 )
		{
			printk("%s %s line %d, of_get_gpio_flags fail \n", __file__, __function__, __line__);
		}
		ket_interrupt_res[i].irq = gpio_to_irq(ket_interrupt_res[i].gpio);
		ket_interrupt_res[i].flag = flag & of_gpio_active_low;



		err = request_irq(ket_interrupt_res[i].irq, irq_handler, irqf_trigger_rising | irqf_trigger_falling, \
						  "ket_interrupt", &ket_interrupt_res[i]);
		
	}
	return 0;
	
	
}
int interrupt_test_remove(struct platform_device *pdev)
{
	struct device_node *node = pdev->dev.of_node;
	int count = 0;
	int i = 0;
	count = of_gpio_count(node);

	for( i = 0 ; i < count ; i++ )
	{
		free_irq(ket_interrupt_res[i].irq,&ket_interrupt_res[i]);
	}
	kfree(ket_interrupt_res);
    return 0;
	
}


static const struct of_device_id ask100_interrupt[] = {
    { .compatible = "100ask_interrupt_test" },
    { },
};



static struct platform_driver interrupt_test_driver = {
    .probe      = interrupt_test_probe,
    .remove     = interrupt_test_remove,
    .driver     = {
        .name   = "100ask_interrupt",
        .of_match_table = ask100_interrupt,
    },
};




static int __init interrupt_test_init(void)
{
    int err;
    
	printk("%s %s line %d\n", __file__, __function__, __line__);
	printk(" interrupt_test_driver register \n");
	
    err = platform_driver_register(&interrupt_test_driver); 
	
	return err;
}

static void __exit interrupt_test_exit(void)
{
	printk("%s %s line %d\n", __file__, __function__, __line__);
	printk(" interrupt_test_driver unregister \n");

    platform_driver_unregister(&interrupt_test_driver);
}


                                

module_init(interrupt_test_init);
module_exit(interrupt_test_exit);

module_license("gpl");





(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com