天天看點

pin state:pinctrl-names的真相

pin state:pinctrl-names的真相

程式框圖:

pin state:pinctrl-names的真相

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

參數: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);
	...
}
           

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;
	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);
		...
		}
   ...
}
           

dt_to_map_one_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);
}
           

of_node_get()函數

include/linux/of.h

static inline struct device_node *of_node_get(struct device_node *node)
{
	return node;
}