我是靠谱客的博主 深情期待,这篇文章主要介绍kernel - pinctrl (二),现在分享给大家,希望可以做个参考。

一、pinctrl的接口使用示例

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
// 以下是一个使用pinctrl的简单例子 static int leds_probe(struct platform_device * pdev) { ...... struct pinctrl * leds_pctrl; struct pinctrl_state * leds_pin_state; leds_pctrl = devm_pinctrl_get(&pdev->dev); // if (IS_ERR(leds_pctrl)) { printk("devm_pinctrl_get errorn"); return -1; } leds_pin_state = pinctrl_lookup_state(leds_pctrl, "leds_active"); if (IS_ERR(leds_pin_state)) { printk(KERN_ERR "pinctrl_lookup_state errorn"); return -1; } ret = pinctrl_select_state(leds_pctrl, leds_pin_state); if (ret < 0) { printk(KERN_ERR "pinctrl_select_state errorn"); return -1; } ...... return 0; }
  • 调用devm_pinctrl_get获取pinctrl句柄,devm_pinctrl_get实际调用pinctrl_get
  • 调用pinctrl_lookup_state查询所需的pinctrl_state
  • 调用pinctrl_select_state设置对应管脚状态

二、pinctrl的接口分析

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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); if (p != NULL) { dev_dbg(dev, "obtain a copy of previously claimed pinctrln"); kref_get(&p->users); return p; } return create_pinctrl(dev); }
  • 首先调用find_pinctrl函数查找pinctrl句柄,如果找到就直接返回
  • 如果find_pinctrl没有找到pinctrl句柄, 则创建create_pinctrl
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
static struct pinctrl *find_pinctrl(struct device *dev) { struct pinctrl *p; mutex_lock(&pinctrl_list_mutex); list_for_each_entry(p, &pinctrl_list, node) if (p->dev == dev) { mutex_unlock(&pinctrl_list_mutex); return p; } mutex_unlock(&pinctrl_list_mutex); return NULL; }
  • 遍历pinctrl_list查找与dev相匹配的设备pinctrl句柄
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
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); if (p == NULL) { dev_err(dev, "failed to alloc struct pinctrln"); return ERR_PTR(-ENOMEM); } p->dev = dev; INIT_LIST_HEAD(&p->states); INIT_LIST_HEAD(&p->dt_maps); ret = pinctrl_dt_to_map(p); 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); /* * 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; }
  • 动态创建pinctrl并进行相应初始化工作
  • 调用pinctrl_dt_to_map将pinctrl设备树解析为pinctrl_map,并注册到pinctrl_maps
  • 查找pinctrl_maps,调用add_setting将相应的map添加到pinctrl
  • 将pinctrl添加到pinctrl_list以便于后面查找
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
int pinctrl_dt_to_map(struct pinctrl *p) { ...... /* For each defined state ID */ for (state = 0; ; state++) { ...... /* For every referenced pin configuration node in it */ for (config = 0; config < size; config++) { phandle = be32_to_cpup(list++); /* Look up the pin configuration node */ np_config = of_find_node_by_phandle(phandle); if (!np_config) { dev_err(p->dev, "prop %s index %i invalid phandlen", prop->name, config); ret = -EINVAL; goto err; } /* Parse the node */ ret = dt_to_map_one_config(p, statename, np_config); of_node_put(np_config); if (ret < 0) goto err; } ....... } ...... }
  • 首先找到对应的设备树结点np_config
  • 然后调用dt_to_map_one_config去解析设备树
