【Linux驱动开发】010 pinctrl子系统

这篇具有很好参考价值的文章主要介绍了【Linux驱动开发】010 pinctrl子系统。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一、前言

上一章我们编写了基于设备树的 LED 驱动,但是驱动的本质还是没变,都是配置 LED 灯所使用的 GPIO 寄存器,驱动开发方式和裸机基本没啥区别。本章我们就来学习一下如何借助 pinctrl 和 gpio 子系统来简化 GPIO 驱动开发。 

 Linux 内核针对 PIN 的配置推出了 pinctrl 子系统,对于 GPIO的配置推出了 gpio 子系统。

本节先讲解 pinctrl 子系统。 


二、pinctrl子系统

1、pinctrl简介

传统的配置 pin 的方式就是直接操作相应的寄存器,但是这种配置方式比较繁琐、而且容易出问题(比如 pin 功能冲突)。pinctrl 子系统就是为了解决这个问题而引入的,pinctrl 子系统主要工作内容如下: 

①、获取设备树中 pin 信息。 
②、根根据获取到的 pin 信息来设置 pin 的复用功能 
③、据获取到的 pin 信息来设置 pin 的电气特性,比如上/下拉、速度、驱动能力等。

对于我们使用者来讲,只需要在设备树里面设置好某个 pin 的相关属性即可,其他的初始化工作均由 pinctrl 子系统来完成。 

2、I.MX6ULL 的 pinctrl 子系统驱动 

<1> PIN 设备树配置

pinctrl 子系统要根据你提供的信息来配置 PIN 功能,因此,如果要使用 pinctrl 子系统,我们需要在设备树里面创建一个节点来描述 PIN 的配置信息。

打开 imx6ull.dtsi 文件,找到一个叫做 iomuxc 的节点:

iomuxc: iomuxc@020e0000 { 
    compatible = "fsl,imx6ul-iomuxc"; 
    reg = <0x020e0000 0x4000>; 
}; 

打开 imx6ull.dts 文件,找到 iomuxc 节点的追加内容:

