gpio子系统和pinctrl子系统(二)

2023-12-07 04:18
文章标签 gpio 子系统 pinctrl

本文主要是介绍gpio子系统和pinctrl子系统(二),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

转自http://blog.rongpmcu.com/gpiozi-xi-tong-he-pinctrlzi-xi-tong-zhong/

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);//第一个核心操作,后面详细分析    ---------> 1ret = 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设备本身也需要做一些配置,这个函数就是用于处理这个功能---------> 2pctldev->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属性,那么状态名就是indexstatename = 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;//设置所属的pctldevsetting->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调用静态添加所有的设置,只是不常用该方式而已。


这篇关于gpio子系统和pinctrl子系统(二)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/464464

相关文章

A20 操作GPIO口

例如:先在 Sys_config.fex文件中 [1302_para] 1302_used      = 1 1302_clk             = port:PD05<1><default><default><0> 1302_dat             = port:PD06<1><default><default><0> 1302_rs

阿里云飞天洛神云网络子系统“齐天”:超大规模云网络智能运维的“定海神针”

云布道师 引言:近日,在南京上秦淮国际文化交流中心举办第八届未来网络发展大会上,阿里云凭借“超大规模云网络智能运维系统”一举斩获由中国通信学会专家组评选的“未来网络领先创新科技成果奖”,本次获奖也体现出阿里云在云网络技术领域科技创新实力获得业界的高度认可,评委专家一致认为“本项目针对云网络运维面临的成本、效率、实施性等挑战,突破了高性能运维数据管理、无人值守网络变更、高精度网络监控、全链路异

新路程------sil9135 hi3516a gpio功能确认

首先确认SCDT管脚 数据手册解释: 也就是hi3516端应该配置为in,这个pin用来表示有video进来,那么进来前后,pin的状态是如何变化的呢? 还有编程手册里 有寄存器可以读取这个SCDT的值,那么还要这个pin干什么呢?不太理解,以后解释 接下来是int pin,中断好配, hi3516a这边是gpio11_2,先看是否配成gpio /usr #

【STM32开发】GPIO最全解析及应用实例

目录 【1】GPIO概述 GPIO的基本概念 GPIO的应用 【2】GPIO功能描述 1.IO功能框图 2.知识补充 3.功能详述 浮空输入 上拉输入 下拉输入 模拟输入 推挽输出 开漏输出 复用开漏输出和复用推挽输出 【3】GPIO常用寄存器 相关寄存器介绍 4个32位配置寄存器 2个32位数据寄存器 1个32位 置位/复位寄存器 2个32位 复用功能配置寄存器 常用寄存器详述 GPIO端

Simulink代码生成: For Iterator子系统及其代码

本文研究Simulink中的For Iterator子系统及其生成的代码。 文章目录 1 Simulink中的For Iterator子系统2 For Iterator子系统建模示例3 For Iterator子系统的代码4 总结 1 Simulink中的For Iterator子系统 不管是在C语言还是Matlab脚本编程的时候,都避免不了使用for循环来反复执行某一段代码。在

集成电路学习:什么是GPIO通用输入输出

GPIO:通用输入输出         GPIO,全称General Purpose Input/Output,即通用输入/输出端口,是嵌入式系统中非常重要的基本硬件资源之一。以下是对GPIO的详细解析: 一、GPIO的定义与功能         GPIO是一种非常灵活的接口,可以实现数字输入、数字输出、模拟输入、模拟输出等多种功能。它作为微控制器、嵌入式系统或其他电子设备与外部世界进行

Linux字符设备驱动 -- regulator子系统

文章目录 环境regulator子系统简介:Regulator设备的注册Consumer设备的注册 环境 linux 4.9 armv8-A regulator子系统简介: 关于regulator子系统,可以看下这这些博客: Linux驱动之Regulator子系统Linux 内核之电源篇(加载流程) regulator,翻译就是调节器。一些可以输出电流电压的设备可以使用

在WIN10的linux子系统是存放在硬盘的哪里?

谷歌搜索 win10 linux location,然后里面有 stackoverflow 的几个链接。 里面说到 linux 存放位置在 C:\Users\{user}\AppData\Local\lxss\{username} 其中 {user} 指的是 windows 的用户,{username} 指的是 linux 里的用户。 以及你的 /home 文件夹会在

玩转 Windows 10 中的 Linux 子系统

在今年的 Build 2016 上,微软向全世界介绍了他们还处于 Beta 阶段的 Windows 下的 Linux 子系统Windows Subsystem for Linux(WSL),它可以让开发者们在 Windows 10 下通过 Bash shell 运行原生的 Ubuntu 用户态二进制程序。如果你参与了 Windows Insider 计划,你就可以在最新的 Windows 10 年

TI DSP TMS320F280025 Note9:GPIO输入输出与外部中断功能原理与应用

TMS320F280025 GPIO输入输出与外部中断功能原理与应用 文章目录 TMS320F280025 GPIO输入输出与外部中断功能原理与应用GPIO原理输入输出模式的共同特性1. 复用设置2. 内部上拉设置3. GPIO状态读取 对于输出模式输出电平设置开漏输出设置 对于输入模式极性设置采样类型不同步(异步输入)只同步到SYSCLKOUT使用采样窗口进行鉴定 外部输入中断G