概述
1. 前言
按理说,kernel中gpio subsystem和pinctrl subsystem的关系应该非常清楚:
pinctrl subsystem管理系统的所有管脚,GPIO是这些管脚的用途之一,因此gpio subsystem应该是pinctrl subsystem的client(也可叫做backend、consumer),基于pinctrl subsystem提供的功能,处理GPIO有关的逻辑。
不过,实际情况却不是这么简单,它们之间有着较为紧密的耦合(看一看kernel中pinctrl和gpio相关的实现就知道了)。本文将对这种耦合进行一个简单的分析,解释为什么要这样设计。
2. Why
首先,无论硬件的架构如何(可参考[2]中“五、和GPIO subsystem交互”),从逻辑上讲,有一点是很明确的(这一点和linuxer同学在[2]中的说明有出入,待讨论):
gpio subsystem永远是pinctrl的backend(或client,或consumer)。
基于这一点,规范的做法,任何一个gpio chip(相关的概念可参考本站GPIO子系统的文章[5]),在使用GPIO的时候(通常是gpio subsystem的consumer申请GPIO资源的时候),都需要向系统的pinctrl subsystem申请管脚,并将管脚配置为GPIO功能。
思路是简单、直接的,但实际操作起来,却有点棘手,下面以一个最简单的例子说明:
假设某一个gpio chip只包括2个gpio,这两个gpio分别和uart进行功能复用。
如果这两个管脚是同时控制的,要么是gpio,要么是uart,就很好处理了,按照pinctrl subsystem的精神,抽象出两个function:gpio和uart,gpio chip在使用gpio功能的时候,调用pinctrl set state,将它们切换为gpio即可。
但是,如果这两个gpio可以分开控制(很多硬件都是这样的设计的),麻烦就出现了,每个gpio要单独抽象为一个function,因此我们可以抽象出3个function:gpio1、gpio2和uart。
然后考虑一下一个包含32个gpio的chip(一般硬件的gpio bank都是32个),如果它们都可以单独控制,则会出现32个function。而系统又不止有一个chip,灾难就发生了,我们的device tree文件将会被一坨坨的gpio functions撑爆!
规范是我们追求的目标,但有限度,不能让上面的事情发生,怎么办呢?在pinctrl subsystem的标准框架上打个洞,只要碰到这种情况,直接就走后门就是了。
3. pinctrl中和gpio有关的后门
后门是什么呢?其实很简单,参考下面的API:
static inline int pinctrl_request_gpio(unsigned gpio) ; static inline void pinctrl_free_gpio(unsigned gpio) ; static inline int pinctrl_gpio_direction_input(unsigned gpio); static inline int pinctrl_gpio_direction_output(unsigned gpio); |
当gpio driver需要使用某个管脚的时候,直接调用pinctrl_request_gpio,向pinctrl subsystem申请。
pinctrl subsystem会维护一个gpio number到pin number的map,将gpio subsystem传来的gpio number转换为pin number之后,调用struct pinmux_ops中有关的回调函数即可:
struct pinmux_ops {
...
int (*gpio_request_enable) (struct pinctrl_dev *pctldev,
struct pinctrl_gpio_range *range,
unsigned offset);
void (*gpio_disable_free) (struct pinctrl_dev *pctldev,
struct pinctrl_gpio_range *range,
unsigned offset);
int (*gpio_set_direction) (struct pinctrl_dev *pctldev,
struct pinctrl_gpio_range *range,
unsigned offset,
bool input);
};对gpio driver来说,要做的事情就是提供gpio number到pin number的map。
而pinctrl subsystem呢,做自己分内的事情即可:管理系统的pin资源,并根据gpio subsystem的请求,将某些pin设置为GPIO功能。
4. gpio range----gpio number到pin number的map
那么,怎么提供gpio number和pin number的map呢?是通过一个名称为gpio range的数据结构(pinctrl subsystem提供的),如下:
/* include/linux/pinctrl/pinctrl.h */ |
该数据结构很容易理解,总结来说,就是:gpio controller(gc)中的gpio(base)到gpio(base + npins - 1),和pin controller中的pin(pin_base)到pin(pin_base + npins - 1)是一一对应的。
有了这个对应关系之后,pinctrl subsystem就可以将任意一个gpio controller中的gpio number转换为相应的pin controller中的pin number。
最后,gpio subsystem为了方便gpio driver的开发,提供了一种简单的、可以通过device tree提供gpio range信息的方法,总结如下:
1)gpio range的dts格式示例(可参考[6]中的介绍)
qe_pio_e: gpio-controller@1460 {
#gpio-cells = <2>;
compatible = "fsl,qe-pario-bank-e", "fsl,qe-pario-bank";
reg = <0x1460 0x18="">;
gpio-controller;
gpio-ranges = <&pinctrl1 0 20 10>, <&pinctrl2 10 50 20>;
};
上面dts节点中的gpio-ranges关键字指定了两个gpio range:gpio controller(qe_pio_e)中的gpio0~9和pinctrl1中的pin20~29对应;gpio controller(qe_pio_e)中的gpio10~29和pinctrl2中的pin50~69对应。
2)gpio range dts node的解析
解析的过程如下(具体不再详细介绍了,大家可参考相应的代码):
devm_gpiochip_add_data(drivers/gpio/gpiolib.c)
gpiochip_add_data
of_gpiochip_add(drivers/gpio/gpiolib-of.c)
of_gpiochip_add_pin_range
gpiochip_add_pin_range(drivers/gpio/gpiolib.c)
pinctrl_find_and_add_gpio_range(drivers/pinctrl/core.c)
pinctrl_add_gpio_range
以上过程的结果,就是在相应的pin controller device的数据结构中生成了一个gpio range的链表,如下:
struct pinctrl_dev {
struct list_head node;
struct pinctrl_desc *desc;
struct radix_tree_root pin_desc_tree;
struct list_head gpio_ranges;
...
};
3)gpio range的使用
当gpio driver需要使用某一个gpio的时候,可以在gpiochip的request函数中,调用pinctrl core提供的pinctrl_request_gpio接口(参数是gpio编号),然后pinctrl core会查寻gpio ranges链表,将gpio编号转换成pin编号,然后调用pinctrl的相应接口(参数是pin编号),申请该pin的使用。
至此,gpio subsystem和pinctrl subsystem的耦合,就真相大白了。
转载地址:http://www.wowotech.net/gpio_subsystem/pinctrl-and-gpio.html
最后
以上就是爱笑未来为你收集整理的linux内核中的GPIO系统之(5):gpio subsysem和pinctrl subsystem之间的耦合的全部内容,希望文章能够帮你解决linux内核中的GPIO系统之(5):gpio subsysem和pinctrl subsystem之间的耦合所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复