gpio子系統和pinctrl子系統(中)


pinctrl子系統核心實現分析

pinctrl子系統的內容在drivers/pinctrl文件夾下,主要文件有(建議先看看pinctrl內核文檔Documentation/pinctrl.txt):
core.c
devicetree.c
pinconf.c
pinmux.c
pinctrl-xxx.c

core.c為pinctrl的核心代碼,實現了pinctrl框架,pinmux.c和pinconf.c基於core實現了對pinmux和pinconf的支持,pinctrl-xxx.c為廠商相關的pinctrl實現(又是苦逼的bsp工程師_),當然有些廠商還未采用pinctrl機制,因此就沒有對應的實現。最后說一句,pinctrl的實現不許用我們在驅動里調用任何它提供的api,所有的pinctrl動作都是在通用內核代碼里完成了,對於驅動工程師是透明的。驅動工程師只需要通過設備樹文件就能掌控整個系統的pin管理了,后面分析的過程會證實這一點。

pinctrl在代碼層級只與bsp工程師有關,他們需要調用pinctrl api pinctrl_register注冊。先引用一張網上截圖:
pinctrl子系統框架
對於驅動工程師,只需要通過設備樹文件就可以起到配置整個系統pin的目的。有幾個概念先理一下,功能和組,功能就是指uart、i2c、spi等這些,組是pin的集合,我們都知道現在的soc的pin中,經常會遇到一個功能可以由不同的pin集合(即組)配置,當然同一時間只能選一個pin集合,因此,當我們要用某個功能的時候,需要告訴它func以及哪一組。下面開始分析pinctrl_register

struct pinctrl_dev *pinctrl_register(struct pinctrl_desc *pctldesc,
				    struct device *dev, void *driver_data)
{
	struct pinctrl_dev *pctldev;
	int ret;

	if (!pctldesc)
		return NULL;
	if (!pctldesc->name)
		return NULL;

	//一般只有pinctrl chip driver需要調用pinctrl_register,pctldev就是軟件上pinctrl的抽象
	pctldev = kzalloc(sizeof(*pctldev), GFP_KERNEL);
	if (pctldev == NULL) {
		dev_err(dev, "failed to alloc struct pinctrl_dev\n");
		return NULL;
	}

	/* Initialize pin control device struct */
    //初始化一些成員,后面會遇到它們的
	pctldev->owner = pctldesc->owner;
	pctldev->desc = pctldesc;
	pctldev->driver_data = driver_data;
    //pin_desc_tree用於存放所有的pin信息,由后面即將分析的pinctrl_register_pins來填充
    //所有pin信息來源於輸入參數pctldesc,也就是說每個pinctrl chip driver的實現者需要告訴pinctrl
    //子系統該pinctrl chip所有的pin信息
	INIT_RADIX_TREE(&pctldev->pin_desc_tree, GFP_KERNEL);
    //這個由gpio子系統填充信息,還記得of_gpiochip_add_pin_range吧^_^最后總結的時候再結合gpio子系統一起看看這部分
	INIT_LIST_HEAD(&pctldev->gpio_ranges);
	pctldev->dev = dev;
	mutex_init(&pctldev->mutex);

	/* check core ops for sanity */
    //pinctrl_ops是pinctrl chip driver必須要實現的一組回調集合,后面在用到它里面的api時再詳細講解
	if (pinctrl_check_ops(pctldev)) {
		dev_err(dev, "pinctrl ops lacks necessary functions\n");
		goto out_err;
	}

	/* If we're implementing pinmuxing, check the ops for sanity */
    //如果提供了pinmux ops,檢查下是否合法
	if (pctldesc->pmxops) {
		if (pinmux_check_ops(pctldev))
			goto out_err;
	}

	/* If we're implementing pinconfig, check the ops for sanity */
    //如果提供了pinconf ops,檢查下是否合法
	if (pctldesc->confops) {
		if (pinconf_check_ops(pctldev))
			goto out_err;
	}

