一文搞懂Linux pinctrl/gpio子系统

嵌入式技术

1371人已加入

描述

前言

注: 所有文章基于linux-3.13以上,本系列主要介绍 GPIO的一些基本知识,驱动操作GPIO的接口,应用层通过sysfs操作GPIO的接口,GPIO一些debug信息查看,以及对高通相关GPIO的寄存器操作。分享给刚刚接触外设bsp的小伙伴们。当然后面有时间还会分享GPIO子系统框架和pinctrl子系统框架,先知道黑盒怎么使用,然后咱再打开仔细瞅瞅。

本篇为驱动申请GPIO和操作GPIO接口篇,分别介绍驱动通过GPIO子系统和PINCTRL 子系统提供的接口对GPIO的操作

GPIO 子系统操作GPIO

GPIO子系统接口简介

相关实现在driver/gpio/gpiolib.c 下

1、gpio_request 申请GPIO

 

int gpio_request(unsigned gpio, const char *label)

 

参数解析:

gpio: gpio编号

label: 名称

返回值: 成功返回0,失败返回负值

2、gpio_request_one 申请GPIO,同时制定配置方式 输出或输入模式

 

int gpio_request_one(unsigned gpio, unsigned long flags, const char *label)

 

3、gpio_free 释放GPIO

 

void gpio_free(unsigned gpio)

 

参数解析:

gpio: gpio编号

4、gpio_direction_input 设置GPIO为输入模式

 

int gpio_direction_input(unsigned gpio)

 

参数解析:

gpio: gpio编号

返回值: 成功返回0,失败返回负值

5、gpio_direction_output 设置GPIO为输出模式

 

int gpio_direction_output(unsigned gpio, int value)

 

参数解析:

gpio: gpio编号

value: 设置为输出模式时的初始值

返回值: 成功返回0,失败返回负值

6、gpio_set_value 设置(写)GPIO的值

 

void __gpio_set_value(unsigned gpio, int value)
#define gpio_set_value  __gpio_set_value

 

gpio: gpio编号

value: 设置的值

返回值: 成功返回0,失败返回负值

7、gpio_get_value 获取(读)GPIO的值

 

int __gpio_get_value(unsigned gpio)
#define gpio_get_value  __gpio_get_value

 

gpio: gpio编号

返回值: 获取的值

8、gpio_to_irq 内核通过调用该函数将gpio端口转换为中断

 

int gpio_to_irq(unsigned gpio); 

 

gpio: gpio编号

返回值:中断编号可以传给request_irq()和free_irq()

举个例子:单个GPIO

申请gpio4,输出模式,输出高(从设备树配置)

设备树设置

 

gpio_test{
 status="ok";
 gpio_req=<&tlmn 4 0>;

 

代码实现

 

struct device dev;
gpio4 = of_get_named_gpio(dev.of_node,"gpio_req", 0);
err = gpio_request(gpio4, "qti-can-reset");
 if (err < 0) {
         return err;
 } 
gpio_direction_output(gpio4, 0);                
gpio_set_value(gpio4,1);                

 

GPIO数组申请一个gpio数组 [36,42,132],主要是设备树 设备树

 

gpios = <&tlmm 36 0>,
                <&tlmm 42 0>,
                <&tlmm 132 0>;
        qcom,gpio-reset = <1>;
        qcom,gpio-standby = <2>;
        qcom,gpio-req-tbl-num = <0 1 2>;  
        qcom,gpio-req-tbl-flags = <1 0 0>; 
        qcom,gpio-req-tbl-label = "CAMIF_MCLK2",  
                                                                "CAM_RESET2",
                                                               "CAM_STANDBY2";

 

解析:

PINCTRL 子系统操作GPIO

pinctrl 子系统相关接口

1、devm_pinctrl_get 解析对应的设备树,获取pinctrl资源

 

struct pinctrl *devm_pinctrl_get(struct device *dev)

 

dev: 驱动设备结构体

返回值:pinctrl节点

2、pinctrl_lookup_state 获取各种state的gpio配置

 

struct pinctrl_state *pinctrl_lookup_state(struct pinctrl *p, const char *name) 

 

p: pinctrl节点

name:gpio配置的名字

3、pinctrl_select_state 将上面获取的指定state状态设置到硬件中*/

 

int pinctrl_select_state(struct pinctrl *p, struct pinctrl_state *state)

 

举个例子

高通的配置为例子

在pinctrl设备树添加一个节点

 

&tlmn{
 
 pin_teset_default:pin_teset_default{
                 mux {
                          pins = "gpio0", "gpio1"; 
                          function = "qup00";
                  };
                  config {
                          pins = "gpio0", "gpio1"; 
                          drive-strength = <2>;
                          bias-disable;
                  };
 }
}

 

在xxx.dtsi中添加一个设备 使用

 

pinctrl_test{
  status="ok";
  pinctrl-name="default";
  pinctrl-0=<&pin_teset_default>;
}

 

代码实现

 

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

 dev->pins->default_state = pinctrl_lookup_state(dev->pins->p, PINCTRL_STATE_DEFAULT); 
  pinctrl_select_state(dev->pins->p, dev->pins->default_state);

 

probe自动配置pinctrl

如上个例子中,我们是不需要自己进行pinctrl适配的,device和驱动在匹配之后会进行适配。调用我们驱动的probe时,pinctrl相关已经初始化好了。获取相关状态和设置相关状态

 

__device_attach
    bus_for_each_drv(dev->bus, NULL, &data, __device_attach_driver);
        __device_attach_driver 
            driver_match_device(drv, dev); 
            driver_probe_device(struct device_driver *drv, struct device *dev)
                really_probe
                    pinctrl_bind_pins 
                        drv->probe(dev)


int pinctrl_bind_pins(struct device *dev)
{
   
   dev->pins->p = devm_pinctrl_get(dev);

   
   dev->pins->default_state = pinctrl_lookup_state(dev->pins->p, PINCTRL_STATE_DEFAULT); 
   dev->pins->init_state = pinctrl_lookup_state(dev->pins->p, PINCTRL_STATE_INIT);
   
   if (IS_ERR(dev->pins->init_state)) {
       
       ret = pinctrl_select_state(dev->pins->p, dev->pins->default_state); 
   } else {
       ret = pinctrl_select_state(dev->pins->p, dev->pins->init_state);
   }

#ifdef CONFIG_PM 
   dev->pins->sleep_state = pinctrl_lookup_state(dev->pins->p, PINCTRL_STATE_SLEEP);
   dev->pins->idle_state = pinctrl_lookup_state(dev->pins->p, PINCTRL_STATE_IDLE);
#endif

   return 0;
}

 

 

  审核编辑:汤梓红

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分