参考文档:
Documentation/pinctrl.txt
Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt
Documentation/devicetree/bindings/pinctrl/msm-pinctrl.txt
include/linux/pinctrl/pinconfig-generic.h
msm_tlmm_probe(pinctrl-msm-tlmm.c) //设备树中的tlmm_pinmux: pinctrl@1000000匹配“qcom,msm-tlmm-8916”
msm_pinctrl_probe
msm_pinctrl_get_drvdata //添加各个pintype的(struct pinctrl_desc pctl),获取普通pinctrl节点(struct msm_pin_grps *pin_grps和unsigned int num_grps)到dd
msm_pinctrl_dt_parse_pintype //找到pinctrl中name(gp,sdc,qdsd,ebi)字段匹配的节点作为pintype,保存到dd(struct msm_pintype_info *msm_pintype和unsigned int num_pintypes)
//分析各个pintype中的"qcom,num-pins"属性,为每个pin分配msm_pindesc,并且保存到dd(struct msm_pindesc *msm_pindesc)
msm_populate_pindesc //为每个pin的msm_pindesc命名,比如gp0,gp1,gp2......
msm_pinctrl_dt_parse_pins //分析pinctrl@1000000中的除pintype之外的节点,节点必须包含
//"qcom,pins(引脚列表)"
//"qcom,num-grp-pins(引脚个数)"
//"qcom,pin-func(可选,引脚func编号,需要参考数据手册)"
//"label(作为grp-pins的名字,func的名字使用xxx(grp_name)-func)"
//分析的信息保存到dd(struct msm_pin_grps *pin_grps,unsigned int num_grps,struct msm_pmx_funcs *pmx_funcs,unsigned int num_funcs)
msm_register_gpiochip
msm_pintype_supports_gpio
of_find_property(pt_node, "gpio-controller", NULL) //找到支持gpio-controller的节点作为所注册pintype的node
gpiochip_add //注册gipchip,方便gpilib.c调用
msm_register_pinctrl
ctrl_desc->pmxops = &msm_pmxops; //设置pinctrl_desc的操作方法
ctrl_desc->confops = &msm_pconfops;
ctrl_desc->pctlops = &msm_pctrlops;
ctrl_desc->pins = pindesc; //从dd中提取前面获取的dd->msm_pindesc信息
ctrl_desc->npins = dd->num_pins;
pinctrl_register //注册一个包含ctrl_desc的pinctrl_dev,并且保留到dd(struct pinctrl_dev *pctl_dev)
pctldev->p = pinctrl_get(pctldev->dev); //如pinctrl-bindings +24所述,pin controller自身也是一个设备节点,可以有pinctrl-names和pinctrl-n属性,用于驱动加载时初始化引脚配置
pinctrl_lookup_state(pctldev->p, PINCTRL_STATE_DEFAULT) //(默认寻找"default属性")
pinctrl_add_gpio_range //设置pinctrl_dev的gpio范围
msm_register_irqchip
msm_pintype_supports_irq
of_find_property(pt_node, "interrupt-controller", NULL)//找到支持interrupt-controller的节点作为所注册pintype的node
ret = pintype->init_irq(dd->irq, pintype, dd->dev);
msm_tlmm_gp_irq_init
platform_set_drvdata//将dd(driver data跟platform dev绑定)
devm_pinctrl_get_select(dev ,name)//其中name即为pinctrl-name的属性,每组pinctrl-%d可以有多组属性,用于设置多种io
//设备驱动中,通过devm_pinctrl_get获取其中的pinctrl属性,并且创建pinctrl对象
devm_pinctrl_get
pinctrl_get //获取设备节点的pinctrl属性
create_pinctrl //第一次调用,先创建pinctrl
pinctrl_dt_to_map //分析节点的pinctrl-%d和pinctrl-names属性
for (state = 0; ; state++) //逐个pinctrl-%d分析,pinctrl-name依次作为pinctrl-%d的statename
for (config = 0; config < size; config++)//分析pinctrl-%d中的每个属性
of_find_node_by_phandle//pinctrl-%d属性为&xxx,通过phandle找到对应的设备树节点
dt_to_map_one_config
of_get_next_parent//逐层寻找父节点,直到找到pinctrl节点属性
dt_node_to_map
msm_dt_node_to_map
pinconf_generic_parse_dt_config //根据dt_params[]中定义的属性,逐条分析pin中定义的属性并且保存到pinctrl_map中
dt_remember_or_free_map
map[i].name = statename;//statename作为map的名字
pinctrl_register_map//将分析得到的map注册到全局pinctrl_maps链表,并与返回的pinctrl绑定
for_each_maps//从pinctrl_maps全局链表中取出每一个map_node,并且分析其中的每个map属性
add_setting
create_state//每个map作为一个state,名字是前面的map->name
//获取指定pinctrl的pinctrl-name为xxx的属性
pinctrl_lookup_state
//设置指定的属性状态
pinctrl_select_state