	/* Register all the pins */
	dev_dbg(dev, "try to register %d pins ...\n",  pctldesc->npins);
    //第一個核心操作,后面詳細分析    ---------> 1
	ret = pinctrl_register_pins(pctldev, pctldesc->pins, pctldesc->npins);
	if (ret) {
		dev_err(dev, "error during pin registration\n");
		pinctrl_free_pindescs(pctldev, pctldesc->pins,
				      pctldesc->npins);
		goto out_err;
	}

	mutex_lock(&pinctrldev_list_mutex);
    //將pctldev加入到全局鏈表
	list_add_tail(&pctldev->node, &pinctrldev_list);
	mutex_unlock(&pinctrldev_list_mutex);

	//這是第二個核心操作,往往pinctrl設備本身也需要做一些配置,這個函數就是用於處理這個功能---------> 2
	pctldev->p = pinctrl_get(pctldev->dev);

	if (!IS_ERR(pctldev->p)) {
    	//如果pinctrl設備提供了default狀態,設置為default狀態
		pctldev->hog_default =
			pinctrl_lookup_state(pctldev->p, PINCTRL_STATE_DEFAULT);
		if (IS_ERR(pctldev->hog_default)) {
			dev_dbg(dev, "failed to lookup the default state\n");
		} else {
        	//設置為default狀態
			if (pinctrl_select_state(pctldev->p,
						pctldev->hog_default))
				dev_err(dev,
					"failed to select default state\n");
		}

		//如果pinctrl設備提供了sleep狀態,獲取它,以后再用
		pctldev->hog_sleep =
			pinctrl_lookup_state(pctldev->p,
						    PINCTRL_STATE_SLEEP);
		if (IS_ERR(pctldev->hog_sleep))
			dev_dbg(dev, "failed to lookup the sleep state\n");
	}

	//和調試相關,先忽略吧
	pinctrl_init_device_debugfs(pctldev);

	return pctldev;

out_err:
	mutex_destroy(&pctldev->mutex);
	kfree(pctldev);
	return NULL;
}

總結一下,pinctrl_register主要做了以下工作:

  1. 分配pctldev數據結構,並添加到全局鏈表pinctrldev_list
  2. 填充pctldev,根據pctldesc里的pin信息注冊所有的pin信息到pctldev里的pin_desc_tree管理起來,
  3. 如果該pinctrl對應的設備樹里有描述它自己的pin配置信息,那么解析它,並設置為default狀態。這一部分是任何一個用到pinctrl設備都會進行的動作(解析、設置狀態)
  4. 初始化調試相關的東西

下面先看看pinctrl_register_pins的過程:

static int pinctrl_register_pins(struct pinctrl_dev *pctldev,
				 struct pinctrl_pin_desc const *pins,
				 unsigned num_descs)
{
	unsigned i;
	int ret = 0;

	for (i = 0; i < num_descs; i++) {
    	//遍歷傳入的所有pin的數據結構,一個個處理它們
        //pinctrl driver會傳入所有的pin管腳及對應的名稱
		ret = pinctrl_register_one_pin(pctldev,
					       pins[i].number, pins[i].name);
		if (ret)
			return ret;
	}

	return 0;
}

static int pinctrl_register_one_pin(struct pinctrl_dev *pctldev,
				    unsigned number, const char *name)
{
	struct pin_desc *pindesc;

	//查看是否已經存在了
	pindesc = pin_desc_get(pctldev, number);
	if (pindesc != NULL) {
		pr_err("pin %d already registered on %s\n", number,
		       pctldev->desc->name);
		return -EINVAL;
	}

	//分配一個pinctrl子系統用於管理pin的數據結構
	pindesc = kzalloc(sizeof(*pindesc), GFP_KERNEL);
	if (pindesc == NULL) {
		dev_err(pctldev->dev, "failed to alloc struct pin_desc\n");
		return -ENOMEM;
	}

	/* Set owner */
    //指定該pin的擁有者
	pindesc->pctldev = pctldev;

	/* Copy basic pin info */
	if (name) {
    	//如果指定了名字,那么好吧,就用你了
		pindesc->name = name;
	} else {
    	//如果沒有指定名字,用默認的格式組合一個
		pindesc->name = kasprintf(GFP_KERNEL, "PIN%u", number);
		if (pindesc->name == NULL) {
			kfree(pindesc);
			return -ENOMEM;
		}
		pindesc->dynamic_name = true;
	}

	//將該pin添加到pctldev里管理起來
	radix_tree_insert(&pctldev->pin_desc_tree, number, pindesc);
	pr_debug("registered pin %d (%s) on %s\n",
		 number, pindesc->name, pctldev->desc->name);
	return 0;
}

