瑞芯微RK3568芯片是一款定位中高端的通用型SOC,采用22nm制程工艺,搭载一颗四核Cortex-A55处理器和Mali G52 2EE 图形处理器。RK3568 支持4K 解码和 1080P 编码,支持SATA/PCIE/USB3.0 外围接口。RK3568内置独立NPU,可用于轻量级人工智能应用。RK3568 支持安卓 11 和 linux 系统,主要面向物联网网关、NVR 存储、工控平板、工业检测、工控盒、卡拉 OK、云终端、车载中控等行业。
【公众号】迅为电子
【粉丝群】824412014(加群获取驱动文档+例程)
【视频观看】嵌入式学习之Linux驱动(第十一篇 pinctrl 子系统_全新升级)_基于RK3568
【购买链接】迅为RK3568开发板瑞芯微Linux安卓鸿蒙ARM核心板人工智能AI主板
第123章dt_node_to_map函数分析
设备树(Device Tree)中存放的是对硬件设备信息的描述,包含了硬件设备的配置和连接信息,例如在pinctrl节点中的引脚的配置和映射关系。而rockchip_dt_node_to_map 函数的作用就是根据设备树中的节点信息,生成对应的引脚映射数组。这个映射数组将描述硬件功能(如复用功能和配置信息)与设备树中的引脚信息进行绑定。
dt_node_to_map函数已经在122.4.1小节的pinctrl_ops函数操作集中进行了简单的讲解,现在将对该函数进行详细的介绍。该函数的具体实现在内核源码的“drivers/pinctrl/pinctrl-rockchip.c”文件中,在讲解该函数之前需要先对struct pinctrl_map结构体进行介绍,该结构体定义在内核源码的“include/linux/pinctrl/machine.h”目录下,具体内容如下所示:
struct pinctrl_map {
const char *dev_name; // 设备名称
const char *name; // 映射名称
enum pinctrl_map_type type; // 映射类型
const char *ctrl_dev_name; // 控制设备名称
union {
struct pinctrl_map_mux mux; // 复用映射数据
struct pinctrl_map_configs configs; // 配置映射数据
} data;
};
该结构体用于在引脚控制器中定义引脚的映射关系。通过映射类型的不同,可以将引脚与具体的复用功能或配置信息关联起来,从而实现引脚的配置和控制。然后来看rockchip_dt_node_to_map函数,该函数的具体内容如下所示:
static int rockchip_dt_node_to_map(struct pinctrl_dev *pctldev,
struct device_node *np,
struct pinctrl_map **map, unsigned *num_maps)
{
struct rockchip_pinctrl *info = pinctrl_dev_get_drvdata(pctldev); // 获取引脚控制器的私有数据指针
const struct rockchip_pin_group *grp; // 引脚组指针
struct device *dev = info->dev; // 设备指针
struct pinctrl_map *new_map; // 新的引脚映射数组
struct device_node *parent; // 父节点指针
int map_num = 1; // 映射数量,默认为1
int i;
/* 查找引脚组 */
grp = pinctrl_name_to_group(info, np->name); // 根据节点名称查找对应的引脚组
if (!grp) {
dev_err(dev, "unable to find group for node %pOFn\n", np); // 如果找不到引脚组,打印错误信息
return -EINVAL;
}
map_num += grp->npins; // 计算映射数量,包括复用映射和配置映射
new_map = kcalloc(map_num, sizeof(*new_map), 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 = 0; i < grp->npins; i++) {
new_map[i].type = PIN_MAP_TYPE_CONFIGS_PIN; // 设置映射类型为配置映射
new_map[i].data.configs.group_or_pin =
pin_get_name(pctldev, grp->pins[i]); // 引脚组或引脚名称为引脚组中的引脚名称
new_map[i].data.configs.configs = grp->data[i].configs; // 配置信息数组为引脚组中该引脚的配置信息
new_map[i].data.configs.num_configs = grp->data[i].nconfigs; // 配置信息数量为引脚组中该引脚的配置数量
}
dev_dbg(dev, "maps: function %s group %s num %d\n",
(*map)->data.mux.function, (*map)->data.mux.group, map_num); // 打印调试信息,显示创建的引脚映射的功能名称、组名和数量
return 0; // 返回成功标志
}
第14-20行:函数根据设备节点的名称使用pinctrl_name_to_group函数查找与该节点对应的引脚组。如果找不到引脚组,则函数打印错误消息并返回EINVAL错误代码。
第22行:函数根据引脚组的引脚数量计算需要创建的映射数量。映射数量包括复用映射和配置映射。
第24-26行:函数使用kcalloc函数为映射数组(new_map)分配内存空间。分配的大小为映射数量乘以每个映射的大小。如果内存分配失败,函数将返回ENOMEM错误代码。
第28-29行:函数将分配的映射数组(new_map)和映射数量(map_num)通过输出参数map和num_maps返回给调用者。
第31-40行:函数首先获取设备节点的父节点,并将其作为复用映射的功能名称。然后,函数设置第一个映射的类型为PIN_MAP_TYPE_MUX_GROUP,并将父节点的名称作为映射的数据。同时,将设备节点的名称作为映射的组名。最后,函数使用of_node_put释放父节点的引用计数。
第42-52行:函数遍历引脚组的引脚数组,并为每个引脚创建一个配置映射。函数设置映射的类型为PIN_MAP_TYPE_CONFIGS_PIN,并将引脚的名称作为映射的数据。同时,将引脚组中该引脚的配置信息和配置数量设置为映射的配置数据。函数使用pin_get_name函数获取引脚的名称。
rockchip_dt_node_to_map函数根据设备节点的信息创建引脚映射,包括复用映射和配置映射。复用映射用于将引脚组的功能与父节点的功能关联起来,而配置映射用于将引脚的配置信息与引脚的名称关联起来。这些映射将用于配置引脚控制器,以确保引脚在系统中正确地配置和使用。这个函数在设备树解析过程中被调用,以便为每个设备节点创建相应的引脚映射。
到这里关于pinctrl子系统第一阶段的讲解到这里就结束了,为了帮助大家整合讲解过的知识点,作者绘制了以下思维导图:
注:该思维导图的存放路径为iTOP-RK3568开发板【底板V1.7版本】\03_【iTOP-RK3568开发板】指南教程\02_Linux驱动配套资料\04_Linux驱动例程\05_思维导图\01_pinctrl 阶段1.jpg
图 123-1
大家可以根据该思维导图,对上面章节的内容进行梳理,从而真正理解pinctrl子系统框架。