zoukankan      html  css  js  c++  java
  • 设备树学习之(一)GPIO中断【转】

    本文转载自:http://blog.csdn.net/lizuobin2/article/details/54563587

    开发板:tiny4412SDK + S702 + 4GB Flash 
    要移植的内核版本:Linux-4.4.0 (支持device tree) 
    u-boot版本:友善之臂自带的 U-Boot 2010.12 
    busybox版本:busybox 1.25

    目标: 
    学习设备树中GPIO资源的使用,实现按键中断简单驱动程序。

    原理图: 
    这里写图片描述 
    tiny4412 底板上有4颗按键,分别为连接在 GPX3_2、GPX3_3、GPX3_4、GPX3_5 ,引脚状态常高。

    设备树:

        interrupt_demo: interrupt_demo {
                compatible         = "tiny4412,interrupt_demo";
                tiny4412,int_gpio1 = <&gpx3 2 GPIO_ACTIVE_HIGH>;
                tiny4412,int_gpio2 = <&gpx3 3 GPIO_ACTIVE_HIGH>;
                tiny4412,int_gpio3 = <&gpx3 4 GPIO_ACTIVE_HIGH>;
                tiny4412,int_gpio4 = <&gpx3 5 GPIO_ACTIVE_HIGH>;
        };
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    <&gpx3 2 GPIO_ACTIVE_HIGHT> 代表什么含义呢?

    Eg: <&gpx2 6 0> 
      <[phandle of the gpio controller node] 
      [pin number within the gpio controller] 
      [flags]> 
      Values for gpio specifier: 
      - Pin number: is a value between 0 to 7. 
      - Flags: 0 - Active High 1 - Active Low

    • &gpx3 引用 gpx3 这个节点,代表这个 GPIO 是属于控制器 gpx3
    • 2 则表示gpx3 这组管脚中的哪一个,gpx3_2
    • GPIO_ACTIVE_HIGHT 则表示引脚状态为常高的

    驱动程序:

    #include <linux/init.h>
    #include <linux/module.h>
    #include <linux/platform_device.h>
    #include <linux/gpio.h>
    #include <linux/of.h>
    #include <linux/of_gpio.h>
    #include <linux/interrupt.h>
    
    typedef struct 
    {
        int gpio;
        int irq;
        char name[20];
    }int_demo_data_t;
    
    static irqreturn_t int_demo_isr(int irq, void *dev_id)
    {
        int_demo_data_t *data = dev_id;
    
        printk("%s enter, %s: gpio:%d, irq: %d
    ", __func__, data->name, data->gpio, data->irq);
    
        return IRQ_HANDLED;
    }
    
    static int int_demo_probe(struct platform_device *pdev) {
        struct device *dev = &pdev->dev;
        int irq_gpio = -1;
        int irq = -1;
        int ret = 0;
        int i = 0;
        int_demo_data_t *data = NULL;
    
        printk("%s enter.
    ", __func__);
    
        if (!dev->of_node) {
            dev_err(dev, "no platform data.
    ");
            goto err1;
        }
    
        data = devm_kmalloc(dev, sizeof(*data)*4, GFP_KERNEL);
        if (!data) {
            dev_err(dev, "no memory.
    ");
            goto err0;
        }
    
    #if 1
        for (i = 3; i >= 0; i--) {
            sprintf(data[i].name, "tiny4412,int_gpio%d", i+1);//名字是我们自己填充的,并不是获取到的
    #else
        for (i = 0; i < 4; i++) {
    #endif
            irq_gpio = of_get_named_gpio(dev->of_node, data[i].name, 0);//通过名字获取gpio
            if (irq_gpio < 0) {
                dev_err(dev, "Looking up %s property in node %s failed %d
    ",
                    data[i].name, dev->of_node->full_name, irq_gpio);
                goto err1;
            }
    
            data[i].gpio = irq_gpio;
    
            irq = gpio_to_irq(irq_gpio);    //将gpio转换成对应的中断号
            if (irq < 0) {
                dev_err(dev,
                    "Unable to get irq number for GPIO %d, error %d
    ",
                    irq_gpio, irq);
                goto err1;
            }
    
            data[i].irq = irq;
    
            printk("%s: gpio: %d ---> irq (%d)
    ", __func__, irq_gpio, irq);
        //注册中断
            ret = devm_request_any_context_irq(dev, irq, int_demo_isr, IRQF_TRIGGER_FALLING, data[i].name, data+i);
            if (ret < 0) {
                dev_err(dev, "Unable to claim irq %d; error %d
    ",
                    irq, ret);
                goto err1;
            }
        }
    
        return 0;
    
    err1:
        devm_kfree(dev, data);
    err0:
        return -EINVAL;
    }
    
    static int int_demo_remove(struct platform_device *pdev) {
    
        printk("%s enter.
    ", __func__);
    
        return 0;
    }
    
    static const struct of_device_id int_demo_dt_ids[] = {
        { .compatible = "tiny4412,interrupt_demo", },
        {},
    };
    
    MODULE_DEVICE_TABLE(of, int_demo_dt_ids);
    
    static struct platform_driver int_demo_driver = {
        .driver        = {
            .name      = "interrupt_demo",
            .of_match_table    = of_match_ptr(int_demo_dt_ids),
        },
        .probe         = int_demo_probe,
        .remove        = int_demo_remove,
    };
    
    static int __init int_demo_init(void)
    {
        int ret;
    
        ret = platform_driver_register(&int_demo_driver);
        if (ret)
            printk(KERN_ERR "int demo: probe failed: %d
    ", ret);
    
        return ret;
    }
    module_init(int_demo_init);
    
    static void __exit int_demo_exit(void)
    {
        platform_driver_unregister(&int_demo_driver);
    }
    module_exit(int_demo_exit);
    
    MODULE_LICENSE("GPL");
  • 相关阅读:
    C#生成唯一值的方法汇总
    WCF中可以使用SVCUtil.exe生成客户端代理类和配置文件
    C# 打开钱箱支持北洋、佳博、爱普生
    MVC使用 Elmah 日志记录组件
    C# ZXing.Net生成二维码、识别二维码、生成带Logo的二维码(一)
    C# Gma.QrCodeNet生成二维码
    支付宝支付开发——当面付条码支付和扫码支付
    微信支付四大支付模式分别有哪些区别?
    web安全测试---AppScan扫描工具
    SVN 使用学习记录
  • 原文地址:https://www.cnblogs.com/zzb-Dream-90Time/p/7550555.html
Copyright © 2011-2022 走看看