Linux之pinctrl subsystem

本文介绍 Linux pinctrl 子系统的基本结构及工作原理。通过平台和外设驱动接口,简化了 CPU 引脚功能配置。利用 pinctrlcore 实现引脚状态查询与切换。

概述:

在各个平台(cpu厂商)上,都会用很多pin用于和外设通讯,同一个pin也会有多种功能,如同一个pin具有gpio,spi,uart,I2C等功能,这些功能会根据需求切换,以及在不同功能下都会上下拉,驱动能力,电压域的配置。linux为管理这些pin,就设计出了pinctrl subsystem来解决这类问题。当然,也可以不用pinctrl来管理,平台厂商如果不用,就会自己设计接口来管理,这种情况就具体看了。

pinctrl subsystem的结构:

个人理解,在linux提供给驱动用的subsystem基本上都是:

  • 外设驱动开发接口
  • 平台(cpu)开发接口
  • pinctrl core

本文将按照这三个部分,来讲述pinctrl subsystem。

pinctrl core:

  • pinctrl core目的(效果,作用):
    驱动开发者,在开发外设驱动时,将外部设备与主控连接的pin配置需要的功能时,只需要简单的提供设备的struct device和功能的名字,这两个信息就可以设置到需要的功能。

  • 为实现目的,设计三个结构体为核心(drivers\pinctrl\core.h):
    struct pinctrl_dev;
    struct pinctrl_map;
    struct pinctrl;
    同时也定义了这三个结构体链表,方便管理和查询pinctrldev_list,pinctrl_maps,pinctrl_list(定义都在drivers\pinctrl\core.c)
    (1)首先,平台厂商通过pinctrl_register()注册struct pinctrl_dev到core,
    struct pinctrl_dev *pinctrl_register(struct pinctrl_desc *pctldesc,struct device *dev, void *driver_data)
    重点就在构建struct pinctrl_desc 和driver_data.
    (2)一般在驱动开发中,都是通过platform注册,在probe前会调用在drivers\base\dd.c里面函数really_preboe(),在这个函数里面,又会调用pinctrl_bind_pins(),这个函数就会为struct device创建pins成员,如果device中of_node(dts中节点)指向的dts节点中,有:

    pinctrl-names = "default","gpio";
    pinctrl-0 = <0xb8 0xb9>;
    pinctrl-1 = <0xba>;

则根据phandle值,建立struct pinctrl_map,这样,设备device的pins(struct pinctrl)通过pinctrl_map与pinctrl_dev联系起来,达到了通过device查询到pinctrl_dev里面pin的配置。改变pin属性配置,就变成了只需要修改dts里面设备节点phandle的值了。

外设驱动开发接口:

平台提供商在releas的code里面,如果用pinctrl来管理pin,那么一般都会做好cpu的pin资源与pinctrl subsystem的对接。那剩下给外设驱动开发,配置某个pin成需要的功能,就非常简单了。主要用下面两个函数即可,用下面的函数需要在驱动模块里面包含如下头文件:

#include <linux/pinctrl/consumer.h>

函数:

struct pinctrl_state *pinctrl_lookup_state(struct pinctrl *p,
                         const char *name);
int pinctrl_select_state(struct pinctrl *p, struct pinctrl_state *state)

用法:

  1. 首先用pinctrl_lookup_state()查询是否有name指定的功能,如果有返回pinctrl_state这个结构体的指针,没有返回负数。
  2. 然后用pinctrl_select_state()切换pin到需要的功能。

例子:

struct device dev;
struct pinctrl_state *pinfunc;
pinfunc = pinctrl_lookup_state(dev.pins->p,"gpio");
if(IS_ERR(pinfunc))
    return -1;//error
if(pinctrl_select_state(dev.pins->p,pinfunc))
    return -1;//error
return 0; 

在dts中查看pin可以配置那些功能:
一般情况,为了描述CPU可控制pin的情况,会在dts中创建一个pinctrl node,如下:

pinctrl@ff770000{
...
...
    gpi08_i2c1{
        i2c1-sda{
            rockchip,pins = <0x8a41>;//具体哪个pin和pin配置成什么功能,这里是i2c的sda
            rockchip,pull = <0x4>;//I2C功能,pin上下拉配置要求
            rockchip,drive = <0x0>;//pin的驱动能力
            linux,phandle = <0xb8>;//此配置的编号,这个值在dts中是唯一的(老版本写法,为了兼容)
            phandle = <0xb8>;//和linux,phandle是一样的,此处是新版本,
        };
        i2c1-scl{
            rockchip,pins = <0x8a51>;
            rockchip,pull = <0x4>;
            rockchip,drive = <0x0>;
            linux,phandle = <0xb9>;
            phandle = <0xb9>;
        };
        i2c1-gpio{
            rockchip,pins = <0x8a40>;
            rockchip,drive = <0x0>;
            linux,phandle = <0xba>;
            phandle = <0xba>;
        };
    };
};
...
...

