先上代碼:
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/gpio.h>
#include <linux/fs.h>
#include <asm/uaccess.h>
#include <linux/platform_device.h>
#include <linux/of_gpio.h>
#include <linux/device.h>
#include <linux/ioctl.h>
#include <linux/err.h>
#include <linux/list.h>
#include <linux/errno.h>
#include <linux/slab.h>
#include <linux/compat.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/irq.h>
#include <linux/of_irq.h>
#include <linux/interrupt.h>
#include <linux/clk-provider.h>
#include <linux/clk/ti.h>
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/of_address.h>
#include <linux/delay.h>
#include <linux/sched.h>
#include <linux/timer.h>
#include <linux/workqueue.h>
#define GPIO_MAX_NUM 256
#define TIMER_TIMEOUT_VALUE 1
#define WORK_DELAY_VALUE 1
#define USE_TIMER 0
#define USE_DELAY_WORK 1
#define DEV_NAME "data_dect"
int irq_num = 0;
int irq_gpio = 0;
int pad_sai2_rxd = 0;
struct timer_list timer;
static struct delayed_work delay_work1;
int major;
static struct class *mod_class;
struct device *mod_dev;
dev_t devt;
struct completion data_dect_completion;
//設備文件寫函數
static ssize_t data_dect_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_ops)
{
return 0;
}
//調用read返回,就說明出現了空白的現象
static ssize_t data_dect_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
{
ssize_t status = 0;
wait_for_completion_interruptible_timeout(&data_dect_completion, HZ);
return status;
}
static long data_dect_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
return 0;
}
static int data_dect_open(struct inode *node, struct file *filp)
{
nonseekable_open(node, filp);
return 0;
}
static const struct file_operations data_dect_fops =
{
.owner = THIS_MODULE,
.write = data_dect_write,
.read = data_dect_read,
.unlocked_ioctl = data_dect_ioctl,
.open = data_dect_open,
};
static irqreturn_t irq_handler_func(int irq, void *dev)
{
// printk ("this is interrupt !kernel _lqd\n"); /*其他模塊的導出符號*/
schedule_delayed_work(&delay_work1, msecs_to_jiffies(WORK_DELAY_VALUE)); //啓動引腳檢測
return IRQ_HANDLED;
}
void timer_function(unsigned long arg)
{
// int value = 0;
static unsigned int value = 0;
mod_timer(&timer, jiffies+TIMER_TIMEOUT_VALUE);
value++;
gpio_set_value(pad_sai2_rxd, value%2);
return ;
value = gpio_get_value(irq_gpio);
if(value)
{
gpio_set_value(pad_sai2_rxd, 1);
printk("irq_gpio status is Hig !\n");
}
else
{
gpio_set_value(pad_sai2_rxd, 0);
}
}
//中斷裏面啓動延時工作隊列
//延時時間到時,開始執行下面的函數
static void delay_work_func(struct work_struct *work)
{
int value = 0;
#if 0
static int temp_value = 0;
temp_value++;
gpio_set_value(pad_sai2_rxd, temp_value%2);
schedule_delayed_work(&delay_work1, msecs_to_jiffies(WORK_DELAY_VALUE));
#endif
value = gpio_get_value(irq_gpio); //獲取中斷引腳電平狀態
if(value) //如果這個時候還是高電平,說明出現了空白
{
complete(&data_dect_completion); //讓應用層的read調用返回
printk("Data appears blank !\n"); //內核打印提示
}
}
static int __init mod_init(void)
{
int ret;
struct device_node *dts_of_node = NULL;
dts_of_node = of_find_node_by_name(NULL, "test-node"); //獲取設備樹對應的節點
if(dts_of_node == NULL)
{
printk("Don't found test-node node !\n");
return -1;
}
irq_gpio = of_get_named_gpio(dts_of_node, "int-gpios", 0);
if(irq_gpio < 0)
{
printk("irq_gpio error !\n");
}
pad_sai2_rxd = of_get_named_gpio(dts_of_node, "pad_sai2_rxd", 0);
if(gpio_is_valid(pad_sai2_rxd))
{
ret = gpio_request(pad_sai2_rxd, "pad_sai2_rxd");
if(ret == 0)
{
gpio_direction_output(pad_sai2_rxd, 1);
}
}
else
{
goto error1;
}
irq_num = irq_of_parse_and_map(dts_of_node, 0); //獲取中斷號
if(irq_num < 0)
{
printk("irq_of_parse_and_map fail !\n");
goto error2;
}
ret = request_irq(irq_num, irq_handler_func, IRQF_TRIGGER_RISING, "gpio_interrupt", NULL); //申請中斷,上升沿觸發
if(ret < 0)
{
printk("request_irq fail !\n");
goto error2;
}
#if USE_TIMER
init_timer(&timer); //初始化定時器
timer.expires = jiffies+TIMER_TIMEOUT_VALUE;
timer.function = timer_function;
add_timer(&timer);
#endif
#if USE_DELAY_WORK
INIT_DELAYED_WORK(&delay_work1, delay_work_func);
schedule_delayed_work(&delay_work1, msecs_to_jiffies(WORK_DELAY_VALUE));
#endif
init_completion(&data_dect_completion); //初始化完成量
//創建設備節點
major = register_chrdev(0, DEV_NAME, &data_dect_fops); //註冊字符設備 返回主設備號
if(major < 0)
{
printk("register_chrdev fail !\n");
goto error3;
}
mod_class = class_create(THIS_MODULE, DEV_NAME); //創建類
if (IS_ERR(mod_class)) {
goto error4;
}
mod_dev = device_create(mod_class, NULL, MKDEV(major, 0), NULL, DEV_NAME); //創建設備
if(IS_ERR(mod_dev))
{
goto error5;
}
return 0;
error5:
class_destroy(mod_class);
error4:
unregister_chrdev(major, DEV_NAME);
error3:
#if USE_TIMER
del_timer(&timer);
#endif
#if USE_DELAY_WORK
cancel_delayed_work_sync(&delay_work1);
#endif
error2:
gpio_free(pad_sai2_rxd);
error1:
return -1;
}
module_init(mod_init);
static void __exit mod_exit(void)
{
unregister_chrdev(major, DEV_NAME);
device_destroy(mod_class, MKDEV(major, 0));
class_destroy(mod_class);
#if USE_TIMER
del_timer(&timer);
#endif
#if USE_DELAY_WORK
cancel_delayed_work_sync(&delay_work1);
#endif
free_irq(irq_num, NULL);
gpio_free(pad_sai2_rxd);
printk("############### %s %s !kernel\n", __FILE__, __func__);
}
module_exit(mod_exit);
MODULE_AUTHOR("lqd");
MODULE_LICENSE("GPL");
上面的例程,通過設備樹獲取中斷信息。通過中斷,去觸發定時器/延時工作隊列去檢測GPIO的電平