本文共 23653 字,大约阅读时间需要 78 分钟。
转自http://blog.rongpmcu.com/gpiozi-xi-tong-he-pinctrlzi-xi-tong-zhong/
pinctrl子系统的内容在drivers/pinctrl文件夹下,主要文件有(建议先看看pinctrl内核文档Documentation/pinctrl.txt):
core.c devicetree.c pinconf.c pinmux.c pinctrl-xxx.ccore.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_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
主要做了以下工作:
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
:
实在不想贴代码了,不过不贴又不好解释清楚^_^ 继续上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_setting
和pinconf_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_setting
和pinconf_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_pin
、configs
、num_configs
以及type分别回调pin_config_set
和pin_config_group_set
。
最后补充下,本文描述的都是基于设备树方式的pinctrl处理,其实也可以通过pinctrl_register_mappings
调用静态添加所有的设置,只是不常用该方式而已。
转载地址:http://xgqji.baihongyu.com/