下面開始分析第二個核心部分pinctrl_get,注意,這部分是任何一個用到pinctrl設備都會進行的動作(解析、設置狀態),所以還必須弄清楚它,它主要的作用就是通過解析該設備的pinctrl信息生成一個pinctrl數據結構,用於管理該設備的pin信息,如有哪些狀態、每個狀態有哪些設置(設置包括pinmux和pinconf兩種,有些設備只用需要pinmux,有些需要pinmux和pinconf)

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.
	 */
    //如果已經有其他模塊get了,那么pinctrl肯定已經創建好了,直接返回吧
	p = find_pinctrl(dev);
	if (p != NULL) {
		dev_dbg(dev, "obtain a copy of previously claimed pinctrl\n");
		kref_get(&p->users);
		return p;
	}

	//否則,創建一個pinctrl用於管理該設備本身的pin信息
	return create_pinctrl(dev);
}

繼續看解析的過程,通過看懂這部分,我們應該就很清楚設備樹里需要怎么配置,怎么對整個系統的pin配置起作用的

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 pinctrl\n");
		return ERR_PTR(-ENOMEM);
	}
	p->dev = dev;
    //每個需要管理的設備都會有對應的pinctrl,每個設備也會有多個狀態,如default、sleep等等(內核
    //默認定義了一些,自己也可以隨意定義),每個狀態又有可能有多種設置。這個需要自己慢慢理解^_^
    //這里的states成員就是用於存放所有的狀態的
	INIT_LIST_HEAD(&p->states);
    //這里的dt_maps就是用於存放所有的設置的
	INIT_LIST_HEAD(&p->dt_maps);

	//又是一個復雜的函數,后面分析,它主要用於解析設備樹里的信息,生成該設備對應的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 */
    //遍歷所有的的設置,這里遍歷的是全局的maps鏈表,因為它要用到
    //pinctrl_map結構,而p->dt_maps里的不是該類型
	for_each_maps(maps_node, i, map) {
		/* Map must be for this device */
        //檢查是否屬於俺的設置
		if (strcmp(map->dev_name, devname))
			continue;

		//將該設置加入到pinctrl中,也許有人會奇怪,前面的dt_maps不是已經包含了該設備的所有設置了么,
        //其實這里會對每個設置做進一步處理,然后放入到p中,后面分析
		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);
    //將每個設備用於控制pin的結構也放到一個全局鏈表中
	list_add_tail(&p->node, &pinctrl_list);
	mutex_unlock(&pinctrl_list_mutex);

	return p;
}

先總結下create_pinctrl

  1. 創建一個pinctrl,將它加入到全局的pinctrl鏈表
  2. 解析該設備的說有設備樹信息,將解析的狀態掛到states里,解析的設置掛到dt_maps(當然,設置同時也掛到全局的maps里去了)

