总体框图:
设备树iomuxc节点层次
-
iomuxc
-
function
-
grouc
fsl,pins = < xxx xxx >;
…
-
group
-
…
-
-
function
-
…
-
层次关系说明
- iomuxc:pinctrl子系统的设备树节点
- function:芯片具有外设功能,一个功能对应一个或多个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;
//获取iomux节点所对应的device_node指针
//返回值为true 就是为1
flat_funcs = imx_pinctrl_dt_is_flat_functions(np);
if (flat_funcs) {
nfuncs = 1; //一个芯片外设只使用到了一组引脚 在pinctl子系统里面,至少会有一个function来管理所有的group
} else {
nfuncs = of_get_child_count(np);
if (nfuncs == 0) {
dev_err(&pdev->dev, "no functions defined\n");
return -EINVAL;
}
}
//
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);
//把这个function_desc的指针插入到pin_function_tree上去
radix_tree_insert(&pctl->pin_function_tree, i, function);
mutex_unlock(&ipctl->mutex);
}
pctl->num_functions = nfuncs;
ipctl->group_index = 0;
if (flat_funcs) {
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;
//遍历iomux节点下所有的子节点
for_each_child_of_node(np, function_np) {
//判断在子节点里有没有"fsl,pins"属性
if (of_property_read_bool(function_np, "fsl,pins"))
return true;
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
参数:imx_pinctrl_parse_functions(np, ipctl, 0);
np–iomux里的device_node结构体指针,ipctl–imx_pinctrl,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;
u32 i = 0;
//从基数树上把把之前保存的function指针重新提取出来
func = pinmux_generic_get_function(pctl, index);
...
//相当于comptabile
func->name = np->name;
//获取iomux节点里的子节点数量(group)
func->num_group_names = of_get_child_count(np);
...
func->group_names = devm_kcalloc(ipctl->dev, func->num_group_names,
sizeof(char *), GFP_KERNEL);
if (!func->group_names)
return -ENOMEM;
for_each_child_of_node(np, child) {
//把子节点的名字记录到group_names数组中
func->group_names[i] = child->name;
grp = devm_kzalloc(ipctl->dev, sizeof(struct group_desc),
GFP_KERNEL);
if (!grp)
return -ENOMEM;
mutex_lock(
&ipctl->mutex);
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;
}
pinmux_generic_get_function()函数
drivers/pinctrl/pinmux.c
struct function_desc *pinmux_generic_get_function(struct pinctrl_dev *pctldev,
unsigned int selector)
{
struct function_desc *function;
function = radix_tree_lookup(&pctldev->pin_function_tree,
selector);
if (!function)
return NULL;
return function;
}
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)
pin_size = FSL_IMX8_PIN_SIZE;
else if (info->flags & SHARE_MUX_CONF_REG)
pin_size = FSL_PIN_SHARE_SIZE;
else
pin_size = FSL_PIN_SIZE;//24
grp->name = np->name;
//获取节点属性 二维数组
list = of_get_property(np, "fsl,pins", &size);
...
list_p = &list;
...
/*该组引脚的配置个数*/
grp->num_pins = size / pin_size;
grp->data = devm_kcalloc(ipctl->dev,
grp->num_pins, sizeof(struct imx_pin),
GFP_KERNEL);
grp->pins = devm_kcalloc(ipctl->dev,
grp->num_pins, sizeof(unsigned int),
GFP_KERNEL);
...
//遍历组里每一个引脚
for (i = 0; i < grp->num_pins; i++) {
struct imx_pin *pin = &((struct imx_pin *)(grp->data))[i];
if (info->flags & IMX8_USE_SCU)
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); //list_p引脚的配置值
}
return 0;
}
imx_pinctrl_parse_pin_mem()函数
drivers/pinctrl/freescale/pinctrl-memmap.c
参数:imx_pinctrl_parse_pin_mem(ipctl, &grp->pins[i],pin, list_p, config); //list_p引脚的配置值
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;
//把二维数组里第一个引脚的配置信息给解析出来 保存到mux_reg上
u32 mux_reg = be32_to_cpu(*((*list_p)++));
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)++));
if (!conf_reg)
conf_reg = -1;
}
//获得芯片引脚的编号
pin_id = (mux_reg != -1) ? mux_reg / 4 : conf_reg / 4;
//找到数组元素
pin_reg = &ipctl->pin_regs[pin_id];
//把芯片引脚的编号记录在imx_pin结构体上的int pin
pin->pin = pin_id;
*grp_pin_id = pin_id;
pin_reg->mux_reg = mux_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)++));
...
if (config & IMX_PAD_SION)
pin_memmap->mux_mode |= IOMUXC_CONFIG_SION;
pin_memmap->config = config & ~IMX_PAD_SION;
...
return 0;
}