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

现把一个蜂鸣器模块的控制引脚接到板上的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标识符
            ...
    };

加入的蜂鸣器描述:

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

设备驱动代码:

/* mydrv.c */


#include 
#include 
#include 
#include 
#include 

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");


板上有两个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失效才可以. 

驱动代码:

/*mydrv.c */

#include 
#include 
#include 
#include 
#include 

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");


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

设备树里的描述:

    mykeys {
        compatible = "mykeys";

        btn1 {
            btn-gpios = <&pio  0  12 GPIO_ACTIVE_LOW>;
        };
    }; 

驱动代码:


#include 
#include 
#include 
#include 
#include 
#include 

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");

你可能感兴趣的:(全志H5,Linux-4.11)