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

时间:2022-12-26 14:09:57

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注册。先引用一张网上截图:

gpio子系统和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月

gpio子系统和pinctrl子系统(中)的更多相关文章

  1. gpio子系统和pinctrl子系统(下)

    情景分析 打算从两个角度来情景分析,先从bsp驱动工程师的角度,然后是驱动工程师的角度,下面以三星s3c6410 Pinctrl-samsung.c为例看看pinctrl输入参数的初始化过程(最开始的 ...

  2. gpio子系统和pinctrl子系统(上)

    前言 随着内核的发展,linux驱动框架在不断的变化.很早很早以前,出现了gpio子系统,后来又出现了pinctrl子系统.在网上很难看到一篇讲解这类子系统的文章.就拿gpio操作来说吧,很多时候都是 ...

  3. Linux驱动之GPIO子系统和pinctrl子系统

    前期知识   1.如何编写一个简单的Linux驱动(一)--驱动的基本框架   2.如何编写一个简单的Linux驱动(二)--设备操作集file_operations   3.如何编写一个简单的Lin ...

  4. 【转】Linux內核驅動之GPIO子系統&lpar;一&rpar;GPIO的使用 &lowbar;蝸牛

    原文网址:http://tc.chinawin.net/it/os/article-2512b.html 一 概述 Linux內核中gpio是最簡單,最常用的資源(和interrupt ,dma,ti ...

  5. 关于Linux系统和Windows系统中文件夹的命名规范

    Windows系统中. 1.在创建文件夹的时候不能以"."开头(但是文件以多个点开头并且还有其他合法字符的话就是合法的) 但是在windows系统中确实见过以一个点".& ...

  6. 在windows系统和linux系统中查询IP地址命令的不同

    在linux和windows系统上查询IP地址的命令是不一样的.         在linux中的命令行模式下,输入ifconfig即可查询到IP.而在windows系统下要查询IP地址需要先打开do ...

  7. Pinctrl子系统之一了解基础概念【转】

    转自:https://blog.csdn.net/u012830148/article/details/80609337 版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请 ...

  8. Linux驱动架构之pinctrl子系统分析(一)

    1.前言在嵌入式系统中,许多SoC的内部都包含了pin控制器,通过芯片内部的pin控制器,我们可以配置一个或者一组引脚的状态和功能特性,Linux内核为了统一各SoC厂商的引脚管理,提供了pinctr ...

  9. 下一代大数据系统和4S标准

    大数据行业发展到今天,它创造的价值和带来的社会效应,大家已经看得很明白,同时很多问题和不足也暴露出来,特别是hadoop能够提供的数据处理能力,现在已经挖掘到极限,但是现在各行业对数据的存储和计算需求 ...

随机推荐

  1. 多线程同步工具——CAS原子变量

    这是我参考的一篇文章<基于CAS的乐观锁实现>,讲述的是一种需要CPU支持的执行技术CAS(Compare and Swap). 首先理解什么是原子性操作,意思是不能再拆分的操作,例如改写 ...

  2. 从0到1,教你实现基于Ruby的watir-webdriver自动化测试

    一.为什么选择Ruby []完全开源. []多平台:Ruby可以运行在Linux, UNIX, Windows, MS-DOS, BeOS, OS/.. []多线程:线程就是指在一个程序中处理若干控制 ...

  3. 合并文件夹里多个excel

    Sub 合并当前目录下所有工作簿的全部工作表() Dim MyPath, MyName, AWbName Dim Wb As workbook, WbN As String Dim G As Long ...

  4. 【转】IE8浏览器无法保存Cookie的解决方法

    转自:http://blog.csdn.net/sjsm2007/article/details/17958145 使用IE8浏览器经常出现了无法保存Cookie的故障.每次打开网站需要重新登录,登录 ...

  5. Pain for friend

    For a guy who has experienced his fair share of mysteries,on mystery,I still can't figure out is why ...

  6. input标签新增属性

    <input   list='list_t' type="text" name='user' placeholder='请输入姓名' value="" / ...

  7. PBOC圈存时用到3DES加密解密以及MAC计算方法

    最近在做PBOC圈存时用到了3DES的加密解密以及MAC计算问题,在网上了解一些知识,复制了一些demo学习,我这里没有深入研究,只是把我用到的和了解的做个总结,便于以后使用和学习. 3DES分双倍长 ...

  8. iptables转发备忘

    iptables -F sysctl net.ipv4.ip_forward=1 iptables -t nat -A PREROUTING -p tcp -i eth0 --dport 8766 - ...

  9. vue&period;js 精学记录

    v-bind:class使用的方式: 1.对象与法::class="{'active':isActive}" 此时当isActive为true时,会拥有active 2.数组语法: ...

  10. &lbrack;蓝桥杯&rsqb;PREV-22&period;历届试题&lowbar;国王的烦恼

    问题描述 C国由n个小岛组成,为了方便小岛之间联络,C国在小岛间建立了m座大桥,每座大桥连接两座小岛.两个小岛间可能存在多座桥连接.然而,由于海水冲刷,有一些大桥面临着不能使用的危险. 如果两个小岛间 ...