开发板:tiny4412(1611)
内核:linux4.4
编译器: arm-none-linux-gnueabi-gcc (gcc version 4.8.3 20140320)
中断背后的知识:http://www.cnblogs.com/pengdonglin137/p/6349209.html
使用到的引脚是XEINT26,即GPX3_2
在设备树下添加节点:
interrupt_int26 {
compatible = "tiny4412,interrupt_int26";
tiny4412,int_gpio1 = <&gpx3 2 GPIO_ACTIVE_HIGH>;
};
interrupt_int26是节点名,compatible属性用来匹配platform驱动
tiny4412,int_gpio1是我们自定义的一个属性,后面三个值分别是中断域(中断控制器) gpio引脚 flags
这里的flags即高电平有效
装载新的设备树后可以在sys/firmware/devicetree/base下看到interrupt_int26节点
驱动:#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
typedef struct
{
int gpio;
int irq;
char name[20];
}int_demo_data_t;
#define INT_NUM 1
static struct class *int26_class= NULL;
struct device *class_dev= NULL;
static int_demo_data_t *data = NULL;
static int major;
static struct cdev int26_cdev;
static const char* devname = "int26";
static dev_t int_dev;
static const struct file_operations int26_fops;
static unsigned char key_val=1;
static volatile int ev_press = 0;
static DECLARE_WAIT_QUEUE_HEAD(int26_waitq);
static irqreturn_t int26_irq(int irq, void *data)
{
ev_press = 1;
wake_up_interruptible(&int26_waitq);
return IRQ_HANDLED;
}
static int int26_open(struct inode * inode, struct file * filp)
{
printk("%s enter.\n", __func__);
devm_request_any_context_irq(class_dev, data->irq,int26_irq, IRQF_TRIGGER_FALLING, data->name, data);
return 0;
}
static ssize_t int26_read(struct file *filp, char __user *buffer,size_t length, loff_t *offset)
{
if (length != 1)
return -EINVAL;
wait_event_interruptible(int26_waitq, ev_press);
copy_to_user(buffer, &key_val, sizeof(key_val));
ev_press = 0;
return 1;
}
static int int26_release(struct inode *inode, struct file *file)
{
devm_free_irq(class_dev,data->irq,data);
return 0;
}
static int int_probe(struct platform_device *pdev) {
struct device *dev = &pdev->dev;
int irq_gpio = -1;
int irq = -1;
printk("%s enter.\n", __func__);
if (!dev->of_node) {
dev_err(dev, "no platform data.\n");
goto err1;
}
data = devm_kmalloc(dev, sizeof(*data), GFP_KERNEL);
if (!data) {
dev_err(dev, "no memory.\n");
goto err0;
}
sprintf(data->name, "tiny4412,int_gpio1");
irq_gpio = of_get_named_gpio(dev->of_node,data->name, 0);
if (irq_gpio < 0) {
dev_err(dev, "Looking up %s property in node %s failed %d\n",data->name, dev->of_node->full_name, irq_gpio);
goto err1;
}
data->gpio = irq_gpio;
irq = gpio_to_irq(irq_gpio);
if (irq < 0) {
dev_err(dev,"Unable to get irq number for GPIO %d, error %d\n",irq_gpio, irq);
goto err1;
}
data->irq = irq;
printk("%s: gpio: %d ---> irq (%d)\n", __func__, irq_gpio, irq);
alloc_chrdev_region(&int_dev, 0, INT_NUM, "int26");
major = MAJOR(int_dev);
cdev_init(&int26_cdev, &int26_fops);
cdev_add(&int26_cdev, MKDEV(major, 0), INT_NUM);
int26_class=class_create(THIS_MODULE,"int26");
class_dev=device_create(int26_class, NULL, int_dev, NULL, "%s", devname);
return 0;
err1:
devm_kfree(dev, data);
err0:
return -EINVAL;
}
static int int_remove(struct platform_device *pdev) {
printk("%s enter.\n", __func__);
unregister_chrdev_region(int_dev,INT_NUM);
cdev_del(&int26_cdev);
device_destroy(int26_class,MKDEV(major, 0));
class_destroy(int26_class);
return 0;
}
static const struct of_device_id dt_ids[] = {
{ .compatible = "tiny4412,interrupt_int26", },
{},
};
MODULE_DEVICE_TABLE(of, dt_ids);
static struct platform_driver int26_driver = {
.driver = {
.name = "int26",
.of_match_table = of_match_ptr(dt_ids),
},
.probe = int_probe,
.remove = int_remove,
};
static const struct file_operations int26_fops={
.owner = THIS_MODULE,
.open = int26_open,
.read = int26_read,
.release= int26_release,
};
static int __init int26_init(void)
{
int ret;
ret = platform_driver_register(&int26_driver);
if (ret)
printk(KERN_ERR "int demo: probe failed: %d\n", ret);
return ret;
}
module_init(int26_init);
static void __exit int26_exit(void)
{
platform_driver_unregister(&int26_driver);
}
module_exit(int26_exit);
MODULE_LICENSE("GPL");
驱动中platform_driver中of_match_table匹配设备树的compatible属性,利用节点的tiny4412,int_gpio1属性来获得中断号,gpio_to_irq把引脚配置成中断模式,devm_request_any_context_irq向内核申请。
测试程序:
#include
#include
int main(int argc,char *argv[]){
int fd;
char buf;
int num;
fd=open("/dev/int26",O_RDONLY);
if(fd<0){
printf("can not open /dev/int26\n");
return -1;
}
while(1){
num=read(fd,&buf,sizeof(char));
if(num!=sizeof(char)){
printf("read error\n");
return -1;
}
printf("read:%d\n",buf);
}
}
执行程序后,按下按键即可看到输出信息。目前驱动存在无法卸载的bug,待调试。。