以下讲的pinctrl子系统框架包括3点,1. pinctrl子系统简介;2.pinctrl子系统的注册;3. 设备驱动匹配时,probe执行前的管脚自动配置。写博客不易,如若转载,请注明出处。
一、pinctrl子系统简介
在arm的各种soc芯片中,往往可以看到1个pin引脚,既可以作为GPIO,也可以作为spi、i2c、uart总线中的1根引脚,即该引脚是可以复用为不同功能的引脚。Linux内核引入的pinctrl子系统,目的正是为了统一各soc厂商的pin脚管理。
Pinctrl子系统提供主要功能有:
(1)管理系统中所有可控的pin,在pinctrl子系统注册时,标识这些pin。
(2)管理这些pin的复用(mux)。通过pin function、pin group的搭配选择来管理一组的pin,定义该组pin为特定的功能。
(3)配置每组pin内每个pin的特性。例如配置pin的上拉、下拉电阻,配置pin的driver strength等。
二、pinctrl子系统的注册
以pfc-r8a7791(见Core.c (drivers\pinctrl\sh-pfc))为例。从入口postcore_initcall(sh_pfc_init);分析,使用postcore_initcall而不是module_init,是因为pinctrl的注册要在其他驱动注册之前完成,各设备(如SOC片内的各个控制器)使用的引脚功能依赖于pinctrl子系统提供的引脚复用服务。其他驱动的注册,设备驱动匹配后执行probe前,pinctrl子系统会自动配置设备需要的引脚复用。
这里注册的是一个平台驱动,看.of_match_table = of_match_ptr(sh_pfc_of_table),
static const struct of_device_id sh_pfc_of_table[] = {
。。。
{
.compatible = "renesas,pfc-r8a7791",
.data = &r8a7791_pinmux_info,
},
。。。
}
MODULE_DEVICE_TABLE(of, sh_pfc_of_table);
见 设备树r8a7791.dtsi 里面的结点:
pfc: pfc@e6060000 {
compatible = "renesas,pfc-r8a7791";
reg = <0 0xe6060000 0 0x250>;
#gpio-range-cells = <3>;
};
得知以上设备驱动将匹配成功,匹配后,执行sh_pfc_probe,进入该函数
static int sh_pfc_probe(struct platform_device *pdev)
{
。。。
ret = sh_pfc_register_pinctrl(pfc);
if (unlikely(ret != 0))
goto error;
。。。
return 0;
。。
}
一开始是资源的获取、准备,继续进入sh_pfc_register_pinctrl:
int sh_pfc_register_pinctrl(struct sh_pfc *pfc)
{
struct sh_pfc_pinctrl *pmx;
int ret;
pmx = devm_kzalloc(pfc->dev, sizeof(*pmx), GFP_KERNEL);
if (unlikely(!pmx))
return -ENOMEM;
pmx->pfc = pfc;
pfc->pinctrl = pmx;
ret = sh_pfc_map_pins(pfc, pmx);
if (ret < 0)
return ret;
pmx->pctl_desc.name = DRV_NAME;
pmx->pctl_desc.owner = THIS_MODULE;
pmx->pctl_desc.pctlops = &sh_pfc_pinctrl_ops;
pmx->pctl_desc.pmxops = &sh_pfc_pinmux_ops;
pmx->pctl_desc.confops = &sh_pfc_pinconf_ops;
pmx->pctl_desc.pins = pmx->pins;
pmx->pctl_desc.npins = pfc->info->nr_pins;
pmx->pctl = pinctrl_register(&pmx->pctl_desc, pfc->dev, pmx);
if (pmx->pctl == NULL)
return -EINVAL;
return 0;
}
这里可以看到,pinctrl_register前所进行的准备:struct pinctrl_desc中pctlops、pmxops、confops各个pin相关操作函数接口的实现,以及pins、npins 系统所有可控pin的前期准备。进入pinctrl_register函数:
struct pinctrl_dev *pinctrl_register(struct pinctrl_desc *pctldesc,
struct device *dev, void *driver_data)
{
struct pinctrl_dev *pctldev;
int ret;
。。。
pctldev = kzalloc(sizeof(*pctldev), GFP_KERNEL);
。。。
/* Initialize pin control device struct */
pctldev->owner = pctldesc->owner;
pctldev->desc = pctldesc;
pctldev->driver_data = driver_data;
INIT_RADIX_TREE(&pctldev->pin_desc_tree, GFP_KERNEL);
INIT_LIST_HEAD(&pctldev->gpio_ranges);
pctldev->dev = dev;
mutex_init(&pctldev->mutex);
。。。
/* Register all the pins */
dev_dbg(dev, "try to register %d pins ...\n", pctldesc->npins);
ret = pinctrl_register_pins(pctldev, pctldesc->pins, pctldesc->npins); ----为pins数组中的每个pin分配struct pin_desc,并进行赋值,struct pin_desc是pinctrl子系统用来进行每个pin管理的最小单元
。。。
mutex_lock(&pinctrldev_list_mutex);
list_add_tail(&pctldev->node, &pinctrldev_list);
mutex_unlock(&pinctrldev_list_mutex);
pctldev->p = pinctrl_get(pctldev->dev); ----重要函数
if (!IS_ERR(pctldev->p)) {
pctldev->hog_default =
pinctrl_lookup_state(pctldev->p, PINCTRL_STATE_DEFAULT); ----选dev结点状态为默认的pin
。。。
pinctrl_select_state(pctldev->p,
pctldev->hog_default)) ----进行dev结点默认状态pin引脚功能的使能
。。。
}
pctldev->hog_sleep =
pinctrl_lookup_state(pctldev->p,
PINCTRL_STATE_SLEEP);
。。。
}
pinctrl_init_device_debugfs(pctldev);
return pctldev;
。。。
}
分配一个struct pinctrl_dev并初始化,一般系统只做一次pinctrl_register,因此struct pinctrl_dev在系统中一般只有一个。pinctrl_register_pins(pctldev, pctldesc->pins, pctldesc->npins);会为pins数组中的每个pin分配独立的struct pin_desc,并进行赋值。struct pin_desc是pinctrl子系统用来管理每个pin的最小单元。继续看pinctrl_get函数:
struct pinctrl *pinctrl_get(struct device *dev)
{
struct pinctrl *p;
if (WARN_ON(!dev))
return ERR_PTR(-EINVAL);
/*
* See if somebody else (such as the device core) has already
* obtained a handle to the pinctrl for this device. In that case,
* return another pointer to it.
*/
p = find_pinctrl(dev); ----首次调用,这里p==NULL
if (p != NULL) {
dev_dbg(dev, "obtain a copy of previously claimed pinctrl\n");
kref_get(&p->users);
return p;
}
return create_pinctrl(dev);
}
进入create_pinctrl函数:
static struct pinctrl *create_pinctrl(struct device *dev)
{
struct pinctrl *p;
const char *devname;
struct pinctrl_maps *maps_node;
int i;
struct pinctrl_map const *map;
int ret;
/*
* create the state cookie holder struct pinctrl for each
* mapping, this is what consumers will get when requesting
* a pin control handle with pinctrl_get()
*/
p = kzalloc(sizeof(*p), GFP_KERNEL); ----对于每个设备节点,都会分配一个struct pinctrl。可以在dd.c中really_probe内找到pinctrl_bind_pins,里面有devm_pinctrl_get,由此可知对于每个设备节点,都会分配一个struct pinctrl
if (p == NULL) {
dev_err(dev, "failed to alloc struct pinctrl\n");
return ERR_PTR(-ENOMEM);
}
p->dev = dev;
INIT_LIST_HEAD(&p->states);
INIT_LIST_HEAD(&p->dt_maps);
ret = pinctrl_dt_to_map(p); ----这里用来获取dtb节点中pinctrl-0,pinctrl-1。。。指向的pinctrl-dev子节点的function、group信息,构建dt_maps链表
if (ret < 0) {
kfree(p);
return ERR_PTR(ret);
}
devname = dev_name(dev);
mutex_lock(&pinctrl_maps_mutex);
/* Iterate over the pin control maps to locate the right ones */
for_each_maps(maps_node, i, map) {
/* Map must be for this device */
if (strcmp(map->dev_name, devname))
continue;
ret = add_setting(p, map); ----创建struct pinctrl_state(有3种state:“default”、“sleep”、“idle”)并加入struct pinctrl的states链表中,通过对构建好的dt_maps链表进行分析,会相应的以链表的形式挂载在这3种state中。以后的pin操作就是用state的状态来统一控制的
/*
* At this point the adding of a setting may:
*
* - Defer, if the pinctrl device is not yet available
* - Fail, if the pinctrl device is not yet available,
* AND the setting is a hog. We cannot defer that, since
* the hog will kick in immediately after the device
* is registered.
*
* If the error returned was not -EPROBE_DEFER then we
* accumulate the errors to see if we end up with
* an -EPROBE_DEFER later, as that is the worst case.
*/
if (ret == -EPROBE_DEFER) {
pinctrl_free(p, false);
mutex_unlock(&pinctrl_maps_mutex);
return ERR_PTR(ret);
}
}
mutex_unlock(&pinctrl_maps_mutex);
if (ret < 0) {
/* If some other error than deferral occured, return here */
pinctrl_free(p, false);
return ERR_PTR(ret);
}
kref_init(&p->users);
/* Add the pinctrl handle to the global list */
mutex_lock(&pinctrl_list_mutex);
list_add_tail(&p->node, &pinctrl_list);
mutex_unlock(&pinctrl_list_mutex);
return p;
}
里面实在庞大,不再继续追踪下去了~_~
贴几张关系图:
1. pinctrl子系统概要图
2. pinctrl子系统数据结构图1
3. pinctrl子系统数据结构图2
4. GPIO子系统(通过gpio_pin_range关联)
三、设备驱动匹配时,probe执行前的管脚自动配置
pinctrl子系统有一个重要的功能,在设备树中填好引脚复用信息后,它能够在设备驱动匹配时,自动地给你配置好设备的引脚,而不需要你在驱动的代码中为设备(如SOC的片内控制器)去配置它所需要的引脚。
设备驱动匹配时,将执行really_probe函数(dd.c (drivers\base)),里面的pinctrl_bind_pins即去自动配置好设备的引脚。执行完之后,再执行probe。看pinctrl.c (drivers\base)的pinctrl_bind_pins函数:
int pinctrl_bind_pins(struct device *dev)
{
int ret;
dev->pins = devm_kzalloc(dev, sizeof(*(dev->pins)), GFP_KERNEL);
。。。
dev->pins->p = devm_pinctrl_get(dev);
。。。
dev->pins->default_state = pinctrl_lookup_state(dev->pins->p,
PINCTRL_STATE_DEFAULT); ----查找“default”的默认state,赋给default_state
。。。
ret = pinctrl_select_state(dev->pins->p, dev->pins->default_state); ----选中、使能“default”状态的引脚
。。。
#ifdef CONFIG_PM ----电源管理相关
。。。
dev->pins->sleep_state = pinctrl_lookup_state(dev->pins->p,
PINCTRL_STATE_SLEEP); ----查找“sleep”的state,赋给sleep_state
if (IS_ERR(dev->pins->sleep_state))
/* Not supplying this state is perfectly legal */
dev_dbg(dev, "no sleep pinctrl state\n");
dev->pins->idle_state = pinctrl_lookup_state(dev->pins->p,
PINCTRL_STATE_IDLE); ----查找“idle”的state,赋给idle_state
if (IS_ERR(dev->pins->idle_state))
/* Not supplying this state is perfectly legal */
dev_dbg(dev, "no idle pinctrl state\n");
#endif
return 0;
。。。
}