程序框图:
pin state->pin group,一对多
pin group->pin,一对多
存储外设所有state下pin group的配置信息
pinctrl_enable()->pinctrl_claim_hogs()
create_pinctrl
----------------------------------------------第一部分-------------------------------------
pinctrl_dt_to_map()
for (state = 0; ; state++):查找外设所有pin group的状态
for (config = 0; config < size; config++):查找状态的所有引脚组
------------------------------第二部分-------------------------------------
dt_to_map_one_config
创建一个pinctrl_map,负责初始化引脚组的所有引脚复用
创建多个pinctrl_map,每个pinctrl_map负责配置引脚中的一个引脚属性
----------------------------------------------第三部分-------------------------------------
drivers/pinctrl/core.c
int pinctrl_enable(struct pinctrl_dev *pctldev)
{
int error;
error = pinctrl_claim_hogs(pctldev);
...
//将pctldev加入全局链表
list_add_tail(&pctldev->node, &pinctrldev_list);
...
return 0;
}
drivers/pinctrl/core.c
static int pinctrl_claim_hogs(struct pinctrl_dev *pctldev)
{
pctldev->p = create_pinctrl(pctldev->dev, pctldev);
//第四部分
pctldev->hog_default =
pinctrl_lookup_state(pctldev->p, PINCTRL_STATE_DEFAULT);
if (IS_ERR(pctldev->hog_default)) {
dev_dbg(pctldev->dev,
"failed to lookup the default state\n");
} else {
//设置为default状态
if (pinctrl_select_state(pctldev->p,
pctldev->hog_default))
dev_err(pctldev->dev,
"failed to select default state\n");
}
...
pctldev->hog_sleep =
pinctrl_lookup_state(pctldev->p,
...
}
drivers/pinctrl/core.c
参数:create_pinctrl(pctldev->dev, pctldev);
static struct pinctrl *create_pinctrl(struct device *dev,
struct pinctrl_dev *pctldev)
{
struct pinctrl *p;
const char *devname;
struct pinctrl_maps *maps_node;
int i;
const struct pinctrl_map *map;
int ret;
p = kzalloc(sizeof(*p), GFP_KERNEL);
...
p->dev = dev;
INIT_LIST_HEAD(&p->states);
INIT_LIST_HEAD(&p->dt_maps);
//第一部分
ret = pinctrl_dt_to_map(p, pctldev);
devname = dev_name(dev);
...
for_each_maps(maps_node, i, map) {
/* Map must be for this device */
if (strcmp(map->dev_name, devname))
continue;
if (pctldev &&
strcmp(dev_name(pctldev->dev), map->ctrl_dev_name))
continue;
//第三部分
ret = add_setting(p, pctldev, map);
...
}
...
list_add_tail(&p->node, &pinctrl_list);
...
}
drivers/pinctrl/devicetree.c
int pinctrl_dt_to_map(struct pinctrl *p, struct pinctrl_dev *pctldev)
{
/*iomux节点*/
struct device_node *np = p->dev->of_node;
int state, ret;
char *propname;
struct property *prop;
const char *statename;
const __be32 *list;
int size, config;
phandle phandle;
struct device_node *np_config;
...
for (state = 0; ; state++) {
propname = kasprintf(GFP_KERNEL, "pinctrl-%d", state);
//获取到属性的名字之后,查找它对应的属性
prop = of_find_property(np, propname, &size);
kfree(propname);
if (!prop) {
if (state == 0) {
of_node_put(np);
return -ENODEV;
}
break;
}
list = prop->value;
//获取当前state中的group数量
size /= sizeof(*list);
ret = of_property_read_string_index(np, "pinctrl-names",state, &statename);
...
for (config = 0; config < size; config++) {
//句柄
phandle = be32_to_cpup(list++);
//根据句柄查找子节点
np_config = of_find_node_by_phandle(phandle);
ret = dt_to_map_one_config(p, pctldev, statename,
np_config);
...
}
...
}
drivers/pinctrl/devicetree.c
dt_to_map_one_config(p, pctldev, statename,np_config);
static int dt_to_map_one_config(struct pinctrl *p,
struct pinctrl_dev *hog_pctldev,
const char *statename,
struct device_node *np_config)
{
struct pinctrl_dev *pctldev = NULL;
struct device_node *np_pctldev;
const struct pinctrl_ops *ops;
int ret;
struct pinctrl_map *map;
unsigned num_maps;
bool allow_default = false;
np_pctldev = of_node_get(np_config);
for (;;) {
/*iomuxc节点*/
np_pctldev = of_get_next_parent(np_pctldev);
if (hog_pctldev && (np_pctldev == p->dev->of_node)) {
pctldev = hog_pctldev;
break;
}
pctldev = get_pinctrl_dev_from_of_node(np_pctldev);
if (pctldev)
break;
}
...
//imx_pctrl_ops
ops = pctldev->desc->pctlops;
...
//imx_dt_node_to_map
ret = ops->dt_node_to_map(pctldev, np_config, &map, &num_maps);
...
return dt_remember_or_free_map(p, statename, pctldev, map, num_maps);
}
include/linux/of.h
static inline struct device_node *of_node_get(struct device_node *node)
{
return node;
}