Linux驱动--中断
1、预备知识
1.1、中断号
中断号也叫中断线,每个中断都有一个中断号,通过中断号即可区分不同的中断。Linux 内核中使用一个 int 变量表示中断号。
2、中断API函数
2.1、获取设备号
gpio_to_irq函数
int gpio_to_irq(unsigned int gpio)
gpiod_to_irq函数
int gpiod_to_irq(const struct gpio_desc *desc)
2.2、申请中断
/**
* request_threaded_irq - allocate an interrupt line
* @irq: Interrupt line to allocate
* @handler: Function to be called when the IRQ occurs.
* Primary handler for threaded interrupts
* If NULL and thread_fn != NULL the default
* primary handler is installed
* @flags: Interrupt type flags
* @name: An ascii name for the claiming device
* @dev: A cookie passed back to the handler function
*/
int request_irq(unsigned int irq,
irq_handler_t handler,
unsigned long flags,
const char *name,
void *dev)
- 中断处理函数
作用:当中断发生以后就会执行此中断处理函数
格式:irqreturn_t (*irq_handler_t)(int, void *);
- flag
标志 | 描述 |
---|---|
IRQF_SHARED | 多个设备共享一个中断线,共享的所有中断都必须指定此标志。如果使用共享中断的话,request_irq 函数的 dev 参数就是唯一区分他们的标志 |
IRQF_ONESHOT | 单次中断,中断执行一次就结束 |
IRQF_TRIGGER_NONE | 无触发 |
IRQF_TRIGGER_RISING | 上升沿触发 |
IRQF_TRIGGER_FALLING | 下降沿触发 |
IRQF_TRIGGER_HIGH | 高电平触发 |
IRQF_TRIGGER_LOW | 低电平触发 |
- dev
1、如果将 flags 设置为 IRQF_SHARED 的话,dev 用来区分不同的中断。
2、一般情况下将dev 设置为设备结构体,dev 会传递给中断处理函数 irq_handler_t 的第二个参数。
2.3、释放中断
/**
* free_irq - free an interrupt allocated with request_irq
* @irq: Interrupt line to free
* @dev_id: Device identity to free
*/
void free_irq(unsigned int irq, void *dev_id)
- irq:要释放的中断号。
- dev:如果中断设置为共享(IRQF_SHARED)的话,此参数用来区分具体的中断。
2.4、中断使能与禁止
/**
* enable_irq - enable handling of an irq
* @irq: Interrupt to enable
*/
void enable_irq(unsigned int irq)
/**
* disable_irq - disable an irq and wait for completion
* @irq: Interrupt to disable
*/
void disable_irq(unsigned int irq)
3、中断实例
实现内容:
按下按键触发中断,在中断服务函数中打印触发次数。
- 设备树
my_key {
compatible = "my_key";
status = "okay";
pinctrl_names = "default";
pinctrl-0 = <&pinctrl_key>;
key-gpio = <&gpio1 18 GPIO_ACTIVE_LOW>;
/* 中断相关 */
interrupt-parent = <&gpio1>;
interrupt = <18 IRQ_TYPE_EDGE_BOTH>;
};
- 驱动
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/gpio/consumer.h>
#include <linux/interrupt.h>
struct key_type
{
struct gpio_desc *gpio;
int irq;
};
struct key_type key_cdev;
/**
* @brief 中断回调函数
*
*/
irqreturn_t key_irq_handler(int irq, void *data)
{
static int counter = 0;
/* 打印触发中断次数 */
printk("key_irq_handler: %d\n", counter);
counter++;
return IRQ_RETVAL(IRQ_HANDLED);
}
/**
* @brief platform驱动-probe函数
*
*/
int key_probe(struct platform_device *pdev)
{
int ret;
/* 1、获取GPIO */
key_cdev.gpio = devm_gpiod_get(&pdev->dev, "key", GPIOD_IN);
/* 2、获取中断号并申请中断 */
key_cdev.irq = gpiod_to_irq(key_cdev.gpio);
ret = request_irq(key_cdev.irq, key_irq_handler, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, "my_key_irq", &key_cdev);
return 0;
}
/**
* @brief platform驱动-remove函数
*
*/
int key_remove(struct platform_device *pdev)
{
/* 释放中断 */
free_irq(key_cdev.irq, &key_cdev);
return 0;
}
/**
* @brief 匹配列表
*
*/
struct of_device_id key_match_table[] = {
{.compatible = "my_key"},
};
/**
* @brief platform驱动
*
*/
struct platform_driver key_itr_driver = {
.driver = {
.name = "my_key",
.of_match_table = key_match_table,
},
.probe = key_probe,
.remove = key_remove,
};
/* 注册平台驱动 */
module_platform_driver(key_itr_driver);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("LSW");