博主假设大家已经阅读了下面这篇文章:GPIO软件框架这篇文章直接深入剖析了pinctrl子系统。使用pinctrl和gpio子系统进行GPIO驱动开发是嵌入式驱动工程师的基本操作,但大多数驱动工程师只使用子系统提供的API接口,并不会分析其底层实现。本文介绍其底层实现分析,文末有参考文章链接。在此框架中,(1)、(2)和(3)由半导体制造商处理。半导体厂商会利用Linux提供的框架,根据自己的芯片定制代码。普通的驱动工程师即使在写驱动,也只是调用API而已。本文主要关注(2),所以从图中我们知道pinctrl子系统和gpio子系统都依赖于(2)的驱动。工具分析源码可以在线查看Linux内核源码,在线网址跳转功能和搜索结构也很方便:https://elixir.bootlin.com/linux/latest/source对于嵌入式工程师来说,少谈设计模式、重构等,因为我们局限于两个方面:硬件、系统(Linux、Android)。很多东西都是操作系统规定好的,留给我们重新设计的已经很少了。我们不做设计题,我们做填空题。在linux内核源码中,pinctrl子系统的代码大多在kernel/drivers/pinctrl/...,不同的平台有不同的文件夹。gpio子系统的大部分代码都在kernel/drivers/gpio/...目录下。博主买了正点原子的imx6ull开发板,所以就拿这块板子作为例程进行分析。一、主要结构pinctrl子系统主要结构之间的关系:pinctrl_dev是pinctrl子系统的根结构,主要包括三个路径:1.pinctrl_desc:这里包含了pinctrl子系统最重要的三个结构,有三个操作函数集,pinctrl_ops包括对PIN的操作函数集,pinmux_ops包括对PIN的复用函数集,pinconf_ops包括对PIN的配置函数,可以在你的平台中点击查看你的平台实现了哪些功能,如何实现.2.pinctrl结构体:这个包含了PIN控制器控制的PIN状态状态。状态包含设置。此设置是设备树中PIN的设置。你可以点击查看相关的数据结构,可以看到你在设备树中使用的String。3、gpio相关的结构体。我们说过pinctrl子系统和gpio子系统是耦合的。从结构体我们可以看出,它包含了最重要的结构体gpio_chip。我们已经描述了pinctrl子系统的主要数据结构,后面会介绍函数调用关系。2、函数调用逻辑在文件drivers/pinctrl/freescale/pinctrl-imx6ul.c中有如下内容:驱动的入口是arch_initcall中声明的函数,类似于我们经常写的module_init,但是arch_initcall会首先被调用。这里写的是:Linux驱动挂载顺序分析我们从下往上看,可以看到最后调用的是imx6ul_pinctrl_probe函数,和普通驱动的probe函数一样,也就是说,pinctrl子系统也是一个标准平台驱动框架分为:driver,device,andbus。平台虚拟总线会根据of_device_id结构中的compatible属性来匹配pinctrl驱动和设备。在不同芯片厂商的probe函数中,都会对上述数据结构进行初始化、填充、调用、释放。我们来看第292行,这是一个匹配结构。它根据设备树的compatible和compatible字段进行匹配。如果匹配成功,则执行探测函数。每个平台的probe功能不一样,就不细说了。我们来看292行of_device_id定义的数组,最后一个元素是空元素。这是必要的,因为平台本身的匹配功能需要判断是否到达终点。of_device_id定义的兼容性通常不止一种。系统需要知道是否匹配到最后一个元素,这个必须要注意。在pinctrl_registerprobe函数之后的调用中,最重要的是调用pinctrl_register函数,这个函数用于向Linux内核注册一个PIN控制器。这个函数的原型如下:structpinctrl_dev*pinctrl_register(structpinctrl_desc*pctldesc,structdevice*dev,void*driver_data)其中参数pctldesc很重要,因为这个参数是要注册的PIN控制器,PIN控制器是用来注册的配置SOC的PIN多路复用函数和电气特性。pctlDesc是pinctrl_desc结构体结构体结构体结构体类型类型,Pinctrl_desc结构体结构体结构体结构体结构体如下如下:structpinctrl_desc{constar*confops;structmodule*owner;#ifdefCONFIG_GENERIC_PINCONFunsignedintnum_custom_params;conststructpinconf_generic_params*custom_params;conststructpin_config_item*custom_conf_items;#endif};这三个“_ops”结构指针非常重要!因为这三个结构体是PIN控制器的“工具”,这三个结构体包含了很多操作函数,通过这些操作函数可以完成对某个PIN的配置。pinctrl_desc结构体需要用户提供,结构体中的成员变量也由用户提供。但是这个用户并不是我们这些使用芯片的程序员,而是半导体厂商。这些任务已经在半导体制造商发布的Linux内核源代码中完成。下面是一篇参考文章,比博主更深入,尤其是第一个链接,大家可以看看。参考文章:http://www.wowotech.net/sort/gpio_subsystemhttps://www.freesion.com/article/89301077969/https://blog.csdn.net/u012830148/article/details/80609337《正点原子 imx6u Linux 驱动开发指南》