复制代码
1
2
3
4
5
6
7
8
9
10
11
static int dt_to_map_one_config(struct pinctrl *p, const char *statename, ...... ret = ops->dt_node_to_map(pctldev, np_config, &map, &num_maps); if (ret < 0) return ret; /* Stash the mapping table chunk away for later use */ return dt_remember_or_free_map(p, statename, pctldev, map, num_maps); }
  • 调用pctldev->desc->pctlops的dt_node_to_map函数去解析设备树(与具体的pinctrl控制器有关)
  • 调用dt_remember_or_free_map去注册map
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
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; 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); if (!dt_map) { dev_err(p->dev, "failed to alloc struct pinctrl_dt_mapn"); dt_free_map(pctldev, map, num_maps); return -ENOMEM; } dt_map->pctldev = pctldev; dt_map->map = map; dt_map->num_maps = num_maps; list_add_tail(&dt_map->node, &p->dt_maps); return pinctrl_register_map(map, num_maps, false); }
  • 动态分配dt_map,然后注册到pinctrl上
  • 调用pinctrl_register_map创建pinctrl_maps,并将mpinctrl_maps注册到pinctrl_maps链表上,至此pinctrl_dt_to_map的工作基本完成,继续回到create_pinctrl
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
static int add_setting(struct pinctrl *p, struct pinctrl_map const *map) { struct pinctrl_state *state; struct pinctrl_setting *setting; int ret; state = find_state(p, map->name); if (!state) state = create_state(p, map->name); if (IS_ERR(state)) return PTR_ERR(state); if (map->type == PIN_MAP_TYPE_DUMMY_STATE) return 0; setting = kzalloc(sizeof(*setting), GFP_KERNEL); if (setting == NULL) { dev_err(p->dev, "failed to alloc struct pinctrl_settingn"); return -ENOMEM; } setting->type = map->type; setting->pctldev = get_pinctrl_dev_from_devname(map->ctrl_dev_name); if (setting->pctldev == NULL) { kfree(setting); /* Do not defer probing of hogs (circular loop) */ if (!strcmp(map->ctrl_dev_name, map->dev_name)) return -ENODEV; /* * OK let us guess that the driver is not there yet, and * let's defer obtaining this pinctrl handle to later... */ dev_info(p->dev, "unknown pinctrl device %s in map entry, deferring probe", map->ctrl_dev_name); return -EPROBE_DEFER; } setting->dev_name = map->dev_name; 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; } if (ret < 0) { kfree(setting); return ret; } list_add_tail(&setting->node, &state->settings); return 0; }
  • 根据pinctrl和map名称查找state,如果没有找到就创建
  • 动态创建setting并初始化,然后添加到state的settings链表上
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
struct pinctrl_state *pinctrl_lookup_state(struct pinctrl *p, const char *name) { struct pinctrl_state *state; state = find_state(p, name); if (!state) { if (pinctrl_dummy_state) { /* create dummy state */ dev_dbg(p->dev, "using pinctrl dummy state (%s)n", name); state = create_state(p, name); } else state = ERR_PTR(-ENODEV); } return state; }
  • 根据名称查找pinctrl里的state,返回pinctrl_state
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
int pinctrl_select_state(struct pinctrl *p, struct pinctrl_state *state) { struct pinctrl_setting *setting, *setting2; struct pinctrl_state *old_state = p->state; int ret; if (p->state == state) return 0; if (p->state) { /* * For each pinmux setting in the old state, forget SW's record * of mux owner for that pingroup. Any pingroups which are * still owned by the new state will be re-acquired by the call * to pinmux_enable_setting() in the loop below. */ list_for_each_entry(setting, &p->state->settings, node) { if (setting->type != PIN_MAP_TYPE_MUX_GROUP) continue; pinmux_disable_setting(setting); } } p->state = NULL; /* Apply all the settings for the new state */ list_for_each_entry(setting, &state->settings, node) { switch (setting->type) { case PIN_MAP_TYPE_MUX_GROUP: ret = pinmux_enable_setting(setting); break; case PIN_MAP_TYPE_CONFIGS_PIN: case PIN_MAP_TYPE_CONFIGS_GROUP: ret = pinconf_apply_setting(setting); break; default: ret = -EINVAL; break; } if (ret < 0) { goto unapply_new_state; } } p->state = state; ...... }
  • 调用pinmux_enable_setting和pinconf_apply_setting应用相应settings

转载于:https://www.cnblogs.com/qzhang1535/p/10948452.html

最后

以上就是深情期待最近收集整理的关于kernel - pinctrl (二)的全部内容,更多相关kernel内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(73)

评论列表共有 0 条评论

立即
投稿
返回
顶部