这周主要对pinctrl子系统进行分析,该分析的基本上已经分析完成,唯一没有细说的估计就是gpio与pinctrl之间的关联了。本章即是pinctrl子系统分析的最后一章,本章我们主要实现一个虚拟的pinctrl device驱动,以便我们能够使用pinctrl子系统提供的接口,实现pinctrl device的驱动开发(本章实现的驱动代码可以在ubuntu18.04系统上正常运行)。
本篇文章的目的如下:
本篇文章涉及的知识点:
本章的主要章节如下:
一、 virt soc pin描述
二、 virt pinctrl dev驱动实现
三、virt board pin描述及pinctrl maps注册
四、device与pinctrl的绑定
五、gpio与pinctrl子系统相关知识点说明
六、功能验证
既然pinctrl device是对soc pin controller的驱动程序,因此我们需要定义下我们虚拟的soc引脚定义。
如下图所示,本virt soc 提供32个pin,每一个pin支持4个可选状态。提供2个32bit寄存器描述该soc 引脚复用信息,因为每个pin支持4个可选状态,因此使用2bits描述该pin的状态。因为只是一个虚拟的soc pin描述,因此此处仅定义了32个pin信息。
两个寄存器分别定义pinmux_reg0、pinmux_reg1,其中pin0使用pinmux_reg0的bit0、bit1描述其状态:00b表示gpio0;01b iic0_sdat。Pin1使用pinmux_reg0的bit2、bit3描述其状态:00b表示gpio1;10表示uart0_tx;
该soc可支持32个gpio、3个iic、2个uart、1个spi、2个can、1个nandflash的功能复用,而这些功
能中存在着引脚复用。
前面的文章中,已经说明了pinctrl dev的驱动开发流程,此处再次说明一下:
主要包含如下几个步骤:
我们定义了三个数据结构,分别为struct virt_function_desc、struct virt_group_desc、struct virt_pinctrl,其中struct virt_function_desc是对一个function的描述,struct virt_group_desc是对一个group的描述,而struct virt_pinctrl则描述一个soc pin controller。
该数据结构描述一个function,包含function名称、该function所包含的group名称数组、group的个数、引脚复用的配置参数、引脚复用配置参数的掩码(针对我们的soc,mask为0x03(占用2位),而mux_val即为引脚复用配置值,如针对iic function,则其mux_val为0x01)
该数据结构描述一个group,包含group名称,该group包含的引脚个数、引脚id数组。
该数据结构描述一个soc pin controller,包含:
如下是该soc pin controller对应的struct pinctrl_desc类型变量的定义,包含描述该soc pin controller的引脚信息的变量(virt_pins)、引脚复用操作接口(virt_pinmux_ops)、group获取相关的操作接口(virt_pinctrl_ops),此处我们没有实现引脚配置的操作接口,感兴趣的童鞋可自行实现。
调用pinctrl_register/devm_pinctrl_register接口即完成virt soc controller 驱动的注册。
如下即为该virt pinctrl dev驱动对应的platform driver probe函数的实现,相对来说比较简单
在上面我们为该platform device注册了属性参数,主要用于读取引脚复用配置寄存器virt_pinctrl_ptr->pin_mux_reg的信息,定义如下:
上面说明soc pin controller 驱动的实现,下面我们说明virt board pin 描述及pinctrl maps的注册。
由于在ubunt1804上测试,其内核是没有支持设备树的,因此我们通过定义struct pinctrl_map数组,并调用pinctrl_register_mappings实现baord相关的pinctrl maps注册。
因为仅是测试验证,此处我们仅描述spi0的pinctrl_map(若是正常的驱动,则需要描述本board所需要配置的所有pinctrl_map信息),我们的pinctrl_map,其对应的spi设备名称为virt_spi.0(spi master设备所对应的platform device的名称,因为spi master并没有使用设备与驱动绑定操作,因此此处不能是spi master对应device的名称)、virt_pinctrl_dev是我们上面定义的virt pinctrl dev对应的struct device类型变量的名称、spi0_group表示我们选择的virt soc pin controller的组名称、spi0_func表示我们选择的virt soc pin controller的function名称(对应最上面的引脚状态定义表格的内容)。
调用pinctrl_regiser_mappings后,则将该pinctrl_map注册到pinctrl_maps链表上。
若内核支持设备树,则需要在各自外设的的节点中增加针对pinctrl function、pinctrl group的描述即可。如下图时zynq-zc702的i2c0控制器的节点描述,通过pinctrl-names(描述该function的状态,包含default、idle、sleep等,在之前的文章中已经说明,需要了解的可查看之前的文章)、pinctrl-0(对应的的function定义)即可描述
在上面我们定义了针对spi0的pinctrl map,那什么时候才会配置spi0的引脚复用呢?我们在前面的《Linux pinctrl子系统分析之六 设备与pinctrl子系统的bind》文章中已经说明,当spi0对应的platform device、platform driver 匹配成功后,probe时进行设备与pinctrl子系统的绑定,并完成引脚的参数配置、复用配置操作。而在此次测试中,我们使用之前在《spi分析专栏》中实现的虚拟spi控制器驱动,完成虚拟spi控制器对应的platform device、platform driver的注册及绑定,从而完成针对spi0引脚的复用配置操作(虚拟spi控制器驱动实现就不再此处细说了)。
针对gpio的使用,一般也是需要进行引脚复用配置,如我们在此处定义的引脚状态表中,这32个引脚既可以作为gpio引脚、也可以作为不同控制器的引脚。而针对gpio控制器而言,和普通的设备引脚复用又有所不同,针对普通的设备而言,若作为设备引脚使用,则这些引脚均被设备使用(如iic0 sda、iic0 scl)。但是针对gpio控制器而言,如我们实现虚拟gpio控制器,其包含32个gpio引脚,但是由于引脚复用的关系,该gpio控制器中可能只有部分引脚可以作为gpio,因此针对gpio的引脚复用配置,pinctrl与gpio子系统做了兼容设置。
在调用gpio_request时,则会调用pinctrl 子系统提供的pin_request操作,通过pin_request确定该引脚是否已被其他模块使用(gpiochip_generic_request接口或者pinctrl_request_gpio、pinctrl_gpio_requeset)。而针对gpio与pinctrl,存在gpio引脚index与pinctrl pin index的转换工作,因此定义数据结构描述gpio引脚与pinctrl 引脚的转换;主要数据结构为struct gpio_pin_range、pinctrl_gpio_range,主要也就是gpio控制器的gpio base、num_gpio、pinctrl pin引脚的base index等信息。只需要在gpio_chip注册时,将struct gpio_pin_range类型的变量,添加到struct pinctrl_dev的成员变量链表gpio_ranges上即可。
本篇文章我们的虚拟gpio控制器驱动(该驱动是在之前《gpio专栏》中实现的,此处不再细述),增
加实现了该功能。主要是在虚拟gpio控制器驱动对应platform driver probe中增加针对gpio range的注册代码,实现如下:
执行完成以上工作后,即完成soc pinctrl dev、pinctrl map的注册,而我们的pinctrl device对应的platform device路径为/sys/devices/platform/virt_pinctrl_dev,我们可以在该目录下查看引脚复用寄存器的设置值。如下:
执行完成insmod后,查看寄存器的值
已经完成引脚复用的配置。
测试验证下:
我们注册的gpio的base index为256,我们会发现能够设置gpio0(即256),但是不能设置gpio6(262),那是引脚6我们已经用作spi0 clk了。下面我们注销spi 0 controller:
注销spi0后,就可以使用gpio6了,那是在spi controller注销时,会调用pin_free释放该引脚,因此就可以将pin6作为gpio使用了。
以上就是本章的主要内容,我们实现了一个虚拟的pinctrl device驱动,且借助虚拟的spi控制器驱动、虚拟的gpio控制器驱动、sysfs的属性文件,完成了完整的模拟工作。希望对学习pinctrl子系统的童鞋有所帮助。
本章所实现的所有测试代码链接如下:https://gitee.com/jerry_chg/virt_pinctrl_dev.git
(代码已在ubuntu18.04上完成验证)