實在不想貼代碼了,不過不貼又不好解釋清楚_ 繼續上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;

	/* CONFIG_OF enabled, p->dev not instantiated from DT */
	if (!np) {
		if (of_have_populated_dt())
			dev_dbg(p->dev,
				"no of_node; not parsing pinctrl DT\n");
		return 0;
	}

	/* We may store pointers to property names within the node */
	of_node_get(np);

	/* For each defined state ID */
	for (state = 0; ; state++) {
		/* Retrieve the pinctrl-* property */
		//pinctrl子系統規定了幾個屬性,如pinctrl-n,用於指定一個狀態對應的設置,從0開始        
		propname = kasprintf(GFP_KERNEL, "pinctrl-%d", state);
        //查找pinctrl-n屬性
		prop = of_find_property(np, propname, &size);
		kfree(propname);
		if (!prop)
			break;
        //value對應的就是該狀態對應的設置(可能有多個),后面會處理它
		list = prop->value;
		size /= sizeof(*list);

		/* Determine whether pinctrl-names property names the state */
        //讀pinctrl-names屬性,也屬於pinctrl子系統規定的屬性,用於指定每個狀態的名字,一一對應的
		ret = of_property_read_string_index(np, "pinctrl-names",
						    state, &statename);
		/*
		 * If not, statename is just the integer state ID. But rather
		 * than dynamically allocate it and have to free it later,
		 * just point part way into the property name for the string.
		 */
		if (ret < 0) {
			/* strlen("pinctrl-") == 8 */
            //如果美譽pinctrl-names屬性,那么狀態名就是index
			statename = prop->name + 8;
		}

		/* For every referenced pin configuration node in it */
        //一個一個處理設置
		for (config = 0; config < size; config++) {
        	//第一個成員規定為配置節點(屬於pinctrl的子節點)的引用,因此通過它可以找到該配置節點
			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 phandle\n",
					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;
		}

		/* No entries in DT? Generate a dummy state table entry */
		if (!size) {
			ret = dt_remember_dummy_state(p, statename);
			if (ret < 0)
				goto err;
		}
	}

	return 0;

err:
	pinctrl_dt_free_maps(p);
	return ret;
}

繼續看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;

	/* Find the pin controller containing np_config */
	np_pctldev = of_node_get(np_config);
	for (;;) {
    	//找該節點的父節點,就是pinctrl設備啦,我們得通過它獲取pctldev,畢竟只有它才有啊
		np_pctldev = of_get_next_parent(np_pctldev);
		if (!np_pctldev || of_node_is_root(np_pctldev)) {
			dev_info(p->dev, "could not find pctldev for node %s, deferring probe\n",
				np_config->full_name);
			of_node_put(np_pctldev);
			/* OK let's just assume this will appear later then */
			return -EPROBE_DEFER;
		}
		pctldev = get_pinctrl_dev_from_of_node(np_pctldev);
		if (pctldev)//拿到就跳出
			break;
		/* Do not defer probing of hogs (circular loop) */
		if (np_pctldev == p->dev->of_node) {
			of_node_put(np_pctldev);
			return -ENODEV;
		}
	}
	of_node_put(np_pctldev);

	/*
	 * Call pinctrl driver to parse device tree node, and
	 * generate mapping table entries
	 */
	ops = pctldev->desc->pctlops;
    //這里就用到了pinctrl_register注冊時pctlops里的dt_node_to_map回調函數了
	if (!ops->dt_node_to_map) {
		dev_err(p->dev, "pctldev %s doesn't support DT\n",
			dev_name(pctldev->dev));
		return -ENODEV;
	}
    //調用它,靠它來解析出這個配置節點,畢竟格式只有對應的pinctrl driver最清楚
	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 */
    //將解析出來的設置添加到pctldev的dt_maps中,也會加到全局的maps中啦,這里就不再深入分析了,自己都覺得太啰嗦了
	return dt_remember_or_free_map(p, statename, pctldev, map, num_maps);
}

繼續看add_setting:

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_setting\n");
		return -ENOMEM;
	}

	//設置的類型
	setting->type = map->type;

	//設置所屬的pctldev
	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) {//根據設置的類型處理設置,因為設置可以表示mux功能,也可以表示conf功能
	case PIN_MAP_TYPE_MUX_GROUP://如果是mux功能的設置,調用mux模塊處理
		ret = pinmux_map_to_setting(map, setting);
		break;
	case PIN_MAP_TYPE_CONFIGS_PIN:
	case PIN_MAP_TYPE_CONFIGS_GROUP://如果是mux功能的設置,調用conf模塊處理
		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;
}

下面分別分析pinmux_map_to_settingpinconf_map_to_setting,先pinmux_map_to_setting,它是和pinmux相關,對應pinmux.c文件,里面也會用到pinmux_ops

