NXP i.MX8系列平台开发讲解 - 3.3 Linux 之Pinctrl子系统

 专栏文章目录传送门返回专栏目录


目录

1. Pinctrl 子系统的作用

2. Pinctrl实现的功能

3. 软件框架

4. 驱动相关分析

4.1 pinctrl_desc结构体

4.2 引脚获取与描述

5. 实例

Linux内核的Pinctrl子系统是一个非常见的框架系统,该子系统的目的是为了提供对硬件引脚(Pin)进行配置和控制的通用接口。通过 pinctrl 子系统,驱动程序可以请求和配置特定硬件引脚的功能和属性,从而实现对硬件引脚的灵活控制。


1. Pinctrl 子系统的作用

pinctrl子系统在Linux内核中的作用和目标是为了实现设备引脚的统一管理和配置,提供硬件抽象和解耦,支持平台适配性,允许动态配置设备引脚的功能和特性,以及促进驱动程序的共享,从而提高Linux内核在不同硬件平台上的可移植性和灵活性。

  • 硬件抽象和解耦:pinctrl将硬件引脚配置与驱动程序分离,简化驱动开发,让开发人员专注于设备功能。

  • 平台适配性:pinctrl支持不同硬件平台的设备引脚配置,提高内核的可移植性。

  • 设备树集成:通过设备树描述硬件引脚配置,实现硬件信息的抽象和动态加载。

  • 灵活性和可配置性:允许在运行时动态配置设备引脚的功能和特性,适应不同应用场景。

  • 驱动程序共享:多个设备可共享同一设备引脚配置,减少重复代码,简化系统维护。

pinctrl简化了驱动开发,提高内核可移植性,允许灵活配置设备引脚,并促进代重用。通俗来讲,在如今各个厂商SOC的pin脚设计使用可能会有一些不一样,但是采用了pinctrl子系统就可以统一进行管理,对于开发人员来说只需要去操作pinctrl就可以。


2. Pinctrl实现的功能

  • 管理系统中所有可以控制的pin,初始化过程,枚举所有的pin, 配置;

  • 管理这些pin的复用功能,pin有的可以配置为gpio, 也可以配置特定功能I2C,SPI,uart等 ;

  • 配置这些pin, 比如配置引脚的上拉,下拉,配置引脚的驱动强度;


3. 软件框架

图片

从软件结构图可以看出,蓝色部分就是内核虚拟出的pin control,这个是和硬件无关的模块,抽象出所有pin controller的硬件特性。为底层的Soc提供底层的通信接口能力,在用户层,提供的都是各个Driver,而不需要去关注底层是如何实现。


4. 驱动相关分析

这里以i.MX8MQ 为例子

./arch/arm64/boot/dts/freescale/imx8mq.dtsi
./arch/arm64/boot/dts/freescale/imx8mq-evk.dts
./drivers/pinctrl/core.c
./drivers/pinctrl/devicetree.c
./drivers/pinctrl/pinmux.c
./drivers/pinctrl/pinconf.c
  // 不同厂商代码
./drivers/pinctrl/freescale/pinctrl-imx8mq.c
./drivers/pinctrl/freescale/pinctrl-imx.c

上面展示了设备树,Linux 内部的pinctrl,另外是不同Soc实现的代码;

pincontroller虽然是没有硬件的支持,是一个软件的概念,所以对于这个我们需要进行去构造;构造pinctrl dev 设备需要提供结构体pinctrl_desc 再进行注册;

先从DTS设备树查看

//vim ./arch/arm64/boot/dts/freescale/imx8mq-evk.dts
                          iomuxc: pinctrl@30330000 {
                                  compatible = "fsl,imx8mq-iomuxc";
                                  reg = <0x30330000 0x10000>;
                          };

根据compatible 中,查找到驱动:

./drivers/pinctrl/freescale/pinctrl-imx8mq.c

struct pinctrl_desc *imx_pinctrl_desc;
  //...
          imx_pinctrl_desc->name = dev_name(&pdev->dev);
          imx_pinctrl_desc->pins = info->pins;
          imx_pinctrl_desc->npins = info->npins;
          imx_pinctrl_desc->pctlops = &imx_pctrl_ops;
          imx_pinctrl_desc->pmxops = &imx_pmx_ops;
          imx_pinctrl_desc->confops = &imx_pinconf_ops;
          imx_pinctrl_desc->owner = THIS_MODULE;
  
          /* for generic pinconf */
          imx_pinctrl_desc->custom_params = info->custom_params;
          imx_pinctrl_desc->num_custom_params = info->num_custom_params;

从代码明显看到probe 函数功能,另外一个重点是注册pinctrl设备,probe中将根据设备树信息,进行配置,对结构体pinctrl_desc一些接口进行设置。

