Pinctrl子系统、GPIO子系统概念

本文详细解释了Pinctrl子系统如何管理GPIO和I2C引脚复用,通过设备树配置,以及GPIOController和clientdevice的角色。介绍了GPIO子系统在驱动程序中的标准化接口,使得开发板无关的代码成为可能。
摘要由CSDN通过智能技术生成

Pinctrl概念:

无论是哪种芯片,都有类似图 16.1 的结构:
要想让 pinA B 用于 GPIO ,需要设置 IOMUX 让它们连接到 GPIO 模块;
要想让 pinA B 用于 I2C ,需要设置 IOMUX 让它们连接到 I2C 模块。
为了将人们从繁杂的寄存器设置工作中解放出来,就把引脚的复用、配置抽出来,做成 Pinctrl 子系统,给 GPIO I2C 等模块使用。
从设备树开始学习 Pintrl 会比较容易。
这会涉及 2 个对象: pin controller client device
前者提供服务:可以用它来复用引脚、配置引脚。
后者使用服务:声明自己要使用哪些引脚的哪些功能,怎么配置它们。
pin controller
在芯片手册里找不到 pin controller ,它是一个软件上的概念,你可以认为它对应 IOMUX ──用来复用引脚,还可以配置引脚 ( 比如上下拉电阻等 )
注意, pin controller GPIO Controller 不是一回事,前者控制的引脚可用于 GPIO 功能、 I2C 功能;后者只是把引脚配置为输入、输出等简单的配置功能。即先用 pin controller 把引脚配置为 GPIO ,再用 GPIO Controler 把引脚配置为输入或输出。
client device:
“客户设备”,谁的客户? Pinctrl 系统的客户,那就是使用 Pinctrl 系统 的设备,使用引脚的设备。它在设备树里会被定义为一个节点,在节点里声明要用哪些引脚。
a) pin state
对于一个“ client device ”来说,比如对于一个 UART 设备,它有多个“状态”:default sleep 等,那对应的引脚也有这些状态。
怎么理解?
比如默认状态下, UART 设备是工作的,那么所用的引脚就要复用为 UART 功 能。
在休眠状态下,为了省电,可以把这些引脚复用为 GPIO 功能;或者直接把 它们配置输出高电平。
b) groups function
一个设备会用到一个或多个引脚,这些引脚就可以归为一组 (group)
这些引脚可以复用为某个功能: function。( 复用功能的宏定义在arch/arm/boot/dts/imx6ul-pinfunc.h中
当然:一个设备可以用到多组引脚,比如 A1 A2 两组引脚, A1 组复用为 F1 功能,A2 组复用为 F2 功能。
c) Generic pin multiplexing node Generic pin configuration node
在上图左边的 pin controller 节点中,有子节点或孙节点,它们是给 client device 使用的。
可 以 用 来 描 述 复 用 信 息 : 哪 组 (group) 引 脚 复 用 为 哪 个 功 能 (function);
可以用来描述配置信息:哪组 (group) 引脚配置为哪个设置功能 (setting),比如上拉、下拉等。
注意 pin controller 节点的格式, 没有统一的标准, 每家芯片都不一样。 甚至上面的 group function 关键字也不一定有,但是概念是有的。

GPIO子系统概念:

要操作 GPIO 引脚,先把所用引脚配置为 GPIO 功能,这通过 Pinctrl 子系统来实现。
然后就可以根据设置引脚方向 ( 输入还是输出 ) 、读值──获得电平状态,写值──输出高低电平。
以前我们通过寄存器来操作 GPIO 引脚,即使 LED 驱动程序,对于不同的板子它的代码也完全不同。 当 BSP 工程师实现了 GPIO 子系统后,我们就可以:
在设备树里指定 GPIO 引脚
在驱动代码中:使用 GPIO 子系统的标准函数获得 GPIO 、设置 GPIO 方向、读取/ 设置 GPIO 值。
这样的驱动代码,将是单板无关的。
在设备树中指定引脚:
在几乎所有 ARM 芯片中, GPIO 都分为几组,每组中有若干个引脚。所以在 使用 GPIO 子系统之前,就要先确定:它是哪组的?组里的哪一个?
在设备树中,“ GPIO 组”就是一个 GPIO Controller ,这通常都由芯片厂家设置好。我们要做的是找到它名字,比如“gpio1” ,然后指定要用它里面的哪个 引脚,比如<&gpio1 0>
有代码更直观,下图是一些芯片的 GPIO 控制器节点,它们一般都是厂家定义好,在 xxx.dtsi 文件中: 
我们暂时只需要关心里面的这 2 个属性:
gpio-controller;
#gpio-cells = <2>;
gpio-controller ”表示这个节点是一个 GPIO Controller ,它下面有很多引脚。
  #gpio-cells = <2> ”表示这个控制器下每一个引脚要用 2 32 位的数 (cell)来描述。 为什么要用 2 个数?