int pinmux_map_to_setting(struct pinctrl_map const *map,
			  struct pinctrl_setting *setting)
{
	struct pinctrl_dev *pctldev = setting->pctldev;
	const struct pinmux_ops *pmxops = pctldev->desc->pmxops;
	char const * const *groups;
	unsigned num_groups;
	int ret;
	const char *group;
	int i;
	//如果在register的時候沒有指定pinmux_ops,那么該函數什么都不做,出錯返回
	if (!pmxops) {
		dev_err(pctldev->dev, "does not support mux function\n");
		return -EINVAL;
	}
	//現在就是pinmux_ops作用的時候啦!里面會以從0開始的索引不停的調用
    //pinmux_ops里的get_function_name來獲取對應的名字,然后和前面解析設備樹過程解析出來的名字做匹配
    //直到找到或到末尾,返回該索引。這個索引與功能之間的關系由pinctrl bsp實現者負責
	ret = pinmux_func_name_to_selector(pctldev, map->data.mux.function);
	if (ret < 0) {
		dev_err(pctldev->dev, "invalid function %s in map table\n",
			map->data.mux.function);
		return ret;
	}
    //保存該索引
	setting->data.mux.func = ret;

	//調用pmxops的get_function_groups獲取該索引對應的組(可能存在多個,前面已經說過,一個功能可以由多個組實現,同一時間只能選一個組)
	ret = pmxops->get_function_groups(pctldev, setting->data.mux.func,
					  &groups, &num_groups);
	if (ret < 0) {
		dev_err(pctldev->dev, "can't query groups for function %s\n",
			map->data.mux.function);
		return ret;
	}
	if (!num_groups) {
		dev_err(pctldev->dev,
			"function %s can't be selected on any group\n",
			map->data.mux.function);
		return -EINVAL;
	}
    //如果設備樹里有直接指定組,那么就會以指定的組為默認選擇
	if (map->data.mux.group) {
		bool found = false;
		group = map->data.mux.group;
        //當然,也還是要校驗下,組是否有效
		for (i = 0; i < num_groups; i++) {
			if (!strcmp(group, groups[i])) {
				found = true;
				break;
			}
		}
		if (!found) {
			dev_err(pctldev->dev,
				"invalid group \"%s\" for function \"%s\"\n",
				group, map->data.mux.function);
			return -EINVAL;
		}
	} else {
    	//如果沒有指定,那么就用第一個組咯
		group = groups[0];
	}

	//根據選定的組,獲取該組的信息,返回的是該組對應的索引,這里會調用pmxops的get_group_name,操作
    //過程和前面的pinmux_func_name_to_selector類似
	ret = pinctrl_get_group_selector(pctldev, group);
	if (ret < 0) {
		dev_err(pctldev->dev, "invalid group %s in map table\n",
			map->data.mux.group);
		return ret;
	}
    //保存該組索引
	setting->data.mux.group = ret;

	return 0;
}

繼續pinconf_map_to_setting吧,它是和pinconf相關,對應pinconf.c文件,但里面還沒用pinconf_ops,后面才會用到:

int pinconf_map_to_setting(struct pinctrl_map const *map,
			  struct pinctrl_setting *setting)
{
	struct pinctrl_dev *pctldev = setting->pctldev;
	int pin;

	switch (setting->type) {//該設置到底是什么類型,是pinctrl driver回調dt_node_to_map里解析的
    //配置有兩種類型,一種是一個pin一個pin的配置,一種是將一些pin的配置組合為一個組,指定某個組就會采用那個組里的所有的pin的配置
	case PIN_MAP_TYPE_CONFIGS_PIN:
    	//根據設備樹里指定的pin名字獲取它對應的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;
		}
        //將該設置對應的pin號保存起來
		setting->data.configs.group_or_pin = pin;
		break;
	case PIN_MAP_TYPE_CONFIGS_GROUP:
    	//根據設備樹指定的pin組獲取它對應的group號
		pin = pinctrl_get_group_selector(pctldev,
					 map->data.configs.group_or_pin);
		if (pin < 0) {
			dev_err(pctldev->dev, "could not map group config for \"%s\"",
				map->data.configs.group_or_pin);
			return pin;
		}
        //將該設置對應的group號保存起來
		setting->data.configs.group_or_pin = pin;
		break;
	default:
		return -EINVAL;
	}
	
    //保存所有其他用於配置的信息
	setting->data.configs.num_configs = map->data.configs.num_configs;
	setting->data.configs.configs = map->data.configs.configs;

	return 0;
}