struct pinctrl_desc *imx_pinctrl_desc;
  //...
          imx_pinctrl_desc->name = dev_name(&pdev->dev);
          imx_pinctrl_desc->pins = info->pins;
          imx_pinctrl_desc->npins = info->npins;
          imx_pinctrl_desc->pctlops = &imx_pctrl_ops;
          imx_pinctrl_desc->pmxops = &imx_pmx_ops;
          imx_pinctrl_desc->confops = &imx_pinconf_ops;
          imx_pinctrl_desc->owner = THIS_MODULE;
  
          /* for generic pinconf */
          imx_pinctrl_desc->custom_params = info->custom_params;
          imx_pinctrl_desc->num_custom_params = info->num_custom_params;
 

4.1 pinctrl_desc结构体

回头看看pinctrl_desc结构体:

./include/linux/pinctrl/pinctrl.h

 ./include/linux/pinctrl/pinctrl.h
  /**
   * struct pinctrl_desc - pin controller descriptor, register this to pin
   * control subsystem
   * @name: name for the pin controller
   * @pins: an array of pin descriptors describing all the pins handled by
   *      this pin controller
   * @npins: number of descriptors in the array, usually just ARRAY_SIZE()
   *      of the pins field above
   * @pctlops: pin control operation vtable, to support global concepts like
   *      grouping of pins, this is optional.
   * @pmxops: pinmux operations vtable, if you support pinmuxing in your driver
   * @confops: pin config operations vtable, if you support pin configuration in
   *      your driver
   * @owner: module providing the pin controller, used for refcounting
   * @num_custom_params: Number of driver-specific custom parameters to be parsed
   *      from the hardware description
   * @custom_params: List of driver_specific custom parameters to be parsed from
   *      the hardware description
   * @custom_conf_items: Information how to print @params in debugfs, must be
   *      the same size as the @custom_params, i.e. @num_custom_params
   * @link_consumers: If true create a device link between pinctrl and its
   *      consumers (i.e. the devices requesting pin control states). This is
   *      sometimes necessary to ascertain the right suspend/resume order for
   *      example.
   */
  struct pinctrl_desc {
          const char *name;
          const struct pinctrl_pin_desc *pins;
          unsigned int npins;
          const struct pinctrl_ops *pctlops;
          const struct pinmux_ops *pmxops;
          const struct pinconf_ops *confops;
          struct module *owner;
  #ifdef CONFIG_GENERIC_PINCONF
          unsigned int num_custom_params;
          const struct pinconf_generic_params *custom_params;
          const struct pin_config_item *custom_conf_items;
  #endif
          bool link_consumers;
  };
 

这三个都是需要硬件厂商去实现的,不同的Soc 厂商会对这些进行实现,如果是做原厂的驱动开发,需要去深入了解,对于做普通驱动,我们知道如何使用他们就可以。

const struct pinctrl_ops *pctlops; //对管脚组的操作集

const struct pinmux_ops *pmxops;//对管脚复用的操作集

const struct pinconf_ops *confops;//对管脚电气的操作集

对于pinctrol 的注册,也是在i.MX8MQ probe部分,在对pinctrl_desc已经定义好后就开始注册,

 static int imx8mq_pinctrl_probe(struct platform_device *pdev)
    --int imx_pinctrl_probe(struct platform_device *pdev,
                          const struct imx_pinctrl_soc_info *info)
      --int devm_pinctrl_register_and_init(struct device *dev,
                                         struct pinctrl_desc *pctldesc,
                                         void *driver_data,
                                         struct pinctrl_dev **pctldev)

4.2 引脚获取与描述

对于一个引脚来说,一般都需要去操作它,那么就要用到刚刚那个结构体pinctrl_pin_desc首先进行描述一个引脚,

pinctrl_ops 这个结构体对管脚进行操作

 static const struct pinctrl_ops imx_pctrl_ops = {
          .get_groups_count = pinctrl_generic_get_group_count,
          .get_group_name = pinctrl_generic_get_group_name,
          .get_group_pins = pinctrl_generic_get_group_pins,
          .pin_dbg_show = imx_pin_dbg_show,
}

获取某一组引脚:get_groups_count, get_group_pins

处理设备树中Pin Controller的某个节点dt_node_to_map 这个函数的作用就是叫设备树转换成pinctrl map,在驱动中可认识;


5. 实例

i.MX8MQ 为例

  • Pin Controller

图片

  • Clinet Device

图片

从上面例子来看,clinet 的设备节点转换成Platform_device, 如图中的SD卡,其中每个结构体都有一个dev_pin_info结构体,用来保存设备的pinctrl信息

  • 21
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值