网站 水印,自己做的网站怎么实现结算功能,佟年给韩商言做的网站,赣州新闻联播今天回放往期内容 本专栏往期内容#xff1a; Pinctrl子系统和其主要结构体引入Pinctrl子系统pinctrl_desc结构体进一步介绍Pinctrl子系统中client端设备树相关数据结构介绍和解析inctrl子系统中Pincontroller构造过程驱动分析#xff1a;imx_pinctrl_soc_info结构体 input子系统专栏…往期内容 本专栏往期内容 Pinctrl子系统和其主要结构体引入Pinctrl子系统pinctrl_desc结构体进一步介绍Pinctrl子系统中client端设备树相关数据结构介绍和解析inctrl子系统中Pincontroller构造过程驱动分析imx_pinctrl_soc_info结构体 input子系统专栏 专栏地址input子系统input角度I2C触摸屏驱动分析和编写一个简单的I2C驱动程序 – 末片有往期内容观看顺序 I2C子系统专栏 专栏地址IIC子系统具体芯片的IIC控制器驱动程序分析i2c-imx.c-CSDN博客 – 末篇有往期内容观看顺序 总线和设备树专栏 专栏地址总线和设备树设备树与 Linux 内核设备驱动模型的整合-CSDN博客 – 末篇有往期内容观看顺序 前言
本节就不提供相关源码文件了各个代码块处都有标明该函数的文件路径需要的可以自行去查看。
主要讲解作为使用者来说去使用pinctrl其相关驱动程序是如何去进行获取pinctrl信息对其进行解析将引脚转为map在转为setting存储起来去进行使用也就是其如何去配置、复用引脚的。
1.回顾client的数据结构
看之前的文章Pinctrl子系统中client端设备树相关数据结构介绍和解析
右侧是Pinctrl节点左侧是client端节点。Pinctrl节点中设置了要使用的引脚的信息以及复用的功能client节点则是对要使用的引脚进行引用其实就是模块的设备节点。 Pin Controller有自己的驱动程序
virtual_pincontroller {compatible 100ask,virtual_pinctrl;myled_pin: myled_pin {functions gpio;groups pin0;configs 0x11223344;};
};GPIO Controller有自己的驱动程序
gpio_virt: virtual_gpiocontroller {compatible 100ask,virtual_gpio;gpio-controller;#gpio-cells 2;ngpios 4;
};Client有自己的驱动程序
myled {compatible 100ask,leddrv;led-gpios gpio_virt 0 GPIO_ACTIVE_LOW;pinctrl-names default;pinctrl-0 myled_pin;
};另一种写法(正确写法)让GPIO和Pinctrl之间建立联系
/ {pinctrl_virt: virtual_pincontroller {compatible 100ask,virtual_pinctrl;myled_pin: myled_pin {functions gpio;groups pin0;configs 0x11223344;};i2cgrp: i2cgrp {functions i2c, i2c;groups pin0, pin1;configs 0x11223344 0x55667788;};};gpio_virt: virtual_gpiocontroller {compatible 100ask,virtual_gpio;gpio-controller;#gpio-cells 2;ngpios 4;gpio-ranges pinctrl_virt 0 0 4; //GPIO控制器的第0号引脚对应pinctrl_virt的第0号引脚也就是对应myled_pin数量为4};myled {compatible 100ask,leddrv;led-gpios gpio_virt 2 GPIO_ACTIVE_LOW;};
};2.client的pinctrl构造过程
相同state的描述引脚的设备树节点如何转换为pinctrl_map这些pinctrl_map又如何转换为pinctrl_setting存放在pinctrl_state结构体中的settings链表中
2.1 总图
比较长看下图就行了。 really_probe pinctrl_bind_pinsdev-pins devm_kzalloc(dev, sizeof(*(dev-pins)), GFP_KERNEL);dev-pins-p devm_pinctrl_get(dev); create_pinctrl(dev);ret pinctrl_dt_to_map(p);for_each_maps(maps_node, i, map) {ret add_setting(p, map);}dev-pins-default_state pinctrl_lookup_state(dev-pins-p,PINCTRL_STATE_DEFAULT); 2.2 解析
如果想深入了解各个代码的含义可以继续看
really_probe //\Linux-4.9.88\drivers\base\dd.c//* If using pinctrl, bind pins now before probing */pinctrl_bind_pins //\Linux-4.9.88\drivers\base\dd.cdev-pins-p devm_pinctrl_get(dev); //直接从该函数进入看p pinctrl_get(dev);//D\Linux-4.9.88\drivers\pinctrl\core.cpinctrl_get内部实现如下根据其注释可以知道去获取到pinctrl的句柄但是在第一次的时候肯定是没有的所以最后会去调用create_pinctrl函数去创建pinctrl
\Linux-4.9.88\drivers\pinctrl\core.c/*** pinctrl_get() - retrieves the pinctrl handle for a device* dev: the device to obtain the handle for*/
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.*/p find_pinctrl(dev);if (p ! NULL) {dev_dbg(dev, obtain a copy of previously claimed pinctrl\n);kref_get(p-users);return p;}return create_pinctrl(dev);
}进入create_pinctrl函数看看
\Linux-4.9.88\drivers\pinctrl\core.c
/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; // 存储返回值用于错误检查/* * 为每个映射创建状态存储结构体 pinctrl* 消费者可以通过 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; // 关联设备指针INIT_LIST_HEAD(p-states); // 初始化引脚控制的状态列表INIT_LIST_HEAD(p-dt_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); // 加锁以保护全局映射/* 遍历所有引脚控制映射以找到合适的映射 */for_each_maps(maps_node, i, map) {/* 检查映射是否属于当前设备 */if (strcmp(map-dev_name, devname))continue;// 将映射添加到引脚控制结构体中ret add_setting(p, map);/** 此时添加设置可能会* - 延迟如果引脚控制设备尚未可用* - 失败如果设置是 hog 类型并且引脚控制设备尚不可用* 如果返回的错误不是 -EPROBE_DEFER则积累错误* 以检查是否有 -EPROBE_DEFER 的情况因为那是最糟糕的情况。*/if (ret -EPROBE_DEFER) {pinctrl_free(p, false); // 释放 pinctrl 结构体mutex_unlock(pinctrl_maps_mutex); // 解锁return ERR_PTR(ret); // 返回延迟错误指针}}mutex_unlock(pinctrl_maps_mutex); // 解锁映射互斥量if (ret 0) {/* 如果发生延迟以外的其他错误返回错误 */pinctrl_free(p, false);return ERR_PTR(ret);}kref_init(p-users); // 初始化引用计数/* 将 pinctrl 句柄添加到全局列表中 */mutex_lock(pinctrl_list_mutex);list_add_tail(p-node, pinctrl_list);mutex_unlock(pinctrl_list_mutex);return p; // 返回创建的引脚控制结构体
}其中最主要的就是ret pinctrl_dt_to_map(p);将设备树节点转为mappingret add_setting(p, map);将mapping转为setting并添加进pinctrl结构体中。这个在之前对client端的相关结构体介绍的时候也有讲解过下面来看看代码中是如何实现的
2.2.1 转mapping
\Linux-4.9.88\drivers\pinctrl\devicetree.c
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 启用时p-dev 可能没有从 DT 中实例化 */if (!np) {if (of_have_populated_dt())dev_dbg(p-dev, no of_node; not parsing pinctrl DT\n);return 0;}// 断言引脚控制设置ret dt_gpio_assert_pinctrl(p);if (ret) {dev_dbg(p-dev, failed to assert pinctrl setting: %d\n, ret);return ret;}// 获取节点引用of_node_get(np);/* 遍历每个状态 ID */for (state 0; ; state) {// 获取当前状态的引脚控制属性名如 pinctrl-0, pinctrl-1 等propname kasprintf(GFP_KERNEL, pinctrl-%d, state);prop of_find_property(np, propname, size); // 查找属性kfree(propname);if (!prop) {// 若状态为 0 但找不到属性说明没有定义if (state 0) {of_node_put(np);return -ENODEV;}break; // 没有更多状态}list prop-value; // 获取属性值列表size / sizeof(*list); // 计算列表中的项数// 从 pinctrl-names 中读取状态名ret of_property_read_string_index(np, pinctrl-names, state, statename);/** 如果没有在 pinctrl-names 中找到状态名将状态名设置为 pinctrl-** 属性名中的 ID 值。例如pinctrl-0 中的 0 可以作为状态名*/if (ret 0) {// 跳过 pinctrl- 的 8 个字符使用属性名中的 IDstatename prop-name 8;}// 遍历每个引用的引脚配置节点for (config 0; config size; config) {phandle be32_to_cpup(list); // 获取 phandle 值// 查找引脚配置节点 ---- 下图中标注 1np_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;}// 解析引脚配置节点并创建对应的映射 --- 下图中标注 2ret dt_to_map_one_config(p, statename, np_config);of_node_put(np_config);if (ret 0)goto err;}// 如果 DT 中没有项生成一个空状态表项if (!size) {ret dt_remember_dummy_state(p, statename);if (ret 0)goto err;}}return 0;err:pinctrl_dt_free_maps(p); // 如果有错误释放分配的映射return ret;
}来看看ret dt_to_map_one_config(p, statename, np_config);是如何解析设备树节点中的引脚转为map。
dt_to_map_one_config 函数用于解析一个设备树中的引脚配置节点 (np_config)并将其转换为内核 pinctrl 映射表。这个过程涉及查找引脚控制器设备 (pinctrl_dev)并调用设备特定的解析函数来生成映射表。 其中最重要的就是调用到了pinctrl_desc-pinctrl_ops-dt_node_to_map这个在之前的pincontroller的数据结构讲解中有提过Pinctrl子系统pinctrl_desc结构体进一步介绍。接下来看代码
\Linux-4.9.88\Linux-4.9.88\drivers\pinctrl\devicetree.cstatic 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;/* 查找包含 np_config 的引脚控制器节点 */np_pctldev of_node_get(np_config); // 获取配置节点的引用for (;;) {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); // 释放节点引用/* 如果未找到引脚控制器假设稍后会出现 */return -EPROBE_DEFER;}pctldev get_pinctrl_dev_from_of_node(np_pctldev); // 获取引脚控制器设备if (pctldev)break; // 找到引脚控制器设备退出循环/* 不要延迟对 hog 配置的探测避免循环依赖 */if (np_pctldev p-dev-of_node) {of_node_put(np_pctldev);return -ENODEV;}}of_node_put(np_pctldev); // 释放父节点的引用/** 调用引脚控制器驱动解析设备树节点并生成映射表项*/ops pctldev-desc-pctlops; // 获取引脚控制器的操作函数if (!ops-dt_node_to_map) {dev_err(p-dev, pctldev %s doesnt support DT\n,dev_name(pctldev-dev));return -ENODEV;}ret ops-dt_node_to_map(pctldev, np_config, map, num_maps); // 解析配置if (ret 0)return ret;/* 将映射表项保存以备后用 */return dt_remember_or_free_map(p, statename, pctldev, map, num_maps);
}查找引脚控制器设备函数首先查找与 np_config 对应的引脚控制器节点。通过向上遍历父节点找到第一个包含配置的 pinctrl_dev这是引脚控制器的核心设备。如果找不到合适的引脚控制器返回 -EPROBE_DEFER 表示稍后再次尝试探测。避免循环依赖在遍历父节点时如果发现父节点是当前设备自身hog 配置则返回 -ENODEV 以避免循环依赖。解析设备树节点找到引脚控制器设备后通过 pctlops-dt_node_to_map 调用设备特定的函数来解析 np_config 节点并生成映射表项。存储映射表项最后通过 dt_remember_or_free_map 函数将生成的映射表项存储到 pinctrl 结构体中以便后续使用。
ret ops-dt_node_to_map(pctldev, np_config, map, num_maps);调用的是哪些map函数呢这就得去Pincontroller的驱动程序中去看了因为这个函数是pinctrl_desc-pinctrl_ops的是属于Pincontroller的\Linux-4.9.88\drivers\pinctrl\freescale\pinctrl-imx.cpinctrl-imx.c
static const struct pinctrl_ops imx_pctrl_ops {.get_groups_count imx_get_groups_count,.get_group_name imx_get_group_name,.get_group_pins imx_get_group_pins,.pin_dbg_show imx_pin_dbg_show,.dt_node_to_map imx_dt_node_to_map, //就是这个函数.dt_free_map imx_dt_free_map,
};
static int imx_dt_node_to_map(struct pinctrl_dev *pctldev,struct device_node *np,struct pinctrl_map **map, unsigned *num_maps)
{struct imx_pinctrl *ipctl pinctrl_dev_get_drvdata(pctldev);const struct imx_pinctrl_soc_info *info ipctl-info;const struct imx_pin_group *grp;struct pinctrl_map *new_map;struct device_node *parent;int map_num 1;int i, j;/** 首先找到该节点的引脚组并检查是否需要为引脚创建配置映射*/grp imx_pinctrl_find_group_by_name(info, np-name);if (!grp) {dev_err(info-dev, unable to find group for node %s\n,np-name);return -EINVAL;}// 确定所需的映射数量if (info-flags IMX8_USE_SCU) {map_num grp-npins;} else {for (i 0; i grp-npins; i) {if (!(grp-pins[i].pin_conf.pin_memmap.config IMX_NO_PAD_CTL))map_num;}}// 分配内存存储新映射new_map kmalloc(sizeof(struct pinctrl_map) * map_num, GFP_KERNEL);if (!new_map)return -ENOMEM;*map new_map;*num_maps map_num;/* 创建复用映射 */parent of_get_parent(np);if (!parent) {kfree(new_map);return -EINVAL;}new_map[0].type PIN_MAP_TYPE_MUX_GROUP;new_map[0].data.mux.function parent-name;new_map[0].data.mux.group np-name;of_node_put(parent);/* 创建配置映射 */new_map;for (i j 0; i grp-npins; i) {if (info-flags IMX8_USE_SCU) {new_map[j].type PIN_MAP_TYPE_CONFIGS_PIN;new_map[j].data.configs.group_or_pin pin_get_name(pctldev, grp-pins[i].pin);new_map[j].data.configs.configs (unsigned long *)grp-pins[i].pin_conf.pin_scu.mux;new_map[j].data.configs.num_configs 2;j;} else if (!(grp-pins[i].pin_conf.pin_memmap.config IMX_NO_PAD_CTL)) {new_map[j].type PIN_MAP_TYPE_CONFIGS_PIN;new_map[j].data.configs.group_or_pin pin_get_name(pctldev, grp-pins[i].pin);new_map[j].data.configs.configs grp-pins[i].pin_conf.pin_memmap.config;new_map[j].data.configs.num_configs 1;j;}}dev_dbg(pctldev-dev, maps: function %s group %s num %d\n,(*map)-data.mux.function, (*map)-data.mux.group, map_num);return 0;
}imx_dt_node_to_map 函数用于将指定设备树节点 (np) 转换为 pinctrl_map 映射表并将其存储在 map 指针中供引脚控制子系统使用。此函数特定于 i.MX 系列硬件平台通过设备树节点的信息生成引脚配置和复用映射。 获取引脚组 使用 imx_pinctrl_find_group_by_name 函数根据节点名称 (np-name) 查找对应的引脚组 (grp)。 计算映射数量 如果 info-flags 标记中设置了 IMX8_USE_SCU则每个引脚都需要一个配置映射因此总映射数为 1 grp-npins。否则遍历每个引脚仅为需要配置的引脚增加映射数。 内存分配 使用 kmalloc 为映射数组分配内存并初始化 map 和 num_maps 指针。如果内存分配失败函数返回 -ENOMEM 错误。 创建复用映射 获取父节点检查其名称并为其创建复用 (MUX) 映射。将父节点的 name 作为 function当前节点的 name 作为 group。 创建配置映射 遍历引脚组中的每个引脚若符合条件则创建配置映射。使用 pin_get_name 函数获取引脚名称并设置相应的配置。IMX8_USE_SCU 标志影响配置内容如果未设置此标志则仅为未设置 IMX_NO_PAD_CTL 的引脚创建配置。 调试信息 使用 dev_dbg 输出映射的 function、group 和映射数量 (map_num) 以供调试。 2.2.2 mapping转setting
那么解析获取到mapping后就要去转化为setting回到create_pinctrl函数
\Linux-4.9.88\drivers\pinctrl\core.c
/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; // 存储返回值用于错误检查//...............// 将设备树映射到引脚控制结构体中ret pinctrl_dt_to_map(p);devname dev_name(dev); // 获取设备名称mutex_lock(pinctrl_maps_mutex); // 加锁以保护全局映射/* 遍历所有引脚控制映射以找到合适的映射 */for_each_maps(maps_node, i, map) {/* 检查映射是否属于当前设备 */if (strcmp(map-dev_name, devname))continue;// 将映射添加到引脚控制结构体中ret add_setting(p, map);}//...............}直接省略掉其它内容对于pinctrl_dt_to_map在上文讲到过那么接下来就是add_setting函数把每一个pinctrl_map转换为pinctrl_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);// 如果映射类型是 PIN_MAP_TYPE_DUMMY_STATE则无需添加设置直接返回if (map-type PIN_MAP_TYPE_DUMMY_STATE)return 0;// 为 pinctrl_setting 结构体分配内存用于存储此设置的信息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;// 获取映射中指定的 pinctrl_dev引脚控制设备setting-pctldev get_pinctrl_dev_from_devname(map-ctrl_dev_name);if (setting-pctldev NULL) {// 如果设备名称无法解析释放内存并判断是否需要延迟加载驱动kfree(setting);// 对于 hog 引脚不允许延迟加载防止循环依赖if (!strcmp(map-ctrl_dev_name, map-dev_name))return -ENODEV;// 设备驱动还未加载输出提示信息并返回 -EPROBE_DEFER 表示延迟加载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) {case PIN_MAP_TYPE_MUX_GROUP:// 如果是引脚复用组调用 pinmux_map_to_setting 进行设置转换ret pinmux_map_to_setting(map, setting);break;case PIN_MAP_TYPE_CONFIGS_PIN:case PIN_MAP_TYPE_CONFIGS_GROUP:// 如果是引脚或组的配置映射调用 pinconf_map_to_setting 进行设置转换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 或 pinconf_map_to_setting) 将映射转换为具体的引脚设置。 pinmux和pinconf在Pinccontroller结构体的讲解中也讲过
先来看pinmux_map_to_setting函数 将一个 pinctrl_map引脚控制映射条目中的复用功能映射转换为一个具体的 pinctrl_setting 设置用于配置指定设备的引脚复用功能。
设备和操作集获取获取 pinctrl_dev引脚控制设备和 pinmux_ops 操作集用于查询功能对应的引脚组并设置引脚复用。功能选择器索引转换将 map-data.mux.function 中指定的功能名称转换为功能选择器索引并存储在 setting-data.mux.func 中。功能支持组查询通过 pmxops-get_function_groups 函数获取该功能支持的引脚组列表和数量确保该功能可以选择特定的引脚组。引脚组验证如果映射条目中指定了具体的引脚组名称则检查该组是否在功能的支持列表中如果未指定则使用默认的第一个组。组选择器索引转换将引脚组名称转换为组选择器索引并存储在 setting-data.mux.group 中。返回设置将转换后的功能和组选择器索引存入 pinctrl_setting用于后续的引脚控制配置操作。如果过程中发生错误则返回相应的错误码。
\Linux-4.9.88\drivers\pinctrl\pinmux.c
int pinmux_map_to_setting(struct pinctrl_map const *map,struct pinctrl_setting *setting)
{// 获取 pinctrl_dev 设备和 pinmux_ops 操作集用于执行引脚复用操作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;// 如果设备不支持引脚复用操作返回错误if (!pmxops) {dev_err(pctldev-dev, does not support mux function\n);return -EINVAL;}// 将功能名称转换为功能选择器索引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; // 设置功能选择器// 查询该功能对应的引脚组获取组的列表和组数ret pmxops-get_function_groups(pctldev, setting-data.mux.func,groups, num_groups);if (ret 0) {dev_err(pctldev-dev, cant query groups for function %s\n,map-data.mux.function);return ret;}// 如果功能不支持任何引脚组返回错误if (!num_groups) {dev_err(pctldev-dev,function %s cant be selected on any group\n,map-data.mux.function);return -EINVAL;}// 如果映射指定了特定的引脚组验证该组是否存在于支持的组列表中if (map-data.mux.group) {group map-data.mux.group;ret match_string(groups, num_groups, group);if (ret 0) {dev_err(pctldev-dev,invalid group \%s\ for function \%s\\n,group, map-data.mux.function);return ret;}} else {// 如果未指定引脚组则使用默认的第一个组group groups[0];}// 将组名转换为组选择器索引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; // 成功返回 0
}再来看看pinconf_map_to_setting函数 将 pinctrl_map引脚控制映射中的引脚或引脚组的配置映射转换为 pinctrl_setting 设置用于对指定设备的引脚或引脚组进行特定的配置。 设备获取从 pinctrl_setting 中获取 pinctrl_dev 设备用于引脚或引脚组的配置映射。 配置类型判断根据 setting-type 判断配置类型。 单引脚配置 (PIN_MAP_TYPE_CONFIGS_PIN)根据引脚名称获取引脚索引并存储在 setting-data.configs.group_or_pin 字段中。引脚组配置 (PIN_MAP_TYPE_CONFIGS_GROUP)根据引脚组名称获取引脚组选择器索引并存储在 setting-data.configs.group_or_pin 字段中。 配置项存储将 map 中的配置数量和配置数组存储到 setting 中以便后续的配置应用。 返回状态如果成功执行映射和存储则返回 0如果引脚或组未找到或类型无效则返回相应的错误码。
int pinconf_map_to_setting(struct pinctrl_map const *map,struct pinctrl_setting *setting)
{// 获取与当前设置相关联的 pinctrl_dev 设备struct pinctrl_dev *pctldev setting-pctldev;int pin;// 根据配置类型执行相应的操作switch (setting-type) {case PIN_MAP_TYPE_CONFIGS_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;}// 将引脚索引存储在设置的 group_or_pin 字段中setting-data.configs.group_or_pin pin;break;case PIN_MAP_TYPE_CONFIGS_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_or_pin 字段中setting-data.configs.group_or_pin pin;break;default:// 如果配置类型无效返回 -EINVAL 错误码return -EINVAL;}// 设置配置项的数量和配置数组setting-data.configs.num_configs map-data.configs.num_configs;setting-data.configs.configs map-data.configs.configs;return 0; // 成功返回 0
}3.切换state情景分析
这一部分看下图简单了解一下就行了。 really_probepinctrl_bind_pinspinctrl_select_state/* 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:ret pinmux_enable_setting(setting);ret ops-set_mux(...);break;case PIN_MAP_TYPE_CONFIGS_PIN:case PIN_MAP_TYPE_CONFIGS_GROUP:ret pinconf_apply_setting(setting);ret ops-pin_config_group_set(...);break;default:ret -EINVAL;break;}
文章转载自: http://www.morning.lpsjs.com.gov.cn.lpsjs.com http://www.morning.wyrkp.cn.gov.cn.wyrkp.cn http://www.morning.bmlcy.cn.gov.cn.bmlcy.cn http://www.morning.bbyqz.cn.gov.cn.bbyqz.cn http://www.morning.tpdg.cn.gov.cn.tpdg.cn http://www.morning.rngyq.cn.gov.cn.rngyq.cn http://www.morning.bplqh.cn.gov.cn.bplqh.cn http://www.morning.c7507.cn.gov.cn.c7507.cn http://www.morning.sqfrg.cn.gov.cn.sqfrg.cn http://www.morning.qwfl.cn.gov.cn.qwfl.cn http://www.morning.drtgt.cn.gov.cn.drtgt.cn http://www.morning.snccl.cn.gov.cn.snccl.cn http://www.morning.ppgdp.cn.gov.cn.ppgdp.cn http://www.morning.sjgsh.cn.gov.cn.sjgsh.cn http://www.morning.kmwsz.cn.gov.cn.kmwsz.cn http://www.morning.kllzy.com.gov.cn.kllzy.com http://www.morning.jgykx.cn.gov.cn.jgykx.cn http://www.morning.rnzgf.cn.gov.cn.rnzgf.cn http://www.morning.mlpch.cn.gov.cn.mlpch.cn http://www.morning.chmcq.cn.gov.cn.chmcq.cn http://www.morning.qxycf.cn.gov.cn.qxycf.cn http://www.morning.nlmm.cn.gov.cn.nlmm.cn http://www.morning.wnbqy.cn.gov.cn.wnbqy.cn http://www.morning.bpmnz.cn.gov.cn.bpmnz.cn http://www.morning.drggr.cn.gov.cn.drggr.cn http://www.morning.tkcz.cn.gov.cn.tkcz.cn http://www.morning.rqqkc.cn.gov.cn.rqqkc.cn http://www.morning.fhkr.cn.gov.cn.fhkr.cn http://www.morning.tqjwx.cn.gov.cn.tqjwx.cn http://www.morning.yhywx.cn.gov.cn.yhywx.cn http://www.morning.zmtrk.cn.gov.cn.zmtrk.cn http://www.morning.psxfg.cn.gov.cn.psxfg.cn http://www.morning.xmttd.cn.gov.cn.xmttd.cn http://www.morning.nslwj.cn.gov.cn.nslwj.cn http://www.morning.ysckr.cn.gov.cn.ysckr.cn http://www.morning.qsyyp.cn.gov.cn.qsyyp.cn http://www.morning.gfnsh.cn.gov.cn.gfnsh.cn http://www.morning.rxxdk.cn.gov.cn.rxxdk.cn http://www.morning.yxgqr.cn.gov.cn.yxgqr.cn http://www.morning.qqrqb.cn.gov.cn.qqrqb.cn http://www.morning.gpnwq.cn.gov.cn.gpnwq.cn http://www.morning.ymjrg.cn.gov.cn.ymjrg.cn http://www.morning.dnphd.cn.gov.cn.dnphd.cn http://www.morning.tqrbl.cn.gov.cn.tqrbl.cn http://www.morning.gwsll.cn.gov.cn.gwsll.cn http://www.morning.mxxsq.cn.gov.cn.mxxsq.cn http://www.morning.dfltx.cn.gov.cn.dfltx.cn http://www.morning.cwgfq.cn.gov.cn.cwgfq.cn http://www.morning.sbjhm.cn.gov.cn.sbjhm.cn http://www.morning.whothehellami.com.gov.cn.whothehellami.com http://www.morning.qgwpx.cn.gov.cn.qgwpx.cn http://www.morning.wxfjx.cn.gov.cn.wxfjx.cn http://www.morning.qdlnw.cn.gov.cn.qdlnw.cn http://www.morning.hrtfz.cn.gov.cn.hrtfz.cn http://www.morning.jfbbq.cn.gov.cn.jfbbq.cn http://www.morning.tfwr.cn.gov.cn.tfwr.cn http://www.morning.ltywr.cn.gov.cn.ltywr.cn http://www.morning.tkqzr.cn.gov.cn.tkqzr.cn http://www.morning.kllzy.com.gov.cn.kllzy.com http://www.morning.ygrdb.cn.gov.cn.ygrdb.cn http://www.morning.trjp.cn.gov.cn.trjp.cn http://www.morning.mbrbg.cn.gov.cn.mbrbg.cn http://www.morning.kqgsn.cn.gov.cn.kqgsn.cn http://www.morning.rqfnl.cn.gov.cn.rqfnl.cn http://www.morning.mgnrc.cn.gov.cn.mgnrc.cn http://www.morning.rfbq.cn.gov.cn.rfbq.cn http://www.morning.nwmwp.cn.gov.cn.nwmwp.cn http://www.morning.qmncj.cn.gov.cn.qmncj.cn http://www.morning.nxtgb.cn.gov.cn.nxtgb.cn http://www.morning.kskpx.cn.gov.cn.kskpx.cn http://www.morning.wqwbj.cn.gov.cn.wqwbj.cn http://www.morning.dmrjx.cn.gov.cn.dmrjx.cn http://www.morning.xbmwm.cn.gov.cn.xbmwm.cn http://www.morning.wgbmj.cn.gov.cn.wgbmj.cn http://www.morning.ldynr.cn.gov.cn.ldynr.cn http://www.morning.zyrcf.cn.gov.cn.zyrcf.cn http://www.morning.fqljq.cn.gov.cn.fqljq.cn http://www.morning.hqwxm.cn.gov.cn.hqwxm.cn http://www.morning.xdjwh.cn.gov.cn.xdjwh.cn http://www.morning.rwmq.cn.gov.cn.rwmq.cn