pinctrl&gpio介绍
目的: 实现IO口功能设置的软硬件分离
pinctrl:通过设备树节点,记录不同板级硬件信息; Pinctrl 遵循的是platform 框架实现实现设备总线。
gpio: 通过一些列的API接口,读取设备树中pinctrl节点的硬件信息,设置相应的引脚功能。
pinctrl文件位置:
Linux文件结构的drivers/pinctrl文件夹下,有不同公司的pinctrl文件 ,以STM为例:
pinctrl中的信息分两类:{
控制文件 pinctrl32-stm32.c pinctrl-stm32.h
板级信息描述文件:如 pinctrl-stm32mp157.c 文件主要记录了IO信息,并注册到platform总线的接口 stm32mp157_pinctrl_init
}
pinctrl-stm32mp157.c 文件介绍:
结构体介绍:
stm32_desc_pin 管脚信息记录结构体
stm32_pinctrl_match_data 节点描述记录,将管脚信息集合,
of_device_id 根据 compatible 信息与设备树中的compatible 进行匹配,查询引脚的硬件信息
platform_driver 注册到 platform 总线上。
接口介绍:
stm32mp157_pinctrl_init 将 stm32mp157_pinctrl_driver (platform_driver类型) 挂载到platform总线上
每个 IO 信息记录表:方便在IO复用时进行查询对照;该文件分两个结构体数组进行记录:stm32mp157_pins(stm32_desc_pin)、stm32mp157_z_pins(stm32_desc_pin )
信息表汇成一个集合:stm32mp157_pctrl_match ( of_device_id)
设备树pinctrl 信息描述:
公共基础信息: stm32mp151.dtsi 中记录了pinctrl节点,包含了所有IO的端口复用信息(每个端口都能有哪些复用功能),compatible信息等
功能信息节点描述:stm32mp15-pinctrl.dtsi 描述了每个功能时,都哪些管脚可以进行复用设置。(pinctrl控制节点,加入pinctrl总线)同时可以自定义添加要使用的控制节点。
上面两个都是设备厂商描述好的。
应用时设置(设备树节点) stm32mp157d-atk.dts 这个文件是实际应用是添加的一个设备树文件,在 / 跟节点下创建要使用的节点,在该节点中描述要使用的IO复用信息.
eg:
//添加一个led节点 gpioled { //可以通过节点名称获取这个节点的信息 compatible = "alientek,led"; //通过compatible 信息总线可以进行match匹配设备和驱动 led-gpio = <&gpioi 0 GPIO_ACTIVE_LOW>; //设置端口PI0 为GPIO功能 默认低电平 led-gpio 这个名称可以进行端口设置 status = "okay"; };
gpio系统:
对驱动层提供了一套关于IO引脚操作的API函数。
int gpio_request(unsigned gpio, const char *label)//label 是给这个GPIO 重新设置个名称 void gpio_free(unsigned gpio) int gpio_direction_input(unsigned gpio) int gpio_direction_output(unsigned gpio, int value) //获取某个 GPIO 的值(0 或 1),此函数是个宏 #define gpio_get_value __gpio_get_value int __gpio_get_value(unsigned gpio) //设置某个 GPIO 的值,此函数是个宏,定义如 #define gpio_set_value __gpio_set_value void __gpio_set_value(unsigned gpio, int value)
与gpio相关of 函数,读取设备树信息
/*获取设备树某个属性里面定义了几个 GPIO 信息,要注意的 是空的 GPIO 信息也会被统计到*/ int of_gpio_named_count(struct device_node *np, const char *propname) //统计gpio这个属性的IO数量 int of_gpio_count(struct device_node *np) /*获取 GPIO 编号*/ int of_get_named_gpio(struct device_node *np,const char *propname,int index) //eg 设备树信息参考上面的设置 /*获取设备节点,设备树中的节点名称是 gpioled*/ gpioled.nd = of_find_node_by_path("/gpioled"); /*获取设备树中的 gpio 属性,得到 LED 所使用的 LED 编号 led-gpio 这个名称是设备树中IO信息设置名称*/ gpioled.led_gpio = of_get_named_gpio(gpioled.nd, "led-gpio", 0); /*申请 gpioled.led_gpio 这个节点的IO口为 GPIO*/ ret = gpio_request(gpioled.led_gpio, "LED-GPIO"); /*设置这个节点的IO口为输出方向*/ ret = gpio_direction_output(gpioled.led_gpio, 1);
流程梳理:
1. stm32mp15-pinctrl.dtsi &pinctrl 中设置相应的节点,添加 pin 属性
2. 设备树中添加设备节点,这个节点会记录到IO的设置;/proc/device-tree 下会出现相应的设备树节点信息。
3. 通过of_gpio相关函数读取设备树的信息。