天天看點

裝置樹學習之(一)GPIO中斷

開發闆:tiny4412SDK + S702 + 4GB Flash

要移植的核心版本:Linux-4.4.0 (支援device tree)

u-boot版本:友善之臂自帶的 U-Boot 2010.12

busybox版本:busybox 1.25

目标:

學習裝置樹中GPIO資源的使用,實作按鍵中斷簡單驅動程式。

原理圖:

裝置樹學習之(一)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>;
    };
           

<&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[];
}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\n", __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 = -;
    int irq = -;
    int ret = ;
    int i = ;
    int_demo_data_t *data = NULL;

    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;
    }

#if 1
    for (i = ; i >= ; i--) {
        sprintf(data[i].name, "tiny4412,int_gpio%d", i+);//名字是我們自己填充的,并不是擷取到的
#else
    for (i = ; i < ; i++) {
#endif
        irq_gpio = of_get_named_gpio(dev->of_node, data[i].name, );//通過名字擷取gpio
        if (irq_gpio < ) {
            dev_err(dev, "Looking up %s property in node %s failed %d\n",
                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 < ) {
            dev_err(dev,
                "Unable to get irq number for GPIO %d, error %d\n",
                irq_gpio, irq);
            goto err1;
        }

        data[i].irq = irq;

        printk("%s: gpio: %d ---> irq (%d)\n", __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 < ) {
            dev_err(dev, "Unable to claim irq %d; error %d\n",
                irq, ret);
            goto err1;
        }
    }

    return ;

err1:
    devm_kfree(dev, data);
err0:
    return -EINVAL;
}

static int int_demo_remove(struct platform_device *pdev) {

    printk("%s enter.\n", __func__);

    return ;
}

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\n", 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");
           

繼續閱讀