其实使用多少个 cell 来描述一个引脚,这是 GPIO Controller 自己决定的。比如可以用其中一个 cell 来表示那是哪一个引脚,用另一个 cell 来表示它是高电平有效还是低电平有效,甚至还可以用更多的 cell 来示其他特性。 普遍的用法是,用第 1 cell 来表示哪一个引脚,用第 2 cell 来表示 有效电平:
GPIO_ACTIVE_HIGH : 高电平有效
GPIO_ACTIVE_LOW : 低电平有效
定义 GPIO Controller 是芯片厂家的事,我们怎么引用某个引脚呢?在自己的设备节点中使用属性"<name>-gpios" ,示例如下:
上图中,可以使用 gpios 属性,也可以使用 name-gpios 属性。
在驱动代码中调用 GPIO 子系统
在设备树中指定了 GPIO 引脚,在驱动代码中如何使用? 也就是 GPIO 子系统的接口函数是什么?
GPIO 子系统有两套接口:基于描述符的 (descriptor-based) 、老的 (legacy)。前者的函数都有前缀“ gpiod_ ”,它使用 gpio_desc 结构体来表示 一个引脚;后者的函数都有前缀“gpio_ ”,它使用一个整数来表示一个引脚。要操作一个引脚,首先要 get 引脚,然后设置方向,读值、写值。

总结:

在实际应用中,

imx6ull格式:

//client端:
@节点名字 {
    pinctrl-names = "default";
    pinctrl-0 = <&pinctrl_自定义名字A>;
    status = "okay";
};
 
//pincontroller服务端
pinctrl_自定义名字A: 自定义名字B {
    fsl,pins = <
            引脚复用宏定义   PAD(引脚)属性, // 引脚 A
            引脚复用宏定义   PAD(引脚)属性; // 引脚 B
    >;
};

Pinctrl client端:

在设备树里被定义为一个节点,在节点里声明要用哪些引脚并告诉驱动程序

  1. 包含了对应驱动程序的compatible属性值
  2. 包含了引脚被设置成的各种模式“default”、“sleep”等,下图中 default 模式也就是gpio模式
  3. 模式的选择“Pinctrl-0”,选择“pinctrl-names”中的第一种模式<&pinctrl_leds>取得了gpio子系统的设置(封装的寄存器的相关设置)
  4. (gpio子系统)gpios = <&gpio5 3 GPIO_ACTIVE_LOW>;有两个参数,表明用的引脚,且低电位有效,参数数量取决于GPIO Controlle:“gpio- cells =  <2>”,此参数将传递给驱动程序中的probe函数用来记录引脚信息。                
  5.  status表明pinctrl是否有效的状态

为什么gpios参数中要声明高低电平有效呢?     因为在驱动程序中设置引脚时传入的是逻辑值0或1来代表有效或不有效,但实际不同的板子引脚有效需要的物理实际值不同,有的是置1有效,有的置0有效。当在gpio子系统中设置有效参数后,驱动程序只要传入逻辑值1,子系统可以自动设置引脚为对应的物理值达成有效状态,对不同的开发板都是使用的。)

        myled{
         compatible = "100ask,leddrv";
         pinctrl-names = "defualt";
         pinctrl-0 = <&pinctrl_leds>;

         gpios = <&gpio5 3 GPIO_ACTIVE_LOW>;

         status = "okay";

        };

Pinctrl  服务端:

设置引脚来完成功能复用或配置

1)表明了该gpio系统的名字和功能,以及引脚的复用情况,下图中是将 MX6ULL_PAD_SNVS_TAMPER3_复用为GPIO5_IO03    

2) 0x000110A0代表对应寄存器的状态配置,包括了上下拉电阻,开漏推挽,输入输出方向等。

        pinctrl_leds: ledgrp {
            fsl,pins = <
                  MX6ULL_PAD_SNVS_TAMPER3__GPIO5_IO03        0x000110A0
            >;
        };

gpioctrl

/*添加rgb_led节点*/
rgb_led{
    #address-cells = <1>;
    #size-cells = <1>;
    compatible = "fire,rgb-led"; // 节点兼容性
    /* pinctrl 子系统 */
    pinctrl-names = "default"; // 引脚状态名称表
    pinctrl-0 = <&pinctrl_rgb_led>; // 第 0 个状态使用的引脚
    /* GPIO子系统 */
    rgb_led_red = <&gpio1 4 GPIO_ACTIVE_LOW>; // 使用的引脚 。旧版
    rgb_led_green-gpios = <&gpio4 20 GPIO_ACTIVE_LOW>; // 新版
    rgb_led_blue-gpios = <&gpio4 19 GPIO_ACTIVE_LOW>; // 新版
    status = "okay";
};

reg属性,一般用于描述设备地址空间资源信息,一般都是某个外设的寄存器地址范围信息。reg属性的格式为<address1 length1 address2 length2 ...>

在设备树中,GPIO组 就是一个 GPIO Controller

GPIO组 的节点内容是由芯片厂商设置好的,一般在芯片厂商提供的设备树头文件 xxx.dtsi 中。如 IMX6UL 的就在 imx6ull.dtsi 文件中定义。
用户只需要做的是根据芯片厂商文档格式要求,在相应设备树节点中填写引脚信息。

两个用处:1、指定GPIO引脚信息  

(为什么需要gpio子系统来指定呢?若不指定,用户就要从数据手册一个一个找寄存器看要用哪些寄存器、功能怎么设置,太繁琐)

                   2、给驱动程序提供API来访问IO口

参考: https://www.bilibili.com/read/cv13931424/from=search&spm_id_from=333.337.0.0 出处:bilibili

原文链接:https://blog.csdn.net/wwwlyj123321/article/details/122898506

  • 28
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值