pinctrl和gpio子系统实验

warren
2024-08-29 / 0 评论 / 2 阅读 / 正在检测是否收录...

Linux 驱动讲究驱动分离与分层,也就是把与soc芯片相关的一些驱动代码与具体的驱动应用给分离开。

pinctrl子系统

pinctrl 子系统主要完成:①获取设备树中 pin 信息②根据获取到的 pin 信息来设置 pin 的复用功能③根据获取到的 pin 信息来设置 pin 的电气特性,比如上/下拉、速度、驱动能力等。
也即是说我们只需要在设备树中描述好这个gpio的具体属性,则pinctrl子系统会根据这些信息帮我们初始化好这个pin。

pinctrl在设备树中的添加/修改方法

我们打开设备树文件imx6ull-alientek-emmc.dts。找到iomuxc节点。在iomuxc节点下创建一个子结点,内容如下:

pinctrl_led: ledgrp{
  fsl,pins = <
    MX6UL_PAD_GPIO1_IO03__GPIO1_IO03    0x10B0
  >;
};
  • pinctrl节点的节点名称必须是以pincrtl_xxxx来命名
  • pinctrl 驱动程序是通过读取“fsl,pins”属性值来获取 PIN 的配置信息
  • fsl中填写的是PIN的复用功能,pins中填写的是PIN的电气属性。
    MX6UL_PAD_UART1_RTS_B__GPIO1_IO19,这是一个宏定义,定义在文件arch/arm/boot/dts/imx6ul-pinfunc.h。打开这个文件我们可以看到里面有好多个宏。
    m0fao8y4.png
    这些宏其实是5个一组的值。具体含义就是<mux_reg conf_reg input_reg mux_mode input_val>
  • mux_reg:mux_reg 寄存器偏移地址
  • conf_reg:conf_reg 寄存器偏移地址
  • input_reg:input_reg 寄存器偏移地址
  • mux_reg:mux_reg寄存器值
  • input_val:input_reg 寄存器值
  • 另外:pins中填写的就是conf_reg 寄存器的值

那么有个问题,iomux如何根据这些信息来初始化pin。
iomuxc 节点中 compatible 属性的值为“fsl,imx6ul-iomuxc”,在 Linux 内核中全局搜索“fsl,imx6ul-iomuxc”字符串就会找到对应的驱动文件
m0fbfh4j.png
第326行有一个 of_device_id 结构体数组,保存着这个驱动文件的兼容性值。那也就说 pinctrl-imx6ul.c 会完成 I.MX6ULL 的 PIN 配置工作。
第347-355行有一个platform_driver结构体类型变量。它里面有个 probe 成员变量,当设备和驱动匹配成功以后 platform_driver 的 probe 成员变量所代表的函数就会执行。也就是说imx6ul_pinctrl_probe是PIN配置的入口函数。
调用路径如下:
m0fbrdre.png
imx_pinctrl_parse_groups 负责获取设备树中关于 PIN 的配置信息。
m0fbxrmj.png
pinctrl_register此函数用于向Linux内核注册一个PIN控制器,函数原型如下
m0fc95zb.png
余下的没有深究

gpio子系统

gpio子系统用于初始化 GPIO 并且提供相应的 API 函数,比如设置 GPIO为输入输出,读取 GPIO 的值等。
驱动开发者在设备树中添加 gpio 相关信息,然后就可以在驱动程序中使用 gpio 子系统提供的 API函数来操作 GPIO
我们在设备树根节点添加gpioled节点

gpioled{
  #address-cells = <1>;
  #size-cells = <1>;
  compatible = "atkalpha-gpioled";
  pinctrl-name = "default";
  pinctrl-0 = <&pinctrl_led>; //指定使用的PIN对应的pinctrl节点
  led-gpio = <&gpio1 3 GPIO_ACTIVE_LOW>;//指定所使用的GPIO为GPIO1-IO03且低电平有效
  status = "okay";
};

gpio子系统API函数

  1. gpio_request函数,申请一个GPIO管脚

      //要申请的 gpio 标号
      //给 gpio 设置个名字
      int gpio_request(unsigned gpio, const char *label)
  2. gpio_free函数,释放一个GPIO管脚

      //要释放的 gpio 标号
      void gpio_free(unsigned gpio)
  3. gpio_direction_input函数

      //设置某个 GPIO 为输入
      int gpio_direction_input(unsigned gpio)
  4. gpio_direction_output函数

      //要设置为输出的 GPIO 标号
      //GPIO 默认输出值
      int gpio_direction_output(unsigned gpio, int value)
  5. gpio_get_value函数

      //要获取的 GPIO 标号
      int __gpio_get_value(unsigned gpio)
  6. gpio_set_value函数

      //gpio:要设置的 GPIO 标号
      //value: 要设置的值
      __gpio_set_value(unsigned gpio, int value)

    与gpio相关的of函数

    1.of_gpio_named_count 函数(获取设备树某个属性里面定义了几个 GPIO 信息,包括空信息)

      //np:设备节点
      //propname:要统计的 GPIO 属性
      int of_gpio_named_count(struct device_node *np, const char *propname)

    2.of_gpio_count函数(获取设备树“gpios”这个属性的 GPIO 数量,包括空信息)

      //np:设备节点
      int of_gpio_count(struct device_node *np)

    3.of_get_named_gpio(获取 GPIO 编号)

      //np:设备节点
      //propname:包含要获取 GPIO 信息的属性名
      //GPIO 索引(因为一个属性里面可能包含多个 GPIO,此参数指定要获取哪个 GPIO的编号,如果只有一个 GPIO 信息的话此参数为 0。)
      int of_get_named_gpio(struct device_node *np,const char *propname,int index)
      /*补充:此函数在驱动中使用很频繁*/
0

评论 (0)

取消