下面是配置成I2C功能,需要指定pin配置:

i2c@ff140000{
...
...
pinctrl-names = "default","gpio";//这个节点提供了两种功能default和gpio
pinctrl-0 = <0xb8 0xb9>;//对应default功能(i2c),pin配置采用上面"phandle = <0xb8>""phandle = <0xb9>"所在节点(dts节点)属性配置
pinctrl-1 = <0xba>;//对应gpio,pin配置采用“phandle = <0xba>”所在节点(dts节点)属性配置
...
...
};

回到下面这行代码,就很清楚了:
pinfunc = pinctrl_lookup_state(dev.pins->p,”gpio”);

待续……

<think>好的,我现在需要帮助用户了解如何在Linux内核中配置支持pinctrl子系统。首先,我得回忆一下pinctrl的作用。pinctrl主要用于管理SoC的引脚复用和配置,比如GPIO、I2C、SPI等功能的引脚设置。所以在配置内核时,相关的选项需要被启用。 接下来,我应该考虑内核版本。不同版本的Linux内核可能会有不同的配置选项位置,但一般来说,pinctrl的配置位于Device Drivers菜单下。用户可能需要进入“Device Drivers -> Pin controllers”来找到相关选项。 然后,具体的配置选项可能包括CONFIG_PINCTRL和特定于硬件的选项,比如针对某个SoC的pinctrl驱动。比如,如果是使用三星的Exynos芯片,可能需要CONFIG_PINCTRL_EXYNOS。这时候,用户需要根据自己使用的硬件来选择对应的驱动。 另外,设备树(Device Tree)的配置也是关键部分。用户需要在设备树中正确配置各个外设的引脚控制信息,包括引脚功能、电气特性等。这部分可能需要查阅具体的SoC文档或参考内核中的示例dts文件。 可能还需要提醒用户,在配置完成后,重新编译内核并更新到目标设备上,然后检查系统启动时的日志,确认pinctrl驱动是否正确加载,是否存在引脚配置错误。 用户可能会有疑问,比如如何确定自己的硬件需要哪些特定的pinctrl驱动,或者如何调试引脚配置问题。这时候可能需要指导他们查看内核文档、设备树绑定文档,或者使用调试工具如dmesg来查看内核日志。 最后,确保整个解释过程清晰,步骤分点说明,方便用户一步步操作。同时,注意使用中文,避免专业术语过于晦涩,必要时举例说明。</think>在Linux内核中配置pinctrl子系统的支持需要以下步骤: 1. **理解pinctrl作用**: - 管理SoC引脚复用(Multiplexing) - 配置引脚电气特性(如上拉/下拉、驱动强度) - 为各外设(I2C/SPI/UART等)提供标准化配置接口 2. **内核配置步骤**: ```shell # 进入内核配置界面 make menuconfig ``` 通过以下路径启用核心功能: ``` Device Drivers → Pin controllers → [*] Enable pin controllers → [*] Support pinctrl subsystem → 选择对应芯片的驱动(如Exynos、i.MX等) ``` 3. **关键配置选项**: ```kconfig CONFIG_PINCTRL=y CONFIG_PINCTRL_<SOC_VENDOR>=y # 例如: CONFIG_PINCTRL_EXYNOS=y # 三星Exynos CONFIG_PINCTRL_ROCKCHIP=y # Rockchip CONFIG_PINCTRL_STM32=y # STM32 ``` 4. **设备树配置示例**(以GPIO按键为例): ```dts / { pinctrl: pinctrl@XXXXXX { compatible = "vendor,soc-pinctrl"; button_pins: button_pins { vendor,pins = "GPIO_A5", "GPIO_B3"; vendor,function = "gpio"; vendor,pull-up; }; }; gpio-keys { compatible = "gpio-keys"; pinctrl-names = "default"; pinctrl-0 = <&button_pins>; button1 { gpios = <&gpio 5 GPIO_ACTIVE_LOW>; }; }; }; ``` 5. **配置验证方法**: ```shell # 查看已加载的pinctrl驱动 dmesg | grep pinctrl # 查看引脚配置状态 cat /sys/kernel/debug/pinctrl/<pinctrl_device>/pins cat /sys/kernel/debug/pinctrl/<pinctrl_device>/pingroups ``` **常见问题排查**: 1. 引脚功能不生效: - 检查设备树pinctrl绑定是否正确 - 确认驱动代码中引用了正确的pinctrl配置 - 验证时钟是否使能 2. 电气特性异常: - 检查pull-up/down配置 - 确认驱动强度设置 - 验证电压域配置 **注意事项**: - 不同SoC厂商的pinctrl实现可能有差异 - 需要参考具体芯片的《参考手册》电气特性章节 - 建议复用内核已有设备树配置作为模板 - 调试时可配合示波器/万用表验证实际电平 完整的pinctrl子系统配置需要驱动开发人员、硬件工程师和PCB layout工程师协同工作,确保软件配置与硬件设计一致。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值