GPIO驱动开发

概述

TB-96AI 开发板扩展接口里的所有的IO都可以作为GPIO使用,但是需要配置iomux。不需要配置iomux,可以直接使用的GPIO是GPIO2_D3、GPIO2_B1、GPIO2_B2。这3个GPIO默认输出的电平是1.8V,通过电平转换芯片,转成3.3V。

添加设备

1、作为普通GPIO使用(reset usb hub)

设备树

usbhub_reset: usbhub-reset {
         compatible = "usbhub-reset";
         uhrst-gpio = <&gpio0 6 GPIO_ACTIVE_HIGH>;
                            };

uhrst-gpio:驱动中通过of_get_named_gpio_flags获取GPIO号;

“6”:表示这个GPIO属于哪个bank的哪个IO;(说明:bank=6/8+A;IO=6%8;例如这里的6表示A6;如果是12表示B4;)

GPIO_ACTIVE_HIGH:高有效;

驱动文件

"drivers/usb/misc/usbhub_reset.c"

of_device_id:用于匹配dts中的设备;

platform_driver:平台驱动,并且通过platform_driver_register注册;

这个驱动很简单,就是在系统reboot时,拉低这个GPIO,通过register_reboot_notifier这个函数注册进reboot的流程中。

2、通过pinctrl使用

设备树

&dsi {
    reset-gpios = <&gpio4 RK_PD5 GPIO_ACTIVE_LOW>;  /* TC358775_RST */
    enable-gpios = <&gpio1 RK_PA7 GPIO_ACTIVE_HIGH>; /* STBY */
    status = "okay";
    pinctrl-names = "default";
    pinctrl-0 = <&lcd_bl_en_h>;
                   ......
};
&pinctrl {
    tc3587 {
         lcd_bl_en_h: lcd-bl-en-h {
                        rockchip,pins =
                                <1 13 RK_FUNC_GPIO &pcfg_output_high>;
                              };
        };
           };

pinctrl-names:这个pin state名字列表,第一个state名字对应pinctrl-0,第二个state名字对应pinctrl-1,以此类推;

pinctrl-0:List of phandles,名字自定义;

&pinctrl:详细定义pin的配置;

tc3587:自定义;

lcd_bl_en_h:之前pinctrl-0定义的名字;

rockchip,pins:pin的配置,这里表示gpio1_b5,作为GPIO功能,默认输出高电平;

对于pinctrl-names有多个state名字,需要通过pinctrl函数获取,例如:

pinctrl-names = "default", "pmic-sleep",
                "pmic-power-off", "pmic-reset";
                pinctrl-0 = <&pmic_int_l>;
                pinctrl-1 = <&soc_slppin_slp>, <&rk809_slppin_slp>;
                pinctrl-2 = <&soc_slppin_gpio>, <&rk809_slppin_pwrdn>;
                pinctrl-3 = <&soc_slppin_rst>, <&rk809_slppin_rst>;

① 获取一个pinctrl句柄:

rk808->pins->p = devm_pinctrl_get(dev);

② 获取这个pin对应pin_state

default_st = pinctrl_lookup_state(rk808->pins->p, PINCTRL_STATE_DEFAULT);

③ 设置引脚为为某个stata

pinctrl_select_state(rk808->pins->p, default_st);

3、作为中断使用

设备树

gpio {
    compatible = "irq-test-gpio";
    irq-gpio = <&gpio4 29 IRQ_TYPE_EDGE_RISING>;  /* GPIO4_D5 */
};

IRQ_TYPE_EDGE_RISING表示中断由上升沿触发,当该引脚接收到上升沿信号时可以触发中断函数。

这里还可以配置成如下:

IRQ_TYPE_NONE //默认值,无定义中断触发类型

IRQ_TYPE_EDGE_RISING //上升沿触发

IRQ_TYPE_EDGE_FALLING //下降沿触发

IRQ_TYPE_EDGE_BOTH //上升沿和下降沿都触发

IRQ_TYPE_LEVEL_HIGH //高电平触发

IRQ_TYPE_LEVEL_LOW //低电平触发

驱动

probe函数中对DTS所添加的资源进行解析,再做中断的注册申请,代码如下:

 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
static int test_gpio_probe(struct platform_device *pdev)
{
    int ret;
    int gpio;
    enum of_gpio_flags flag;
    struct test_gpio_info *gpio_info;
    struct device_node * test_gpio_node = pdev->dev.of_node;
    ......

    gpio_info-> test_irq_gpio = gpio;
    gpio_info-> test_irq_mode = flag;
    gpio_info-> test_irq = gpio_to_irq(gpio_info-> test_irq_gpio);
    if (gpio_info-> test_irq) {
       if (gpio_request(gpio, "irq-test-gpio")) {
          printk("gpio %d request failed!\n", gpio); gpio_free(gpio); return IRQ_NONE;
        }
        ret = request_irq(gpio_info-> test_irq, test_gpio_irq, flag, "irq-test-gpio", gpio_info);
        if (ret != 0) free_irq(gpio_info-> test_irq, gpio_info);
           dev_err(&pdev->dev, "Failed to request IRQ: %d\n", ret);
     }
     return 0;
}
static irqreturn_t test_gpio_irq(int irq, void *dev_id) //中断函数
{
    printk("Enter irq test gpio irq test program!\n");
    return IRQ_HANDLED;
}

调用gpio_to_irq把GPIO的PIN值转换为相应的IRQ值,调用gpio_request申请占用该IO口,调用request_irq申请中断,如果失败要调用free_irq释放,该函数中gpio_info-> test_irq是要申请的硬件中断号,test_gpio_irq是中断函数,gpio_info-> test_irq_mode是中断处理的属性,”irq-test-gpio”是设备驱动程序名称,gpio_info是该设备的device结构,在注册共享中断时会用到。