pinctrl_desc结构体实现
文章目录
struct device_node *dev_np = pdev->dev.of_node;
struct device_node *np;
struct imx_pinctrl *ipctl;
struct resource *res;
struct pinctrl_desc *imx_pinctrl_desc;
/**
* @dev: a pointer back to containing device
* @base: the offset to the controller in virtual memory
*/
struct imx_pinctrl {
struct device *dev;
struct pinctrl_dev *pctl;
void __iomem *base;
void __iomem *input_sel_base;
const struct imx_pinctrl_soc_info *info;
};
imx_pinctrl_probe
int imx_pinctrl_probe(struct platform_device *pdev,
struct imx_pinctrl_soc_info *info)
{
// 获取设备节点
struct device_node *dev_np = pdev->dev.of_node;
struct device_node *np;
struct imx_pinctrl *ipctl;
struct resource *res;
struct pinctrl_desc *imx_pinctrl_desc;
int ret, i;
// 检查 pinctrl 信息是否正确
if (!info || !info->pins || !info->npins) {
dev_err(&pdev->dev, "wrong pinctrl info\n");
return -EINVAL;
}
info->dev = &pdev->dev;
// 分配内存给 imx_pinctrl_desc
imx_pinctrl_desc = devm_kzalloc(&pdev->dev, sizeof(*imx_pinctrl_desc),
GFP_KERNEL);
if (!imx_pinctrl_desc)
return -ENOMEM;
// 为驱动程序创建状态持有者等
ipctl = devm_kzalloc(&pdev->dev, sizeof(*ipctl), GFP_KERNEL);
if (!ipctl)
return -ENOMEM;
// 分配内存给 info->pin_regs
info->pin_regs = devm_kmalloc(&pdev->dev, sizeof(*info->pin_regs) *
info->npins, GFP_KERNEL);
if (!info->pin_regs)
return -ENOMEM;
// 初始化 info->pin_regs
for (i = 0; i < info->npins; i++) {
info->pin_regs[i].mux_reg = -1;
info->pin_regs[i].conf_reg = -1;
}
// 获取资源
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
ipctl->base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(ipctl->base))
return PTR_ERR(ipctl->base);
// 检查是否存在 fsl,input-sel 属性
if (of_property_read_bool(dev_np, "fsl,input-sel")) {
np = of_parse_phandle(dev_np, "fsl,input-sel", 0);
if (np) {
ipctl->input_sel_base = of_iomap(np, 0);
if (IS_ERR(ipctl->input_sel_base)) {
of_node_put(np);
dev_err(&pdev->dev,
"iomuxc input select base address not found\n");
return PTR_ERR(ipctl->input_sel_base);
}
} else {
dev_err(&pdev->dev, "iomuxc fsl,input-sel property not found\n");
return -EINVAL;
}
of_node_put(np);
}
// 初始化 imx_pinctrl_desc
imx_pinctrl_desc->name = dev_name(&pdev->dev);
imx_pinctrl_desc->pins = info->pins;
imx_pinctrl_desc->npins = info->npins;
imx_pinctrl_desc->pctlops = &imx_pctrl_ops;
imx_pinctrl_desc->pmxops = &imx_pmx_ops;
imx_pinctrl_desc->confops = &imx_pinconf_ops;
imx_pinctrl_desc->owner = THIS_MODULE;
// 调用 imx_pinctrl_probe_dt 函数解析设备树
ret = imx_pinctrl_probe_dt(pdev, info);
if (ret) {
dev_err(&pdev->dev, "fail to probe dt properties\n");
return ret;
}
ipctl->info = info;
ipctl->dev = info->dev;
platform_set_drvdata(pdev, ipctl);
ipctl->pctl = pinctrl_register(imx_pinctrl_desc, &pdev->dev, ipctl);
if (!ipctl->pctl) {
dev_err(&pdev->dev, "could not register IMX pinctrl driver\n");
return -EINVAL;
}
dev_info(&pdev->dev, "initialized IMX pinctrl driver\n");
return 0;
}
这段代码是 imx_pinctrl_probe 函数的实现。让我们逐行详细分析:
1.struct device_node *dev_np = pdev->dev.of_node; 这行代码获取设备结构体中的设备节点 (of_node)。
2.struct imx_pinctrl *ipctl; 声明了一个指向 struct imx_pinctrl 结构体的指针 ipctl,用于存储引脚控制器的相关信息。
3.struct resource *res; 声明了一个指向 struct resource 结构体的指针 res,用于获取设备的资源信息。
4.struct pinctrl_desc *imx_pinctrl_desc; 声明了一个指向 struct pinctrl_desc 结构体的指针 imx_pinctrl_desc,用于描述引脚控制器的相关信息。
5.if (!info || !info->pins || !info->npins) 检查 info 及其相关成员是否为空。如果为空,表示传递给函数的引脚控制器信息有误,函数返回 -EINVAL 表示无效参数。
6.info->dev = &pdev->dev; 将设备结构体指针赋值给引脚控制器信息的 dev 成员。
7.imx_pinctrl_desc = devm_kzalloc(&pdev->dev, sizeof(*imx_pinctrl_desc), GFP_KERNEL); 使用 devm_kzalloc 函数分配内存,大小为 sizeof(*imx_pinctrl_desc),并将返回的内存指针赋值给 imx_pinctrl_desc。如果分配失败,函数返回 -ENOMEM 表示内存不足。
8.ipctl = devm_kzalloc(&pdev->dev, sizeof(*ipctl), GFP_KERNEL); 类似地,使用 devm_kzalloc 函数分配内存,大小为 sizeof(*ipctl),并将返回的内存指针赋值给 ipctl。如果分配失败,函数返回 -ENOMEM 表示内存不足。
9.info->pin_regs = devm_kmalloc(&pdev->dev, sizeof(*info->pin_regs) * info->npins, GFP_KERNEL); 使用 devm_kmalloc 函数分配内存,大小为 sizeof(*info->pin_regs) * info->npins,并将返回的内存指针赋值给 info->pin_regs。如果分配失败,函数返回 -ENOMEM 表示内存不足。
10.for (i = 0; i < info->npins; i++) 循环遍历引脚控制器信息的每个引脚,将对应的寄存器地址初始化为 -1。
11.res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 使用 platform_get_resource 函数获取设备的内存资源信息,类型为 IORESOURCE_MEM,索引为 0。
12.ipctl->base = devm_ioremap_resource(&pdev->dev, res); 使用 devm_ioremap_resource 函数将设备的内存资源映射到虚拟地址空间,并将返回的映射后的地址赋值给 ipctl->base。如果映射失败,函数返回一个错误码。
13.if (of_property_read_bool(dev_np, “fsl,input-sel”)) 检查设备节点中是否存在名为 “fsl,input-sel” 的属性。
14.np = of_parse_phandle(dev_np, “fsl,input-sel”, 0); 使用 of_parse_phandle 函数获取与 “fsl,input-sel” 属性关联的设备节点。
15.if (np) 如果成功获取到设备节点,说明找到了输入选择寄存器的基地址。
16.ipctl->input_sel_base = of_iomap(np, 0); 使用 of_iomap 函数将设备节点的物理地址映射为虚拟地址,并将返回的映射后的地址赋值给 ipctl->input_sel_base。如果映射失败,函数返回一个错误码。
17.of_node_put(np); 释放之前获取的设备节点。
18.imx_pinctrl_desc->name = dev_name(&pdev->dev); 将设备的名称赋值给引脚控制器描述结构体的 name 成员。
19.imx_pinctrl_desc->pins = info->pins; 将引脚控制器信息结构体中的引脚数组赋值给引脚控制器描述结构体的 pins 成员。
20.imx_pinctrl_desc->npins = info->npins; 将引脚控制器信息结构体中的引脚数量赋值给引脚控制器描述结构体的 npins 成员。
21.imx_pinctrl_desc->pctlops = &imx_pctrl_ops; 将引脚控制器操作结构体赋值给引脚控制器描述结构体的 pctlops 成员。
22.imx_pinctrl_desc->pmxops = &imx_pmx_ops; 将引脚复用操作结构体赋值给引脚控制器描述结构体的 pmxops 成员。
23.imx_pinctrl_desc->confops = &imx_pinconf_ops; 将引脚配置操作结构体赋值给引脚控制器描述结构体的 confops 成员。
24.imx_pinctrl_desc->owner = THIS_MODULE; 将当前模块的所有者赋值给引脚控制器描述结构体的 owner 成员。
25.ret = imx_pinctrl_probe_dt(pdev, info); 调用 imx_pinctrl_probe_dt 函数,该函数用于从设备树中读取引脚控制器的配置信息,并进行相应的初始化操作。
26.ipctl->info = info; 将引脚控制器信息结构体赋值给 ipctl->info。
27.ipctl->dev = info->dev; 将设备结构体指针赋值给 ipctl->dev。
28.platform_set_drvdata(pdev, ipctl); 将 ipctl 指针作为私有数据存储在平台设备结构体中。
29.ipctl->pctl = pinctrl_register(imx_pinctrl_desc, &pdev->dev, ipctl); 注册引脚控制器驱动程序,并将返回的引脚控制器句柄赋值给 ipctl->pctl。如果注册失败,函数返回 -EINVAL。
30.dev_info(&pdev->dev, “initialized IMX pinctrl driver\n”); 打印初始化成功的信息。
31.return 0; 返回 0 表示函数执行成功。
这段代码的作用是进行引脚控制器的初始化操作。它根据传入的引脚控制器信息和设备树中的配置,进行相关资源的分配和初始化,并注册引脚控制器驱动程序。
imx_pinctrl_probe_dt
static int imx_pinctrl_probe_dt(struct platform_device *pdev,
struct imx_pinctrl_soc_info *info)
{
// 获取设备节点
struct device_node *np = pdev->dev.of_node;
struct device_node *child;
u32 nfuncs = 0;
u32 i = 0;
// 检查设备节点是否存在
if (!np)
return -ENODEV;
// 获取子节点数量
nfuncs = of_get_child_count(np);
if (nfuncs <= 0) {
dev_err(&pdev->dev, "no functions defined\n");
return -EINVAL;
}
// 分配内存给 info->functions
info->nfunctions = nfuncs;
info->functions = devm_kzalloc(&pdev->dev, nfuncs * sizeof(struct imx_pmx_func),
GFP_KERNEL);
if (!info->functions)
return -ENOMEM;
// 计算子节点数量
info->ngroups = 0;
for_each_child_of_node(np, child)
info->ngroups += of_get_child_count(child);
// 分配内存给 info->groups
info->groups = devm_kzalloc(&pdev->dev, info->ngroups * sizeof(struct imx_pin_group),
GFP_KERNEL);
if (!info->groups)
return -ENOMEM;
// 遍历子节点并解析函数
for_each_child_of_node(np, child)
imx_pinctrl_parse_functions(child, info, i++);
return 0;
}
这段代码是 imx_pinctrl_probe_dt 函数的实现。让我们逐行详细分析:
struct device_node *np = pdev->dev.of_node;这行代码获取设备结构体中的设备节点 (of_node)。
struct device_node *child;声明了一个指向 struct device_node 结构体的指针 child,用于遍历设备节点的子节点。
u32 nfuncs = 0; 声明了一个无符号 32 位整数变量 nfuncs,用于存储子节点的数量。
u32 i = 0; 声明了一个无符号 32 位整数变量 i,用于迭代子节点的索引。
if (!np) return -ENODEV; 如果设备节点为空,则返回 -ENODEV 表示设备不存在。
nfuncs = of_get_child_count(np); 使用 of_get_child_count 函数获取设备节点的子节点数量。
if (nfuncs <= 0) 如果子节点数量小于等于 0,表示没有定义函数信息,函数返回 -EINVAL 表示参数无效。
info->nfunctions = nfuncs; 将子节点数量赋值给引脚控制器信息结构体的 nfunctions 成员。
info->functions = devm_kzalloc(&pdev->dev, nfuncs * sizeof(struct imx_pmx_func), GFP_KERNEL); 使用 devm_kzalloc 函数分配内存,大小为 nfuncs * sizeof(struct imx_pmx_func),并将返回的内存指针赋值给引脚控制器信息结构体的 functions 成员。如果分配失败,函数返回 -ENOMEM 表示内存不足。
info->ngroups = 0; 将引脚控制器信息结构体的 ngroups 成员初始化为 0。
for_each_child_of_node(np, child) 遍历设备节点的每个子节点。
info->ngroups += of_get_child_count(child); 使用 of_get_child_count 函数获取当前子节点的子节点数量,并将其累加到 info->ngroups 中,计算引脚组的总数。
info->groups = devm_kzalloc(&pdev->dev, info->ngroups * sizeof(struct imx_pin_group), GFP_KERNEL); 使用 devm_kzalloc 函数分配内存,大小为 info->ngroups * sizeof(struct imx_pin_group),并将返回的内存指针赋值给引脚控制器信息结构体的 groups 成员。如果分配失败,函数返回 -ENOMEM 表示内存不足。
for_each_child_of_node(np, child) 再次遍历设备节点的每个子节点。
imx_pinctrl_parse_functions(child, info, i++); 调用 imx_pinctrl_parse_functions 函数解析当前子节点的函数信息,并将解析得到的函数和引脚组信息存储到引脚控制器信息结构体的相应数组中。
return 0; 返回 0 表示函数执行成功。
这段代码的作用是解析设备树中的引脚控制器相关信息。它遍历设备节点的子节点,获取函数和引脚组的数量,并分配内存存储函数和引脚组的信息。然后,它调用 imx_pinctrl_parse_functions 函数解析每个子节点的函数和引脚组信息,并将其存储在引脚控制器信息结构体中。最后,函数返回执行成功的标志。
imx_pinctrl_parse_functions
static int imx_pinctrl_parse_functions(struct device_node *np,
struct imx_pinctrl_soc_info *info,
u32 index)
{
// 获取设备节点的子节点
struct device_node *child;
// 获取函数信息
struct imx_pmx_func *func;
// 获取引脚组信息
struct imx_pin_group *grp;
// 初始化索引
u32 i = 0;
// 打印函数解析信息
dev_dbg(info->dev, "解析函数(%d): %s\n", index, np->name);
// 获取函数信息
func = &info->functions[index];
// 初始化函数名称
func->name = np->name;
// 获取子节点数量
func->num_groups = of_get_child_count(np);
// 检查是否存在引脚组
if (func->num_groups == 0) {
dev_err(info->dev, "在 %s 中未定义引脚组\n", np->full_name);
return -EINVAL;
}
// 分配内存给函数的引脚组
func->groups = devm_kzalloc(info->dev,
func->num_groups * sizeof(char *), GFP_KERNEL);
// 遍历子节点并解析引脚组
for_each_child_of_node(np, child) {
// 将子节点名称添加到函数的引脚组中
func->groups[i] = child->name;
// 获取引脚组信息
grp = &info->groups[info->grp_index++];
// 解析引脚组
imx_pinctrl_parse_groups(child, grp, info, i++);
}
return 0;
}
这段代码是 imx_pinctrl_parse_functions 函数的实现。让我们逐行详细分析:
struct device_node *child;声明了一个指向 struct device_node 结构体的指针 child,用于遍历设备节点的子节点。
struct imx_pmx_func *func; 声明了一个指向 struct imx_pmx_func 结构体的指针 func,用于存储函数信息。
struct imx_pin_group *grp; 声明了一个指向 struct imx_pin_group 结构体的指针 grp,用于存储引脚组信息。
u32 i = 0; 声明了一个无符号 32 位整数变量 i,用于迭代子节点的索引。
dev_dbg(info->dev, “parse function(%d): %s\n”, index, np->name); 打印调试信息,显示当前正在解析的函数的索引和名称。
func = &info->functions[index]; 将函数数组中对应索引的元素赋值给 func,获取当前正在解析的函数信息。
func->name = np->name; 将设备节点的名称赋值给函数信息结构体的 name 成员。
func->num_groups = of_get_child_count(np); 使用 of_get_child_count 函数获取当前函数节点的子节点数量,并将其赋值给函数信息结构体的 num_groups 成员。
if (func->num_groups == 0) 如果子节点数量为 0,表示没有定义引脚组,函数返回 -EINVAL 表示参数无效。
func->groups = devm_kzalloc(info->dev, func->num_groups * sizeof(char *), GFP_KERNEL); 使用 devm_kzalloc 函数分配内存,大小为 func->num_groups * sizeof(char *),并将返回的内存指针赋值给函数信息结构体的 groups 成员。如果分配失败,函数返回 -ENOMEM 表示内存不足。
for_each_child_of_node(np, child) 遍历当前函数节点的每个子节点。
func->groups[i] = child->name; 将当前子节点的名称赋值给函数信息结构体的 groups 数组的相应元素。
grp = &info->groups[info->grp_index++]; 将引脚组信息数组中对应索引的元素赋值给 grp,获取当前正在解析的引脚组信息。
imx_pinctrl_parse_groups(child, grp, info, i++); 调用 imx_pinctrl_parse_groups 函数解析当前子节点的引脚组信息,并将解析得到的信息存储在引脚组信息结构体中。
return 0; 返回 0 表示函数执行成功。
这段代码的作用是解析设备树中函数节点的信息。它获取函数节点的名称和子节点的数量,并分配内存存储函数名称和引脚组名称。然后,它遍历子节点,将子节点的名称存储到函数信息结构体的引脚组数组中,并调用 imx_pinctrl_parse_groups 函数解析引脚组的信息。最后,函数返回执行成功的标志。
imx_pinctrl_parse_groups
/*
* Each pin represented in fsl,pins consists of 5 u32 PIN_FUNC_ID and
* 1 u32 CONFIG, so 24 types in total for each pin.
*/
#define FSL_PIN_SIZE 24
#define SHARE_FSL_PIN_SIZE 20
static int imx_pinctrl_parse_groups(struct device_node *np,
struct imx_pin_group *grp,
struct imx_pinctrl_soc_info *info,
u32 index)
{
// 定义变量
int size, pin_size;
const __be32 *list;
int i;
u32 config;
// 打印组解析信息
dev_dbg(info->dev, "group(%d): %s\n", index, np->name);
// 根据标志位确定 pin_size 的值
if (info->flags & SHARE_MUX_CONF_REG)
pin_size = SHARE_FSL_PIN_SIZE;
else
pin_size = FSL_PIN_SIZE;
// 初始化组的名称
grp->name = np->name;
/*
* the binding format is fsl,pins = <PIN_FUNC_ID CONFIG ...>,
* do sanity check and calculate pins number
*/
// 获取 fsl,pins 属性的值
list = of_get_property(np, "fsl,pins", &size);
if (!list) {
dev_err(info->dev, "在节点 %s 中找不到 fsl,pins 属性\n", np->full_name);
return -EINVAL;
}
// 检查 fsl,pins 属性的有效性
if (!size || size % pin_size) {
dev_err(info->dev, "节点 %s 中的 fsl,pins 属性无效\n", np->full_name);
return -EINVAL;
}
// 计算引脚数量并分配内存
grp->npins = size / pin_size;
grp->pins = devm_kzalloc(info->dev, grp->npins * sizeof(struct imx_pin),
GFP_KERNEL);
grp->pin_ids = devm_kzalloc(info->dev, grp->npins * sizeof(unsigned int),
GFP_KERNEL);
if (!grp->pins || ! grp->pin_ids)
return -ENOMEM;
// 遍历每个引脚并解析
for (i = 0; i < grp->npins; i++) {
// 获取引脚的 mux_reg 和 conf_reg
u32 mux_reg = be32_to_cpu(*list++);
u32 conf_reg;
unsigned int pin_id;
struct imx_pin_reg *pin_reg;
struct imx_pin *pin = &grp->pins[i];
// 如果标志位 ZERO_OFFSET_VALID 未设置且 mux_reg 为 0,则将 mux_reg 设置为 -1
if (!(info->flags & ZERO_OFFSET_VALID) && !mux_reg)
mux_reg = -1;
// 根据标志位 SHARE_MUX_CONF_REG 确定 conf_reg 的值
if (info->flags & SHARE_MUX_CONF_REG) {
conf_reg = mux_reg;
} else {
conf_reg = be32_to_cpu(*list++);
// 如果标志位 ZERO_OFFSET_VALID 未设置且 conf_reg 为 0,则将 conf_reg 设置为 -1
if (!(info->flags & ZERO_OFFSET_VALID) && !conf_reg)
conf_reg = -1;
}
// 计算引脚的 pin_id,并获取引脚的寄存器信息
pin_id = (mux_reg != -1) ? mux_reg / 4 : conf_reg / 4;
pin_reg = &info->pin_regs[pin_id];
pin->pin = pin_id;
grp->pin_ids[i] = pin_id;
pin_reg->mux_reg = mux_reg;
pin_reg->conf_reg = conf_reg;
pin->input_reg = be32_to_cpu(*list++);
pin->mux_mode = be32_to_cpu(*list++);
pin->input_val = be32_to_cpu(*list++);
// SION 位在 mux 寄存器中
config = be32_to_cpu(*list++);
if (config & IMX_PAD_SION)
pin->mux_mode |= IOMUXC_CONFIG_SION;
pin->config = config & ~IMX_PAD_SION;
// 打印引脚的信息
dev_dbg(info->dev, "%s: 0x%x 0x%08lx", info->pins[pin_id].name,
pin->mux_mode, pin->config);
}
return 0;
}
imx6ul_pinctrl_probe 函数就是I.MX6ULL 这个 SOC 的 PIN 配置入口函数。以此为入口,如图所示的函数调用路径:
函数 imx_pinctrl_parse_groups 负责获取设备树中关于 PIN 的配置信息,也就是我们前面分析的那 6 个 u32 类型的值。
这段代码是 imx_pinctrl_parse_groups 函数的实现。让我们逐行详细分析:
int size, pin_size; 声明了两个整型变量 size 和 pin_size,用于存储属性值的大小和 PIN 的大小。
const __be32 *list; 声明了一个指向 __be32 类型的指针 list,用于存储属性值的指针。
int i; 声明了一个整型变量 i,用于迭代循环。
u32 config; 声明了一个无符号 32 位整数变量 config,用于存储配置信息。
dev_dbg(info->dev, “group(%d): %s\n”, index, np->name); 打印调试信息,显示当前正在解析的引脚组的索引和名称。
if (info->flags & SHARE_MUX_CONF_REG) 检查引脚控制器信息结构体中的标志位 SHARE_MUX_CONF_REG 是否被设置,以确定 PIN 的大小。
pin_size = SHARE_FSL_PIN_SIZE; 如果标志位被设置,将 PIN 的大小设置为 SHARE_FSL_PIN_SIZE。
else pin_size = FSL_PIN_SIZE; 如果标志位未被设置,将 PIN 的大小设置为 FSL_PIN_SIZE。
grp->name = np->name; 将设备节点的名称赋值给引脚组信息结构体的 name 成员。
list = of_get_property(np, “fsl,pins”, &size); 使用 of_get_property 函数获取设备节点的属性 “fsl,pins” 的值,并将其指针赋值给 list,同时获取属性值的大小赋值给 size。
if (!list) 如果属性值为空指针,表示设备节点缺少 “fsl,pins” 属性,函数返回 -EINVAL 表示参数无效。
if (!size || size % pin_size) 如果属性值的大小为 0 或者不是 PIN 大小的整数倍,表示 “fsl,pins” 属性值无效,函数返回 -EINVAL。
grp->npins = size / pin_size; 将属性值的大小除以 PIN 大小,得到引脚组中 PIN 的数量,并赋值给引脚组信息结构体的 npins 成员。
grp->pins = devm_kzalloc(info->dev, grp->npins * sizeof(struct imx_pin), GFP_KERNEL); 使用 devm_kzalloc 函数分配内存,大小为 grp->npins * sizeof(struct imx_pin),并将返回的内存指针赋值给引脚组信息结构体的 pins 成员。如果分配失败,函数返回 -ENOMEM 表示内存不足。
grp->pin_ids = devm_kzalloc(info->dev, grp->npins * sizeof(unsigned int), GFP_KERNEL); 类似地,使用 devm_kzalloc 函数分配内存,大小为 grp->npins * sizeof(unsigned int),并将返回的内存指针赋值给引脚组信息结构体的 pin_ids 成员。如果分配失败,函数返回 -ENOMEM 表示内存不足。
for (i = 0; i < grp->npins; i++) 循环遍历引脚组中的每个 PIN。
u32 mux_reg = be32_to_cpu(*list++); 从属性值中读取一个 u32 值,并将其赋值给 mux_reg,同时将指针 list 向后移动。
u32 conf_reg = be32_to_cpu(*list++); 类似地,从属性值中读取一个 u32 值,并将其赋值给 conf_reg,同时将指针 list 向后移动。
unsigned int pin_id; 声明了一个无符号整数变量 pin_id,用于存储 PIN 的 ID。
struct imx_pin_reg *pin_reg; 声明了一个指向 struct imx_pin_reg 结构体的指针 pin_reg,用于存储 PIN 寄存器的信息。
struct imx_pin *pin = &grp->pins[i]; 声明了一个指向 struct imx_pin 结构体的指针 pin,用于表示当前循环迭代的 PIN。
if (!(info->flags & ZERO_OFFSET_VALID) && !mux_reg) mux_reg = -1; 检查引脚控制器信息结构体中的标志位 ZERO_OFFSET_VALID 是否未设置,并且 mux_reg 的值为 0。如果满足条件,将 mux_reg 的值设为 -1。
if (info->flags & SHARE_MUX_CONF_REG) conf_reg = mux_reg; 如果引脚控制器信息结构体中的标志位 SHARE_MUX_CONF_REG 被设置,将 conf_reg 的值设为 mux_reg 的值。
else { conf_reg = be32_to_cpu(*list++); if (!(info->flags & ZERO_OFFSET_VALID) && !conf_reg) conf_reg = -1; } 否则,从属性值中读取一个 u32 值,并将其赋值给 conf_reg,同时将指针 list 向后移动。如果 conf_reg 的值为 0,且标志位 ZERO_OFFSET_VALID 未设置,则将 conf_reg 的值设为 -1。
pin_id = (mux_reg != -1) ? mux_reg / 4 : conf_reg / 4; 根据 mux_reg 和 conf_reg 的值计算 PIN 的 ID。
pin_reg = &info->pin_regs[pin_id]; 将 PIN 寄存器数组中对应索引的元素赋值给 pin_reg,获取当前 PIN 对应的寄存器信息。
pin->pin = pin_id; 将 PIN 的 ID 赋值给 PIN 信息结构体的 pin 成员。
grp->pin_ids[i] = pin_id; 将 PIN 的 ID 存储到引脚组信息结构体的 pin_ids 数组中。
pin_reg->mux_reg = mux_reg; 将 mux_reg 的值赋值给 PIN 寄存器结构体的 mux_reg 成员。
pin_reg->conf_reg = conf_reg;
将 conf_reg 的值赋值给 PIN 寄存器结构体的 conf_reg 成员。
pin->input_reg = be32_to_cpu(*list++); 从属性值中读取一个 u32 值,并将其赋值给 PIN 信息结构体的 input_reg 成员。
pin->mux_mode = be32_to_cpu(*list++); 类似地,从属性值中读取一个 u32 值,并将其赋值给 PIN 信息结构体的 mux_mode 成员。
pin->input_val = be32_to_cpu(*list++); 类似地,从属性值中读取一个 u32 值,并将其赋值给 PIN 信息结构体的 input_val 成员。
config = be32_to_cpu(*list++); 从属性值中读取一个 u32 值,并将其赋值给 config。
if (config & IMX_PAD_SION) pin->mux_mode |= IOMUXC_CONFIG_SION; 检查 config 的值中是否设置了 IMX_PAD_SION 标志位,如果设置了,将 IOMUXC_CONFIG_SION 添加到 PIN 的 mux_mode 成员中。
pin->config = config & ~IMX_PAD_SION; 将 config 的值与 IMX_PAD_SION 的逻辑反操作,赋值给 PIN 的 config 成员,以清除 IMX_PAD_SION 标志位。
dev_dbg(info->dev, “%s: 0x%x 0x%08lx”, info->pins[pin_id].name, pin->mux_mode, pin->config); 打印调试信息,显示 PIN 的名称、mux_mode 的值和 config 的值。
return 0; 返回 0 表示函数执行成功。
这段代码的作用是解析设备树中引脚组的信息。它获取属性 “fsl,pins” 的值,并根据该值解析每个 PIN 的信息,包括寄存器地址、配置和模式等。然后,它将解析得到的 PIN 信息存储在引脚组信息结构体的相应数组中,并返回执行成功的标志。