現在都僅僅是分析了pinmux_map_to_settingpinconf_map_to_setting,具體它們的作用我們在后面才能看的出來,所以繼續分析吧!到這里pinctrl_get分析完了,執行完pinctrl_get,就意味着該設備的所有和pin相關的設備樹信息已經解析完成,並生成了用於管理、配置的數據結構,為以后的其他api提供了支持。其他驅動一般不會直接調用pinctrl_get,而是調用它的變體devm_pinctrl_get或者pinctrl_get_select來初始化設備。devm_pinctrl_get就不用說了啦,pinctrl_get_select類似與pinctrl_register調用pinctrl_get及它后的那段代碼的結合,不僅調用了pinctrl_get,還根據輸入參數讓設備處於指定的狀態。通過pinctrl_select_state來讓設備處於指定的狀態,下面開始分析它,通過分析它,應該就清楚了前面各種填充的作用啦!

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) {
		/*
		 * The set of groups with a mux configuration in the old state
		 * may not be identical to the set of groups with a mux setting
		 * in the new state. While this might be unusual, it's entirely
		 * possible for the "user"-supplied mapping table to be written
		 * that way. For each group that was configured in the old state
		 * but not in the new state, this code puts that group into a
		 * safe/disabled state.
		 */
		list_for_each_entry(setting, &p->state->settings, node) {
			bool found = false;
			if (setting->type != PIN_MAP_TYPE_MUX_GROUP)
				continue;
			list_for_each_entry(setting2, &state->settings, node) {
				if (setting2->type != PIN_MAP_TYPE_MUX_GROUP)
					continue;
				if (setting2->data.mux.group ==
						setting->data.mux.group) {
					found = true;
					break;
				}
			}
			if (!found)
				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://如果該設置是mux設置,那么調用pinmux_enable_setting,這里面
        	//就用到了前面填充的信息
			ret = pinmux_enable_setting(setting);
			break;
		case PIN_MAP_TYPE_CONFIGS_PIN:
		case PIN_MAP_TYPE_CONFIGS_GROUP://如果該設置是conf設置,那么調用pinconf_apply_setting,
        	//這里面就用到了前面填充的信息
			ret = pinconf_apply_setting(setting);
			break;
		default:
			ret = -EINVAL;
			break;
		}

		if (ret < 0) {
			goto unapply_new_state;
		}
	}

	p->state = state;

	return 0;

unapply_new_state:
	dev_err(p->dev, "Error applying setting, reverse things back\n");

	list_for_each_entry(setting2, &state->settings, node) {
		if (&setting2->node == &setting->node)
			break;
		/*
		 * All we can do here is pinmux_disable_setting.
		 * That means that some pins are muxed differently now
		 * than they were before applying the setting (We can't
		 * "unmux a pin"!), but it's not a big deal since the pins
		 * are free to be muxed by another apply_setting.
		 */
		if (setting2->type == PIN_MAP_TYPE_MUX_GROUP)
			pinmux_disable_setting(setting2);
	}

	/* There's no infinite recursive loop here because p->state is NULL */
	if (old_state)
		pinctrl_select_state(p, old_state);

	return ret;
}

pinmux_enable_setting當然處於pinmux.c中,根據前面填充的setting->data.mux.group獲取該組的pin信息,然后以pin號為參數循環回調ops->request,最后回調ops->enable。

pinconf_apply_setting當然處於pinconf.c中,根據前面填充的group_or_pinconfigsnum_configs以及type分別回調pin_config_setpin_config_group_set

最后補充下,本文描述的都是基於設備樹方式的pinctrl處理,其實也可以通過pinctrl_register_mappings調用靜態添加所有的設置,只是不常用該方式而已。

未完,待續!
2015年7月


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM