pin state:pinctrl-names的真相
pinctrl(三)讲解的是将iomuxc当中的所有pin信息解析并存储起来。而每个外设使用一组或多组pin,每个pin state对应一组或多组pin group,根据pin state存储pin group信息。
iomuxc节点
- 存储全部所需的引脚配置信息
- "虚拟"外设
- 设置pin state数量和类型
- 设置状态对应的pin group
pin state->pin group,一对多
pin group->pin,一对多
pinctl_map
存储外设所有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负责配置引脚中的一个引脚属性
-
-
-
-
----------------------------------------------第三部分-------------------------------------
- add_setting
-
pinctrl_enable()函数
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;
}
pinctrl_claim_hogs()函数
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,
...
}
create_pinctrl()函数
drivers/pinctrl/core.c
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; //iomuxc设备device结构体
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);
...
}
pinctrl_dt_to_map()函数
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;//iomuxc节点的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);//这里就是pinctrl-0、1...写入到propname当中
prop = of_find_property(np, propname, &size);//根据属性名字查找对应属性,同时将属性的引脚组的总大小记录到size当中
kfree(propname);
if (!prop) {//如果属性都被找完,就会break结束for循环的执行
if (state == 0) {
of_node_put(np);
return -ENODEV;
}
break;
}
list = prop->value;//首先取出了value值,value值就是各个引脚组子节点的地址即pinctrl-0 = <&pinctrl_hog_1>;中的pinctrl_hog_1也称作句柄
//获取当前state中的group数量,用总大小除以一个引脚组的大小获取group数量
size /= sizeof(*list);
ret = of_property_read_string_index(np, "pinctrl-names",state, &statename);//读取pinctrl-name当中的状态值,是根据state大小读取的,pinctrl-names = "default","init","sleep";比如state为0的时候读取到statename的值是default
...
for (config = 0; config < size; config++) {
//句柄
phandle = be32_to_cpup(list++);
//根据句柄查找子节点
//根据句柄地址找到对应grp子节点此时np_config指向pinctrl_uart1
np_config = of_find_node_by_phandle(phandle);
ret = dt_to_map_one_config(p, pctldev, statename,
np_config);
...
}
...
}
dt_to_map_one_config()函数
drivers/pinctrl/devicetree.c
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);//将np_config赋值给了np_pctldev,即grp子节点
for (;;) {
/*iomuxc节点*/
np_pctldev = of_get_next_parent(np_pctldev);//获取子节点的父节点,即iomuxc节点
if (hog_pctldev && (np_pctldev == p->dev->of_node)) {//这个条件肯定是成立的
pctldev = hog_pctldev;//pctldev指向pinctrl_dev节点
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);
}
pinctl_map:引脚三千,只取一瓢
pinctrl_map数组//存放引脚组所有引脚的配置信息
-
pin group配置信息
-
pinctrl_map[0]:配置pin group的所有引脚复用
-
pinctrl_map[1~n]:配置pin group的每个引脚的属性
-
imx_dt_node_to_map()函数
drivers/pinctrl/freescale/pinctrl-imx.c
static int imx_dt_node_to_map(struct pinctrl_dev *pctldev,
struct device_node *np,//group子节点
struct pinctrl_map **map//构造一个map数组
, unsigned *num_maps)
{
struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev);
//从pinctrl_dev中获取imx_pinctrl
const struct imx_pinctrl_soc_info *info = ipctl->info;
const struct group_desc *grp;
struct pinctrl_map *new_map;
struct device_node *parent;
int map_num = 1;
int i, j;
//通过group的name查找pinctrl基数树当中的group_desc
grp = imx_pinctrl_find_group_by_name(pctldev, np->name);
if (info->flags & IMX8_USE_SCU) {
map_num += grp->num_pins;
} else {
for (i = 0; i < grp->num_pins; i++) {//遍历grp当中的所有pin取出对应的pin
struct imx_pin *pin = &((struct imx_pin *)(grp->data))[i];
if (!(pin->pin_conf.pin_memmap.config & IMX_NO_PAD_CTL))
map_num++;
//条件一定成立,因此map_num的值就等于所有pin的数量了
}
}
new_map = kmalloc_array(map_num, sizeof(struct pinctrl_map),
GFP_KERNEL);
*map = new_map;
*num_maps = map_num;
/*iomuxc节点*/
parent = of_get_parent(np);//获取节点的父节点
...
//第一个map存储复用寄存器
new_map[0].type = PIN_MAP_TYPE_MUX_GROUP;
new_map[0].data.mux.function = parent->name;//将function赋值为parent的名字
new_map[0].data.mux.group = np->name;//将group赋值为子节点group的名字
..
new_map++;//new_map指向第一个元素了
for (i = j = 0; i < grp->num_pins; i++) {
struct imx_pin *pin = &((struct imx_pin *)(grp->data))[i];
if (info->flags & IMX8_USE_SCU) {
new_map[j].type = PIN_MAP_TYPE_CONFIGS_PIN;
new_map[j].data.configs.group_or_pin =
pin_get_name(pctldev, pin->pin);
new_map[j].data.configs.configs =
(unsigned long *)&pin->pin_conf.pin_scu;
new_map[j].data.configs.num_configs = 2;
j++;
} else if (!(pin->pin_conf.pin_memmap.config & IMX_NO_PAD_CTL)) {
new_map[j].type = PIN_MAP_TYPE_CONFIGS_PIN;
new_map[j].data.configs.group_or_pin =
pin_get_name(pctldev, pin->pin);
//返回引脚对应的名字
new_map[j].data.configs.configs =
&pin->pin_conf.pin_memmap.config;//保存了mux_reg当中的属性值
new_map[j].data.configs.num_configs = 1;
j++;
}
}
...
}
dt_remember_or_free_map()函数
drivers/pinctrl/devicetree.c
static int dt_remember_or_free_map(struct pinctrl *p, const char *statename,struct pinctrl_dev *pctldev,struct pinctrl_map *map, unsigned num_maps)
{
int i;
struct pinctrl_dt_map *dt_map;
/* Initialize common mapping table entry fields */
for (i = 0; i < num_maps; i++) {
map[i].dev_name = dev_name(p->dev);
map[i].name = statename;//芯片引脚状态比如default
if (pctldev)
map[i].ctrl_dev_name = dev_name(pctldev->dev);
}
/* Remember the converted mapping table entries */
dt_map = kzalloc(sizeof(*dt_map), GFP_KERNEL);
dt_map->pctldev = pctldev;
dt_map->map = map;
dt_map->num_maps = num_maps; //group当中pin的数目
list_add_tail(&dt_map->node, &p->dt_maps);//将dt_maps加入到dt_map->node
return pinctrl_register_map(map, num_maps, false);
}
pinctrl_register_map()函数
drivers/pinctrl/core.c
int pinctrl_register_map(const struct pinctrl_map *maps, unsigned num_maps,
bool dup)
{
int i, ret;
struct pinctrl_maps *maps_node;
for (i = 0; i < num_maps; i++) {
switch (maps[i].type) {
case PIN_MAP_TYPE_DUMMY_STATE:
break;
case PIN_MAP_TYPE_MUX_GROUP://第0个map会在这里执行
//判断data.mux.function是否为空,不为空ret = 0
ret = pinmux_validate_map(&maps[i], i);
if (ret < 0)
return ret;
break;
case PIN_MAP_TYPE_CONFIGS_PIN://后面的map会执行这里之后的
case PIN_MAP_TYPE_CONFIGS_GROUP:
//判断data.configs中的参数是否为空,不为空ret = 0
ret = pinconf_validate_map(&maps[i], i);
if (ret < 0)
return ret;
break;
default:
pr_err("failed to register map %s (%d): invalid type given\n",
maps[i].name, i);
return -EINVAL;
}
}
maps_node = kzalloc(sizeof(*maps_node), GFP_KERNEL);
maps_node->num_maps = num_maps;
if (dup) {
maps_node->maps = kmemdup(maps, sizeof(*maps) * num_maps,
GFP_KERNEL);
if (!maps_node->maps) {
kfree(maps_node);
return -ENOMEM;
}
} else {
maps_node->maps = maps;//指向pinctrl_map数组
}
...
list_add_tail(&maps_node->node, &pinctrl_maps);把这个节点加入到pinctrl_maps上面来
...
}
pinmux_validate_map()函数
drivers/pinctrl/pinmux.c
int pinmux_validate_map(const struct pinctrl_map *map, int i)
{
if (!map->data.mux.function) {
pr_err("failed to register map %s (%d): no function given\n",
map->name, i);
return -EINVAL;
}
return 0;
}
pinconf_validate_map()函数
drivers/pinctrl/pinmux.c
int pinconf_validate_map(const struct pinctrl_map *map, int i)
{
if (!map->data.configs.group_or_pin) {
pr_err("failed to register map %s (%d): no group/pin given\n",
map->name, i);
return -EINVAL;
}
if (!map->data.configs.num_configs ||
!map->data.configs.configs) {
pr_err("failed to register map %s (%d): no configs given\n",
map->name, i);
return -EINVAL;
}
//以上都不为空因此这个函数会return0
return 0;
}
pinctl_setting:如何统一管理pin state
pinctl_map
- 保存了所有pin state所需要的pin group信息
pinctl_setting
- 把pin group信息按pin state分类保存
目的
- pinctl_map->pinctl_setting
for_each_maps()宏
drivers/pinctrl/core.h
#define for_each_maps(_maps_node_, _i_, _map_) \
list_for_each_entry(_maps_node_, &pinctrl_maps, node) \
for (_i_ = 0, _map_ = &_maps_node_->maps[_i_]; \
_i_ < _maps_node_->num_maps; \
_i_++, _map_ = &_maps_node_->maps[_i_])
add_setting()函数
drivers/pinctrl/core.c
static int add_setting(struct pinctrl *p, struct pinctrl_dev *pctldev,
const struct pinctrl_map *map)
{
struct pinctrl_state *state;
struct pinctrl_setting *setting;
//遍历state链表,但是没有节点返回NULL
state = find_state(p, map->name);
if (!state)
//创建state节点
state = create_state(p, map->name);
...
setting = kzalloc(sizeof(*setting), GFP_KERNEL);
setting->type = map->type;//将map的type赋值给setting
if (pctldev)
setting->pctldev = pctldev;
else
setting->pctldev =
get_pinctrl_dev_from_devname(map->ctrl_dev_name);
setting->dev_name = map->dev_name;//iomuxc节点名
switch (map->type) {
case PIN_MAP_TYPE_MUX_GROUP://第一个setting执行这个
ret = pinmux_map_to_setting(map, setting);
break;
case PIN_MAP_TYPE_CONFIGS_PIN:
case PIN_MAP_TYPE_CONFIGS_GROUP://其他的setting执行这个
ret = pinconf_map_to_setting(map, setting);
break;
default:
ret = -EINVAL;
break;
}
...
list_add_tail(&setting->node, &state->settings);
//讲解点加入state->setting上
return 0;
}
create_state()函数
drivers/pinctrl/core.c
static struct pinctrl_state *create_state(struct pinctrl *p,const char *name)
{
struct pinctrl_state *state;//一个状态如defualt对应一个pinctrl_state结构体
state = kzalloc(sizeof(*state), GFP_KERNEL);
//分配内存
state->name = name;//这个name就是defualt
INIT_LIST_HEAD(&state->settings);//初始化setting链表节点
list_add_tail(&state->node, &p->states);//把节点加入到pinctrl的states上面去
return state;
}
pinmux_map_to_setting()函数
drivers/pinctrl/pinmux.c
int pinmux_map_to_setting(const struct pinctrl_map *map,struct pinctrl_setting *setting)
{
struct pinctrl_dev *pctldev = setting->pctldev;
//imx_pmx_ops
const struct pinmux_ops *pmxops = pctldev->desc->pmxops;
char const * const *groups;
unsigned num_groups;
int ret;
const char *group;
...
//对比function name是否相同,相同返回0
ret = pinmux_func_name_to_selector(pctldev, map->data.mux.function);
...
/*function的索引*/
setting->data.mux.func = ret;//0
//就是这个函数pinmux_generic_get_function_groups,这个函数就是去找function——desc结构体下的group_names和num_groups_names变量
//也就是group的名字数组和数量
ret = pmxops->get_function_groups(pctldev, setting->data.mux.func,&groups, &num_groups);
//判断map中的group名与func当中的group名是否匹配
if (map->data.mux.group) {
//group节点名
group = map->data.mux.group;
//判断两个变量指向的值是否相匹配
ret = match_string(groups, num_groups, group);
...
}
} else {
group = groups[0];
}
//在所有的group中查找与map中的group名相同的group编号并返回
ret = pinctrl_get_group_selector(pctldev, group);
...
setting->data.mux.group = ret;
...
}
pinmux_func_name_to_selector()函数
drivers/pinctrl/pinmux.c
static int pinmux_func_name_to_selector(struct pinctrl_dev *pctldev,
const char *function)
{
//imx_pmx_ops
const struct pinmux_ops *ops = pctldev->desc->pmxops;
//pinmux_generic_get_function_count
//这个函数返回pctldev->num_function成员变量,就是function的数量为1
unsigned nfuncs = ops->get_functions_count(pctldev);
unsigned selector = 0;
while (selector < nfuncs) {
//即pinmux_generic_get_function_name这个函数,获取function的name,返回iomuxc节点名
const char *fname = ops->get_function_name(pctldev, selector);
//这里都是imouxc节点名因此返回0
if (!strcmp(function, fname))
return selector;
selector++;
}
return -EINVAL;
}
pinctrl_get_group_selector()函数
drivers/pinctrl/core.c
int pinctrl_get_group_selector(struct pinctrl_dev *pctldev,const char *pin_group)
{
const struct pinctrl_ops *pctlops = pctldev->desc->pctlops;
//返回group节点的数量
unsigned ngroups = pctlops->get_groups_count(pctldev);
unsigned group_selector = 0;
//在所有的group中查找与map中的group名相同的group编号并返回
while (group_selector < ngroups) {
//从基数树中找到group,返回group的名字
const char *gname = pctlops->get_group_name(pctldev,
group_selector);
if (gname && !strcmp(gname, pin_group)) {
dev_dbg(pctldev->dev,
"found group selector %u for %s\n",
group_selector,
pin_group);
return group_selector;//进行对比,相同的话返回group编号
}
group_selector++;
}
dev_err(pctldev->dev, "does not have pin group %s\n",
pin_group);
return -EINVAL;
}
pinconf_map_to_setting()函数
int pinconf_map_to_setting(const struct pinctrl_map *map,
struct pinctrl_setting *setting)
{
struct pinctrl_dev *pctldev = setting->pctldev;
int pin;
switch (setting->type) {
case PIN_MAP_TYPE_CONFIGS_PIN:
pin = pin_get_from_name(pctldev,
map->data.configs.group_or_pin);
if (pin < 0) {
dev_err(pctldev->dev, "could not map pin config for \"%s\"",
map->data.configs.group_or_pin);
return pin;
}
setting->data.configs.group_or_pin = pin;
break;
...
}
setting->data.configs.num_configs = map->data.configs.num_configs;
setting->data.configs.configs = map->data.configs.configs;
...
}