pinctrl子系统分析(一)
pinctrl子系统分析(二)
pinctrl子系统分析(三)
这章讲解配置节点的解析以及pinctrl_state的pinctrl_setting增添,先来个图:
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;
......
//解析配置节点
ret = pinctrl_dt_to_map(p);
......
devname = dev_name(dev);
mutex_lock(&pinctrl_maps_mutex);
//遍历pinctrl_maps链表得到每项pinctrl_map
for_each_maps(maps_node, i, map) {
/*判断是不是该设备的pinctrl_map */
if (strcmp(map->dev_name, devname))
continue;
//增添pinctrl_setting
ret = add_setting(p, map);
......
}
mutex_unlock(&pinctrl_maps_mutex);
......
return p;
}
重点pinctrl_dt_to_map函数:
int pinctrl_dt_to_map(struct pinctrl *p)
{
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;
......
/* 举例子说明:
device {
pinctrl-names = "default", "idle";
pinctrl-0 = <&state_0_node_a>;
pinctrl-1 = <&state_1_node_a &state_1_node_b>;
};
*/
//设备可能有多种状态如default、idle,所以来个for循环
for (state = 0; ; state++) {
propname = kasprintf(GFP_KERNEL, "pinctrl-%d", state);
prop = of_find_property(np, propname, &size);
......
list = prop->value;
size /= sizeof(*list);
/* 获取设备的状态名,对于上面的例子,第一次循环获取的状态名为:"default",
第二次循环获取的状态名为:"idle",状态名保存在statename
*/
ret = of_property_read_string_index(np, "pinctrl-names",
state, &statename);
......
//每种状态可能有多个匹配节点,所以来个for循环
for (config = 0; config < size; config++) {
phandle = be32_to_cpup(list++);
/* 对于上面的例子,idle状态下有两个配置节点(state_1_node_a和state_1_node_b)
调用of_find_node_by_phandle函数找到配置节点对应的device_node
*/
np_config = of_find_node_by_phandle(phandle);
......
/* 解析配置节点 */
ret = dt_to_map_one_config(p, statename, np_config);
......
}
......
}
return 0;
......
}
解析单个配置节点dt_to_map_one_config:
static int dt_to_map_one_config(struct pinctrl *p, const char *statename,
struct device_node *np_config)
{
struct device_node *np_pctldev;
struct pinctrl_dev *pctldev;
const struct pinctrl_ops *ops;
int ret;
struct pinctrl_map *map;
unsigned num_maps;
/* 举例子说明:
device {
pinctrl-names = "default", "idle";
pinctrl-0 = <&state_0_node_a>;
pinctrl-1 = <&state_1_node_a &state_1_node_b>;
};
pincontroller {
//配置节点
state_0_node_a {
... //复用为哪个功能,引脚配置值等等
};
//配置节点
state_1_node_a {
...
};
//配置节点
state_1_node_b {
...
};
};
*/
np_pctldev = of_node_get(np_config);
//通过配置节点找到pin控制器的device_node,这正是配置节点要位于pin控制器节点之下的原因
for (;;) {
np_pctldev = of_get_next_parent(np_pctldev);
......
//通过pin控制器的device_node在pinctrldev_list链表里找到对应的pinctrl_dev
pctldev = get_pinctrl_dev_from_of_node(np_pctldev);
if (pctldev)
break;
......
}
of_node_put(np_pctldev);
ops = pctldev->desc->pctlops;
......
/* 调用pinctrl_dev->pinctrl_desc->pinctrl_ops里的dt_node_to_map函数解析配置节点
解析得到得配置信息保存在pinctrl_map,一个配置节点的信息,对应一个或多个pinctrl_map
*/
ret = ops->dt_node_to_map(pctldev, np_config, &map, &num_maps);
......
/* 这些pinctrl_map在增添pinctrl_setting的时候会用到,所以把这些pinctrl_map注册进内核
以链表的形式,插入到全局链表pinctrl_maps
*/
return dt_remember_or_free_map(p, statename, pctldev, map, num_maps);
}
来看看数据结构pinctrl_map:
enum pinctrl_map_type {
PIN_MAP_TYPE_INVALID,
PIN_MAP_TYPE_DUMMY_STATE,
PIN_MAP_TYPE_MUX_GROUP, //复用
PIN_MAP_TYPE_CONFIGS_PIN, //引脚配置
PIN_MAP_TYPE_CONFIGS_GROUP, //一组引脚配置
};
struct pinctrl_map {
//device的name
const char *dev_name;
//状态的名字,如"default"、"idle"
const char *name;
//配置类型
enum pinctrl_map_type type;
const char *ctrl_dev_name;
union {
struct pinctrl_map_mux mux;
struct pinctrl_map_configs configs;
} data;
};
struct pinctrl_map_mux {
const char *group; //group的name
const char *function; //function的name
};
struct pinctrl_map_configs {
const char *group_or_pin; //group或引脚的name
unsigned long *configs; //配置信息,是个数组
unsigned num_configs; //配置信息的个数
};
注册pinctrl_map:
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;
/* 初始化pinctrl_map的dev_name、name等 */
for (i = 0; i < num_maps; i++) {
map[i].dev_name = dev_name(p->dev);
map[i].name = statename;
if (pctldev)
map[i].ctrl_dev_name = dev_name(pctldev->dev);
}
/* 分配一个pinctrl_dt_map,用于保存多个pinctrl_map */
dt_map = kzalloc(sizeof(*dt_map), GFP_KERNEL);
......
//初始化pinctrl_dt_map
dt_map->pctldev = pctldev;
dt_map->map = map;
dt_map->num_maps = num_maps;
//将pinctrl_dt_map插入到pinctrl的dt_maps链表
list_add_tail(&dt_map->node, &p->dt_maps);
//注册pinctrl_map
return pinctrl_register_map(map, num_maps, false);
}
int pinctrl_register_map(struct pinctrl_map const *maps, unsigned num_maps,
bool dup)
{
int i, ret;
struct pinctrl_maps *maps_node;
......
//分配一个pinctrl_maps,保存多个pinctrl_map
maps_node = kzalloc(sizeof(*maps_node), GFP_KERNEL);
......
//设置pinctrl_maps
maps_node->num_maps = num_maps;
if (dup) { //false
......
}
} else {
maps_node->maps = maps;
}
mutex_lock(&pinctrl_maps_mutex);
list_add_tail(&maps_node->node, &pinctrl_maps); //插入到pinctrl_maps链表
mutex_unlock(&pinctrl_maps_mutex);
return 0;
}
来个整体的流程图:
回到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;
......
devname = dev_name(dev);
mutex_lock(&pinctrl_maps_mutex);
//遍历pinctrl_maps链表得到每项pinctrl_map
for_each_maps(maps_node, i, map) {
/*判断是不是该设备的pinctrl_map */
if (strcmp(map->dev_name, devname))
continue;
//增添pinctrl_setting
ret = add_setting(p, map);
......
}
mutex_unlock(&pinctrl_maps_mutex);
......
return p;
}
add_setting:
static int add_setting(struct pinctrl *p, struct pinctrl_map const *map)
{
struct pinctrl_state *state;
struct pinctrl_setting *setting;
int ret;
......
if (map->type == PIN_MAP_TYPE_DUMMY_STATE)
return 0;
//分配pinctrl_setting
setting = kzalloc(sizeof(*setting), GFP_KERNEL);
......
//设置pinctrl_setting
setting->type = map->type;
setting->pctldev = get_pinctrl_dev_from_devname(map->ctrl_dev_name);
......
setting->dev_name = map->dev_name;
//通过pinctrl_map初始化pinctrl_setting
switch (map->type) {
case PIN_MAP_TYPE_MUX_GROUP:
ret = pinmux_map_to_setting(map, setting);
break;
case PIN_MAP_TYPE_CONFIGS_PIN:
case PIN_MAP_TYPE_CONFIGS_GROUP:
ret = pinconf_map_to_setting(map, setting);
break;
default:
ret = -EINVAL;
break;
}
......
//把pinctrl_setting插入到pinctrl_state的settings链表
list_add_tail(&setting->node, &state->settings);
return 0;
}