pin function和pin group:iomuxc节点解析始末
设备树iomuxc节点层次
-
iomuxc
-
function
-
group
fsl,pins = < xxx xxx >;
…
-
group
-
…
-
-
function
-
…
-
层次关系说明
- iomuxc:pinctrl子系统的设备树节点
- function:芯片具有外设功能,一个 功能对应一个或多个IO组配置信息
- 比如说i2c有几个功能,一个功能用一组IO引脚,另一个功能用另一组引脚
- group:IO组中每个IO的配置信息
- fsl,pins:imx6ull中,功能和IO组的标识属性
imx_pinctrl_probe_dt()函数
drivers/pinctrl/freescale/pinctrl-imx.c
static int imx_pinctrl_probe_dt(struct platform_device *pdev,
struct imx_pinctrl *ipctl)
{
//iomux节点
struct device_node *np = pdev->dev.of_node;
struct device_node *child;
struct pinctrl_dev *pctl = ipctl->pctl;
//用于判断iomuxc节点下面有几个fuction
flat_funcs = imx_pinctrl_dt_is_flat_functions(np);
//如果返回的是true说明只有一个function
if (flat_funcs) {
nfuncs = 1;
} else {
nfuncs = of_get_child_count(np);
if (nfuncs == 0) {
dev_err(&pdev->dev, "no functions defined\n");
return -EINVAL;
}
}
//创建func_desc,并加入func的基数树中
for (i = 0; i < nfuncs; i++) {
struct function_desc *function;
function = devm_kzalloc(&pdev->dev, sizeof(*function),
GFP_KERNEL);
if (!function)
return -ENOMEM;
mutex_lock(&ipctl->mutex);
radix_tree_insert(&pctl->pin_function_tree, i, function);
//在pin_function_tree中插入一个function_desc节点
mutex_unlock(&ipctl->mutex);
}
pctl->num_functions = nfuncs;
ipctl->group_index = 0;
if (flat_funcs) {
//获取function的子节点数量,即group数量
pctl->num_groups = of_get_child_count(np);
} else {
pctl->num_groups = 0;
for_each_child_of_node(np, child)
pctl->num_groups += of_get_child_count(child);
}
if (flat_funcs) {
imx_pinctrl_parse_functions(np, ipctl, 0);
} else {
i = 0;
for_each_child_of_node(np, child)
imx_pinctrl_parse_functions(child, ipctl, i++);
}
imx_pinctrl_dt_is_flat_functions()函数
drivers/pinctrl/freescale/pinctrl-imx.c
static bool imx_pinctrl_dt_is_flat_functions(struct device_node *np)
{
struct device_node *function_np;
struct device_node *pinctrl_np;
for_each_child_of_node(np, function_np) {//遍历一下device_node(iomuxc)的子节点
//判断一下这些子节点当中有没有fsl,pins属性,也就是说判断一下fuction节点下是否有这个属性,如果fuction下有的话说明设备只有一个fuction,因为fuction和group合并了
if (of_property_read_bool(function_np, "fsl,pins"))
return true;
//判断一下这些子节点的子节点当中有没有fsl,pins属性,也就是说判断一下group节点下是否有这个属性
for_each_child_of_node(function_np, pinctrl_np) {
if (of_property_read_bool(pinctrl_np, "fsl,pins"))
return false;
}
}
return true;
}
imx_pinctrl_parse_functions()函数
drivers/pinctrl/freescale/pinctrl-imx.c
iomuxc节点的device_node结构体指针, ipctl, 0
static int imx_pinctrl_parse_functions(struct device_node *np,
struct imx_pinctrl *ipctl,
u32 index)
{
struct pinctrl_dev *pctl = ipctl->pctl;
struct device_node *child;
struct function_desc *func;
struct group_desc *grp;//专门用来描述每一个group下的引脚信息的
u32 i = 0;
//从基数树当中提出之前保存的function指针
func = pinmux_generic_get_function(pctl, index);
...
func->name = np->name;//获取device_node中的name变量,其实就是compatible属性值
func->num_group_names = of_get_child_count(np);//获取iomuxc的子节点数量,在这里就是获取group节点的数量
...
//为group的名字分配内存,分配group数量的char*数组
func->group_names = devm_kcalloc(ipctl->dev, func->num_group_names,
sizeof(char *), GFP_KERNEL);
//遍历每一个子节点,生成对应的group_desc,并加入pin_group_tree基数树
for_each_child_of_node(np, child) {
//func中的group_names就是来记录group名的,比如说设备树上的uartgrp1
func->group_names[i] = child->name;
grp = devm_kzalloc(ipctl->dev, sizeof(struct group_desc),
GFP_KERNEL);
mutex_lock(&ipctl->mutex);
//将grp_desc结构体记录在基数树当中,grp的编号就是group_index
radix_tree_insert(&pctl->pin_group_tree,
ipctl->group_index++, grp);
mutex_unlock(&ipctl->mutex);
imx_pinctrl_parse_groups(child, grp, ipctl, i++);
}
return 0;
}
imx_pinctrl_parse_groups()函数
static int imx_pinctrl_parse_groups(struct device_node *np,
struct group_desc *grp,
struct imx_pinctrl *ipctl,
u32 index)
{
const struct imx_pinctrl_soc_info *info = ipctl->info;//存放引脚编号和名字的结构体
int size, pin_size;
const __be32 *list, **list_p;
u32 config;
int i;
if (info->flags & IMX8_USE_SCU)//因为info->flag没有赋值过因此为0
pin_size = FSL_IMX8_PIN_SIZE;
else if (info->flags & SHARE_MUX_CONF_REG)
pin_size = FSL_PIN_SHARE_SIZE;
else
//24,因为每一个引脚信息是一个宏和一个十六进制数,而宏又是五个十六进制数,一个十六进制数站4个字节,因此就是24个字节
pin_size = FSL_PIN_SIZE;
grp->name = np->name;//name是指iomuxc的子节点名
list = of_get_property(np, "fsl,pins", &size);//获取到fsl,pins属性的长度到size,返回grp引脚具体的配置值都在list当中
...
list_p = &list;
...
/*该组引脚的配置个数*/
//用fsl,pins的总长度除以每一个引脚的长度
grp->num_pins = size / pin_size;
//为每一个引脚分配一个imx_pin结构体,并分配内存,保存在data变量里
grp->data = devm_kcalloc(ipctl->dev,
grp->num_pins, sizeof(struct imx_pin),
GFP_KERNEL);
//为pins分配sizeof(unsigned int)*num_pins的内存,存pin的编号
grp->pins = devm_kcalloc(ipctl->dev,
grp->num_pins, sizeof(unsigned int),
GFP_KERNEL);
...
//遍历grp当中的每一个pin并保存其属性信息
for (i = 0; i < grp->num_pins; i++) {
//for循环依次获取data当中的imx_pin的地址
struct imx_pin *pin = &((struct imx_pin *)(grp->data))[i];
if (info->flags & IMX8_USE_SCU)//flags没有定义因此为0
imx_pinctrl_parse_pin_scu(ipctl, &grp->pins[i],
pin, list_p, config);
else
imx_pinctrl_parse_pin_mem(ipctl, &grp->pins[i],
pin, list_p, config);
}
return 0;
}
imx_pinctrl_parse_pin_mem()函数
drivers/pinctrl/freescale/pinctrl-memmap.c
int imx_pinctrl_parse_pin_mem(struct imx_pinctrl *ipctl,
unsigned int *grp_pin_id, struct imx_pin *pin,
const __be32 **list_p, u32 generic_config)
{
struct imx_pin_memmap *pin_memmap = &pin->pin_conf.pin_memmap;
const struct imx_pinctrl_soc_info *info = ipctl->info;
u32 mux_reg = be32_to_cpu(*((*list_p)++));//be32这个函数是用来大小端兼容,list_p第一个是mux寄存器的偏移地址,++之后指向下一个元素就是conf_reg
u32 conf_reg;
u32 config;
unsigned int pin_id;
struct imx_pin_reg *pin_reg;
if (info->flags & SHARE_MUX_CONF_REG) {
conf_reg = mux_reg;
} else {
conf_reg = be32_to_cpu(*((*list_p)++));//读取conf_reg的值
if (!conf_reg)
conf_reg = -1;
}
pin_id = (mux_reg != -1) ? mux_reg / 4 : conf_reg / 4;//用复用寄存器的值/4得到对应的引脚编号
pin_reg = &ipctl->pin_regs[pin_id];//用引脚编号获取对应的pin寄存器描述结构体
pin->pin = pin_id;//将芯片引脚编号赋值给imx_pin->pin
*grp_pin_id = pin_id;//也存在了grp—>pins当中
pin_reg->mux_reg = mux_reg;//将mux_reg记录到pin_reg上
pin_reg->conf_reg = conf_reg;//同上
pin_memmap->input_reg = be32_to_cpu(*((*list_p)++));//继续++读取属性值
pin_memmap->mux_mode = be32_to_cpu(*((*list_p)++));//同上
pin_memmap->input_val = be32_to_cpu((*(*list_p)++));//同上
...
config = be32_to_cpu(*((*list_p)++));//最后一个16进制整数
...
if (config & IMX_PAD_SION)
pin_memmap->mux_mode |= IOMUXC_CONFIG_SION;
//这个判断就是跟寄存器具体属性相关
pin_memmap->config = config & ~IMX_PAD_SION;//保存属性值
...
return 0;
}