处理设备驱动中使用的中断
十二、处理设备驱动中使用的中断
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