linux设备树的gpio和gpio中断应用实例

10 linux设备树的gpio和gpio中断应用实例

发表于2017/11/20 17:08:19  267人阅读

分类: 全志H5 Linux-4.11

现把一个蜂鸣器模块的控制引脚接到板上的PL11, 当输出低电平时蜂鸣器响,高电平时就不响. 
H5芯片上有两个gpio控制器, PL组gpio口单独在一个gpio控制器上.

PL组的gpio控制器在设备树里的描述:

         r_pio: pinctrl@01f02c00 {  /* 可通过此基础区分gpio控制器 */
            compatible = "allwinner,sun8i-h3-r-pinctrl";
            ...
            gpio-controller;
            #gpio-cells = <3>; //每个gpio口由3个数字组成一个gpio标识符
            ...
    };
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

加入的蜂鸣器描述:

    mybuzzer {
        compatible = "mybuzzer";
        gpios = <&r_pio 0 11 GPIO_ACTIVE_LOW>;  //设备节点的gpios属性
    };
   
   
  • 1
  • 2
  • 3
  • 4

设备驱动代码:

/* mydrv.c */


#include <linux/init.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/property.h>
#include <linux/gpio/consumer.h>

int myprobe(struct platform_device *pdev)
{
    struct gpio_desc  *gpiod = NULL;

    gpiod = gpiod_get(&pdev->dev, NULL, GPIOD_OUT_HIGH);
    if (NULL == gpiod)
        return -ENODEV;

    gpiod_direction_output(gpiod, 1); //输出低电平,因在设备树里是用GPIO_ACTIVE_LOW

    platform_set_drvdata(pdev, gpiod);
    printk("in myprobe\n");
    return 0;
}

int myremove(struct platform_device *pdev)
{
    struct gpio_desc *gpiod = platform_get_drvdata(pdev);
    printk("in myremove ...\n");

    gpiod_set_value(gpiod, 0); //输出高电平
    gpiod_put(gpiod);  //回收gpio口的gpio_desc资源
    return 0;
}

struct of_device_id ids[] = {
    {.compatible = "mybuzzer"},
    {},
};

struct platform_driver mydrv = {
    .probe = myprobe,
    .remove = myremove,

    .driver = {
        .owner = THIS_MODULE,
        .name = "mydrv" ,

        .of_match_table = ids,
    },
};

module_platform_driver(mydrv);
MODULE_LICENSE("GPL");
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53


板上有两个led灯,分别接在PA17, PL10上,自定义的设备节点:

    myleds {
        compatible = "myleds";
        leds-gpios = <&r_pio 0 10 GPIO_ACTIVE_HIGH>,<&pio 0 17 GPIO_ACTIVE_HIGH>;
    };
    //注意gpio口在设备驱动里只能独占使用的,所以需要确认gpio口不会发生重用的情况.
    // 在h5里, 需要把设备节点leds失效才可以. 
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

驱动代码:

/*mydrv.c */

#include <linux/init.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/property.h>
#include <linux/gpio/consumer.h>

int myprobe(struct platform_device *pdev)
{
    struct gpio_descs  *gpiods = NULL;
    int i;

    gpiods = devm_gpiod_get_array(&pdev->dev, "leds", GPIOD_OUT_LOW);
    if (IS_ERR(gpiods))
    {
        printk("gpiod get array failed\n");
        return -ENODEV;
    }

    printk("ndescs = %d\n", gpiods->ndescs);
    for (i = 0; i < gpiods->ndescs; i++)
        gpiod_set_value(gpiods->desc[i], 1); //输出有效电平

    platform_set_drvdata(pdev, gpiods);
    printk("in myprobe\n");
    return 0;
}

int myremove(struct platform_device *pdev)
{
    struct gpio_descs *gpiods = platform_get_drvdata(pdev);
    int i;
    printk("in myremove ...\n");

    for (i = 0; i < gpiods->ndescs; i++)
        gpiod_set_value(gpiods->desc[i], 0); //输出失效电平

    devm_gpiod_put_array(&pdev->dev, gpiods);  //回收gpio口的gpio_desc资源
    return 0;
}

struct of_device_id ids[] = {
    {.compatible = "myleds"},
    {},
};

struct platform_driver mydrv = {
    .probe = myprobe,
    .remove = myremove,

    .driver = {
        .owner = THIS_MODULE,
        .name = "mydrv" ,

        .of_match_table = ids,
    },
};

module_platform_driver(mydrv);
MODULE_LICENSE("GPL");

   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62


gpio中断的应用. 一个按键模块接在PA12接口上。 默认处于高电平状态, 当按下时变为低电平.

设备树里的描述:

    mykeys {
        compatible = "mykeys";

        btn1 {
            btn-gpios = <&pio  0  12 GPIO_ACTIVE_LOW>;
        };
    }; 
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

驱动代码:


#include <linux/init.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/property.h>
#include <linux/gpio/consumer.h>
#include <linux/interrupt.h>

typedef struct {
    struct gpio_desc *desc;
    int keycode;
}mygpio_t;

typedef struct {
    mygpio_t *mygpio;
    int n;
}mygpio_pdata;

irqreturn_t irq_func(int irqno, void *arg) // arg参值就是在request_irq时的最后一个参数值
{
    printk("irq irq irq ...\n");
    return IRQ_HANDLED;
}

int myprobe(struct platform_device *pdev)
{
    int n = device_get_child_node_count(&pdev->dev);
    int i = 0, ret;
    struct fwnode_handle *fwnode;

    mygpio_pdata *pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata)+n*sizeof(mygpio_t), GFP_KERNEL);

    pdata->mygpio = (mygpio_t *)(pdata+1);
    pdata->n = n;

    device_for_each_child_node(&pdev->dev, fwnode) {
        pdata->mygpio[i].desc = fwnode_get_named_gpiod(fwnode, "btn-gpios",0,GPIOD_IN, NULL);
        if (IS_ERR(pdata->mygpio[i].desc))
        {
            printk("get gpiod failed\n");
            return -ENODEV;
        }

        ret = devm_request_any_context_irq(&pdev->dev, gpiod_to_irq(pdata->mygpio[i].desc), irq_func, IRQF_TRIGGER_FALLING|IRQF_TRIGGER_RISING, pdev->name, NULL);
        if (ret < 0)
            printk("request irq failed\n");
        i++;
    }

    platform_set_drvdata(pdev, pdata);
    printk("in myprobe n = %d\n", n);
    return 0;
}

int myremove(struct platform_device *pdev)
{
    mygpio_pdata *pdata = platform_get_drvdata(pdev);
    int i;

    for (i = 0; i < pdata->n; i++)
        gpiod_put(pdata->mygpio[i].desc);

    printk("in myremove\n");
    return 0;
}

struct of_device_id ids[] = {
    {.compatible = "mykeys"},
    {},
};

struct platform_driver mydrv = {
    .probe = myprobe,
    .remove = myremove,

    .driver = {
        .owner = THIS_MODULE,
        .name = "mydrv" ,

        .of_match_table = ids,
    },
};

module_platform_driver(mydrv);
MODULE_LICENSE("GPL");
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值