&iomuxc { 
    pinctrl-names = "default"; 
    pinctrl-0 = <&pinctrl_hog_1>; 
    imx6ul-evk { 
        pinctrl_hog_1: hoggrp-1 { 
            fsl,pins = < 
                MX6UL_PAD_UART1_RTS_B__GPIO1_IO19      0x17059  
                MX6UL_PAD_GPIO1_IO05__USDHC1_VSELECT   0x17059  
                MX6UL_PAD_GPIO1_IO09__GPIO1_IO09       0x17059  
                MX6UL_PAD_GPIO1_IO00__ANATOP_OTG1_ID   0x13058  
            >; 
        }; 
...... 
        pinctrl_wdog: wdoggrp { 
            fsl,pins = < 
                MX6UL_PAD_LCD_RESET__WDOG1_WDOG_ANY    0x30b0 
            >; 
        }; 
};

不同的外设使用的 PIN 不同、其配置也不同,因此一个萝卜一个坑,将某个外设所使用的所有 PIN 都组织在一个子节点里面。

这些外设子节点是没有compatible属性的,因此需要使用父节点的compatible属性 (.dtsi文件中) 对应的驱动文件对子节点进行处理。compatible 属性值为“fsl,imx6ul-iomuxc”,我们在 Linux 内核源码中全局搜索字符串“fsl,imx6ul-iomuxc”就会找到 I.MX6ULL 这颗 SOC 的 pinctrl 驱动文件。

<2> PIN 设备树配置信息详解

pinctrl 子系统如何添加 PIN 的配制信息呢?我们以 imx6ull.dts 文件中UART1_RTS_B 这个PIN为例说明:

MX6UL_PAD_UART1_RTS_B__GPIO1_IO19    0x17059 

配置信息分为两部分:
MX6UL_PAD_UART1_RTS_B__GPIO1_IO19(复用功能) 和 0x17059(电气属性)

🦌 MX6UL_PAD_UART1_RTS_B__GPIO1_IO19(复用功能)

MX6UL_PAD_UART1_RTS_B__GPIO1_IO19 其实是一个宏定义:

#define MX6UL_PAD_UART1_RTS_B__UART1_DCE_RTS 0x0090 0x031C 0x0620 0x0 0x3 
#define MX6UL_PAD_UART1_RTS_B__UART1_DTE_CTS 0x0090 0x031C 0x0000 0x0 0x0 
#define MX6UL_PAD_UART1_RTS_B__ENET1_TX_ER   0x0090 0x031C 0x0000 0x1 0x0 
#define MX6UL_PAD_UART1_RTS_B__USDHC1_CD_B   0x0090 0x031C 0x0668 0x2 0x1 
#define MX6UL_PAD_UART1_RTS_B__CSI_DATA05    0x0090 0x031C 0x04CC 0x3 0x1 
#define MX6UL_PAD_UART1_RTS_B__ENET2_1588_EVENT1_OUT 0x0090 0x031C 0x0000 0x4 0x0 
#define MX6UL_PAD_UART1_RTS_B__GPIO1_IO19    0x0090 0x031C 0x0000 0x5 0x0 
#define MX6UL_PAD_UART1_RTS_B__USDHC2_CD_B   0x0090 0x031C 0x0674 0x8 0x2 

这 8 个宏定义分别对应 UART1_RTS_B 这个 PIN 的 8 个复用 IO,上面代码的意思是将这个 IO 复用为 GPIO1_IO19:

pinctrl 子系统,linux驱动,驱动开发

宏定义后跟了5个数字,含义为:<mux_reg conf_reg input_reg mux_mode input_val> 。

                                                      0x0090 0x031C 0x0000 0x5 0x0 

  1. 0x0090:mux_reg 寄存器偏移地址(PIN 的复用寄存器地址)。相对于iomuxc 节点reg属性(外设寄存器的起始地址 0x020e0000)的偏移,该PIN 的端口复用寄存器IOMUXC_SW_MUX_CTL_PAD_UART1_RTS_B (设置IO复用)地址是 “基地址” + “偏移”。
  2. 0x031C:conf_reg 寄存器偏移地址,和 mux_reg 一样,0x020e0000+0x031c=0x020e031c,这个就是寄存器 IOMUXC_SW_PAD_CTL_PAD_UART1_RTS_B (设置IO电气属性)的地址。 
  3. 0x0000:input_reg 寄存器偏移地址。UART1_RTS_B 这个 PIN 在做GPIO1_IO19 的时候是没有 input_reg 寄存器,因此这里 intput_reg 是无效的。 
  4. 0x5:mux_reg  寄存器的值。也即是设置 UART1_RTS_B 这个 PIN 复用为 GPIO1_IO19。 
  5. 0x0:input_reg 寄存器值,在这里无效。

🦌 0x17059(电气属性)

0x17059:上面config_reg 寄存器的值,也就是设置电气属性的寄存器IOMUXC_SW_PAD_CTL_PAD_UART1_RTS_B的值,通过此值来设置一个 IO 的上/下拉、驱动能力和速度等。

<3> pinctrl驱动程序详解

所有的东西都已经准备好了,包括寄存器地址和寄存器值,Linux 内核相应的驱动文件就会根据这些值来做相应的初始化。

根据 iomuxc 节点中 compatible 属性的值 “fsl,imx6ul-iomuxc”,找到文件drivers/pinctrl/freescale/pinctrl-imx6ul.c ,具体内容不再列出,总之,该文件是一个标准的platform驱动,设备(设备树中iomuxc节点)和驱动匹配成功之后便会执行,然后按照以下函数调用路径解析设备树中提供的配置:

pinctrl 子系统,linux驱动,驱动开发

 <4> 设备树中添加pinctrl节点步骤(总结)

对于IMX 系列SOC 的pinctrl 设备树绑定信息,可以参考文档Documentation/devicetree/bindings/pinctrl/fsl,imx-pinctrl.txt。此处,我们建立一个虚拟的设备test,test 使用了 GPIO1_IO00 这个 PIN 的 GPIO 功能,pinctrl 节点添加过程如下: 

👺 创建对应的设备树节点

打开 imx6ull-alientek-emmc.dts,在 iomuxc 节点中的 “imx6ul-evk” 子节点下添加 “pinctrl_test” 节点,注意!节点前缀一定要为“pinctrl_”

pinctrl_test: testgrp { 
    /* 具体的 PIN 信息 */ 
}; 

👺 添 ”fsl,pins“ 属性

对于 I.MX 系列 SOC 而言,pinctrl 驱动程序是通过读取“fsl,pins”属性值来获取 PIN 的配置信息,完成以后如下所示: 

pinctrl_test: testgrp { 
    fsl,pins = < 
        /* 设备所使用的 PIN 配置信息 */ 
    >; 
}; 

👺 在“fsl,pins”属性中添加 PIN 配置信息 

在 “fsl,pins” 属性中添加具体的 PIN 配置信息:

pinctrl_test: testgrp { 
    fsl,pins = < 
        MX6UL_PAD_GPIO1_IO00__GPIO1_IO00  config /*config 是具体设置值*/ 
    >; 
};

至此,我们已经在 imx6ull-alientek-emmc.dts 文件中添加好了 test 设备所使用的 PIN 配置信息。 

三、注意事项

一个引脚一次只能实现一个功能,如果 A 引脚在设备树中配置为了 I2C 的 SDA 信号,那么 A 引脚就不能再配置为 GPIO,否则的话驱动程序在申请 GPIO 的时候就会失败。

检查 PIN 有没有被其他外设使用包括两个方面(pinctrl和gpio两方面的检查): 

①、检查 pinctrl 设置。 
②、如果这个 PIN 配置为 GPIO 的话,检查这个 GPIO 有没有被别的外设使用。 文章来源地址https://www.toymoban.com/news/detail-628304.html

到了这里,关于【Linux驱动开发】010 pinctrl子系统的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • <Linux开发>驱动开发 -之-Linux INPUT 子系统

    <Linux开发>驱动开发 -之-Linux INPUT 子系统 交叉编译环境搭建: <Linux开发> linux开发工具-之-交叉编译环境搭建 uboot移植可参考以下: <Linux开发> -之-系统移植 uboot移植过程详细记录(第一部分) <Linux开发> -之-系统移植 uboot移植过程详细记录(第二部分) <Linux开发

    2024年02月09日
    浏览(48)
  • Linux驱动开发:gpio子系统

    目录 1、GPIO配置流程 2、GPIO子系统API 2.1 of_find_node_by_path 2.2 of_get_named_gpio 2.3 gpio_request 与 gpiod_get 与 gpiod_get_index 2.4 gpio_direction_input 与 gpiod_direction_input 2.5 gpio_direction_output 与 gpiod_direction_output 2.6 gpio_get_value 与 gpiod_get_value 2.7 gpio_set_value 与 gpiod_set_value 2.8  gpiod_get_from

    2024年02月12日
    浏览(44)
  • Linux驱动开发:SPI子系统

    MISO:主设备数据输入,从设备数据输出。 MOSI:主设备数据输出,从设备数据输入。 SCLK:时钟信号,由主设备产生。 CS:    从设备片选信号,由主设备控制。 CPOL(时钟极性) :   0:时钟起始位低电平      1:时钟起始为高电平   CPHA(时钟相位) :0:第一个时钟周期采样   1

    2024年02月06日
    浏览(48)
  • 【Linux驱动开发】011 gpio子系统

    前面我们编写了基于设备树的 LED 驱动,但是驱动的本质还是没变,都是配置 LED 灯所使用的 GPIO 寄存器,驱动开发方式和裸机基本没啥区别。本章我们就来学习一下如何借助 pinctrl 和 gpio 子系统来简化 GPIO 驱动开发。   Linux 内核针对 PIN 的配置推出了 pinctrl 子系统,对于

    2024年02月03日
    浏览(45)
  • 【Linux驱动开发】012 gpio子系统API函数

    设置好设备树以后, 在驱动程序中就可以使用 gpio 子系统提供的 API 函数来操作指定的 GPIO, gpio 子系统向驱动开发人员屏蔽了具体的读写寄存器过程。这就是驱动分层与分离的好处,大家各司其职,做好自己的本职工作即可。 gpio 子系统提供的常用的 API 函数有下面几个:

    2023年04月18日
    浏览(40)
  • 【LED子系统深度剖析】一、开篇词|Linux驱动开发必读

    我的圈子: 高级工程师聚集地 我是董哥,高级嵌入式软件开发工程师,从事嵌入式Linux驱动开发和系统开发,曾就职于世界500强公司! 创作理念:专注分享高质量嵌入式文章,让大家读有所得!

    2024年02月09日
    浏览(39)
  • 【IMX6ULL驱动开发学习】14.Linux驱动开发 - GPIO中断(设备树 + GPIO子系统)

    代码自取 【14.key_tree_pinctrl_gpios_interrupt】: https://gitee.com/chenshao777/imx6-ull_-drivers 主要接口函数: 1. of_gpio_count (获得GPIO的数量) 2. kzalloc (向内核申请空间) 3. of_get_gpio (获取GPIO子系统标号) 4. gpio_to_irq (根据GPIO子系统标号得到软件中断号) 5. request_irq (根据软件中断号

    2024年02月12日
    浏览(49)
  • 【IMX6ULL驱动开发学习】21.Linux驱动之PWM子系统(以SG90舵机为例)

    首先在 imx6ull.dtsi 文件中已经帮我们定义好了一些pwm的设备树节点,这里以pwm2为例 我们要在设备树(.dts)文件中引用和使能该节点,同时指定好pwm映射到的GPIO引脚(即pinctrl子系统,我这里映射到了GPIO1_9上) 使用pwm 只需要在设备树节点中添加两条属性信息,如下所示 pwms :属

    2024年02月12日
    浏览(129)
  • Linux Mii management/mdio子系统分析之三 mii_bus注册、注销及其驱动开发流程

    (转载)原文链接:https://blog.csdn.net/u014044624/article/details/123303174       本篇是mii management/mdio模块分析的第三篇文章,本章我们主要介绍mii-bus的注册与注销接口。在前面的介绍中也已经说过,我们可以将mii-bus理解为mdio总线的控制器的抽象,就像spi-master、i2c-adapter一样。 本

    2024年01月16日
    浏览(42)
  • Linux MMC 驱动子系统详解

    SD/SDIO/MMC 驱动是一种基于 SDMMC 和 SD SPI 主机驱动的协议级驱动程序,目前已支持 SD 存储器、SDIO 卡和 eMMC 芯片。 因为linux内核mmc子系统里面已经实现了这些协议,我们以后并不需要重新实现这些,只需要对协议有个简单的了解。 mmc是比较老的存储卡了,sd是mmc的替代者,sdi

    2024年02月06日
    浏览(41)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包