0
点赞
收藏
分享

微信扫一扫

嵌入式Linux设备驱动程序开发指南12(处理设备驱动中使用的中断)——读书笔记

天蓝Sea 2022-03-30 阅读 18

处理设备驱动中使用的中断

十二、处理设备驱动中使用的中断

12.1 Linux内核的中断域

IRQ是来自设备的中断请求,不同设备可以共享中断线,从而可以共享IRQ。中断控制器驱动将irq_chip数据结构注册到内核中,

GPIO中断芯片分类:
1、级联GPIO中断芯片

generic_handle_irq()	//运行每个特定GPIO设备驱动处理程序
request_irq()			//请求此特定的GPIO控制器中断引脚
platform_get_resource()	//从设备树中提取与源于父级中断控制器的中断引脚对应每个中断号

2、嵌套线程化GPIO中断芯片
片外GPIO扩展器以及位于睡眠总线另一侧的任何其他GPIO中断芯片。

gpiochip_irqchip_add()
irq_create_mapping()

12.2 设备树中断处理

中断信号可以来自机器中的任何设备,也可以在机器设备的任何设备上终止,设备寻址表现为树形结构,中断信号表现为独立于树的节点之间的连接。
中断连接的4个属性:
1、interrupt_controller属性,将节点表明为接受中断连接;
2、interrupt_cell是中断控制节点的属性,表明设备中断属性中的单元数;
3、interrupt_parent包含与其相连的中断控制器的phandle;
4、interrupt包含一系列中断说明符

举例:

			flx4: flexcom@fc018000 {
				atmel,flexcom-mode = <ATMEL_FLEXCOM_MODE_TWI>;
				status = "okay";

				i2c2: i2c@600 {
					compatible = "atmel,sama5d2-i2c";
					reg = <0x600 0x200>;
					interrupts = <23 IRQ_TYPE_LEVEL_HIGH 7>;
					dmas = <0>, <0>;
					dma-names = "tx", "rx";
					#address-cells = <1>;
					#size-cells = <0>;
					clocks = <&flx4_clk>;
					pinctrl-names = "default";
					pinctrl-0 = <&pinctrl_flx4_default>;
					atmel,fifo-size = <16>;
					status = "okay";
				};
			};

12.3 按钮中断设备

中断由CPU调度,异步运行。在Linux中,使用以下函数来获取和释放中断的:

request_irq()
free_irq()

分配中断资源、并启用中断线和IRQ处理函数是用的函数:

devm_request_irq()

中断处理函数的定义如下:

irqreturn_t (*handler)(int irq_no, void *dev_id);	    //中断处理函数接收Linux中断号(irq_no)

12.3.1 设备树

			pinctrl@fc038000 {
				/*
				 * There is no real pinmux for ADC, if the pin
				 * is not requested by another peripheral then
				 * the muxing is done when channel is enabled.
				 * Requesting pins for ADC is GPIO is
				 * encouraged to prevent conflicts and to
				 * disable bias in order to be in the same
				 * state when the pin is not muxed to the adc.
				 */
				pinctrl_adc_default: adc_default {
					pinmux = <PIN_PD23__GPIO>;
					bias-disable;
				};
				...
					
					pinctrl_key_gpio_default: key_gpio_default {
					pinmux = <PIN_PB9__GPIO>;
					bias-pull-up;
				};

/ {
	model = "Atmel SAMA5D2 Xplained";
	compatible = "atmel,sama5d2-xplained", "atmel,sama5d2", "atmel,sama5";

	chosen {
		stdout-path = "serial0:115200n8";
	};

	clocks {
		slow_xtal {
			clock-frequency = <32768>;
		};

		main_xtal {
			clock-frequency = <12000000>;
		};
	};

	int_key{
		compatible = "arrow,intkey";
		pinctrl-names = "default";
		pinctrl-0 = <&pinctrl_key_gpio_default>;
		gpios = <&pioA 41 GPIO_ACTIVE_LOW>;
		interrupt-parent = <&pioA>;
		interrupts = <41  IRQ_TYPE_EDGE_FALLING>;
	};

12.3.2 int_sam_key.c代码

/* 头文件 */
#include <linux/module.h>
#include <linux/platform_device.h> 	
#include <linux/interrupt.h> 		
#include <linux/gpio/consumer.h>
#include <linux/miscdevice.h>

static char *HELLO_KEYS_NAME = "PB_KEY";

/* interrupt handler */
//编写中断处理函数
static irqreturn_t hello_keys_isr(int irq, void *data)
{
	struct device *dev = data;
	dev_info(dev, "interrupt received. key: %s\n", HELLO_KEYS_NAME);
	return IRQ_HANDLED;
}

static struct miscdevice helloworld_miscdevice = {
		.minor = MISC_DYNAMIC_MINOR,
		.name = "mydev",
};

static int __init my_probe(struct platform_device *pdev)
{	
	int ret_val, irq;
	struct gpio_desc *gpio;
	struct device *dev = &pdev->dev;

	dev_info(dev, "my_probe() function is called.\n");
	
	/* First method to get the Linux IRQ number */
	//获取设备中断号,获取中断号有两种:
	// devm_gpiod_get()
	// platform_get_irq()
	gpio = devm_gpiod_get(dev, NULL, GPIOD_IN);
	if (IS_ERR(gpio)) {
		dev_err(dev, "gpio get failed\n");
		return PTR_ERR(gpio);
	}
	irq = gpiod_to_irq(gpio);
	if (irq < 0)
		return irq;
	dev_info(dev, "The IRQ number is: %d\n", irq);

	/* Second method to get the Linux IRQ number */
	irq = platform_get_irq(pdev, 0);
	if (irq < 0){
		dev_err(dev, "irq is not available\n");
		return -EINVAL;
	}
	dev_info(dev, "IRQ_using_platform_get_irq: %d\n", irq);
	
	/* Allocate the interrupt line */
	//分配中断线
	//irq是中断号
	//hello_keys_isr
	ret_val = devm_request_irq(dev, irq, hello_keys_isr, 
				   IRQF_TRIGGER_FALLING,
				   HELLO_KEYS_NAME, dev);
	if (ret_val) {
		dev_err(dev, "Failed to request interrupt %d, error %d\n", irq, ret_val);
		return ret_val;
	}
	
	ret_val = misc_register(&helloworld_miscdevice);
	if (ret_val != 0)
	{
		dev_err(dev, "could not register the misc device mydev\n");
		return ret_val;
	}

	dev_info(dev, "mydev: got minor %i\n",helloworld_miscdevice.minor);
	dev_info(dev, "my_probe() function is exited.\n");

	return 0;
}

static int __exit my_remove(struct platform_device *pdev)
{	
	dev_info(&pdev->dev, "my_remove() function is called.\n");
	misc_deregister(&helloworld_miscdevice);
	dev_info(&pdev->dev, "my_remove() function is exited.\n");
	return 0;
}

//声明驱动程序支持的设备列表
static const struct of_device_id my_of_ids[] = {
	{ .compatible = "arrow,intkey"},
	{},
};

MODULE_DEVICE_TABLE(of, my_of_ids);

//注册平台总线
static struct platform_driver my_platform_driver = {
	.probe = my_probe,
	.remove = my_remove,
	.driver = {
		.name = "intkey",
		.of_match_table = my_of_ids,
		.owner = THIS_MODULE,
	}
};

module_platform_driver(my_platform_driver);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Alberto Liberal");
MODULE_DESCRIPTION("This is a button INT platform driver");

12.3.3 测试调试

insmod int_key_imx_key.ko
cat /proc/interrupts
rmmod int_key_imx_key.ko

感谢阅读,祝君成功!
-by aiziyou

举报

相关推荐

0 条评论