imx6q的Pinctrl子系统源码分析

pinctrl子系统驱动加载入口 driver/pinctrl/freescale/pinctrl-imx6q.c

static int __init imx6q_pinctrl_init(void)
{
return platform_driver_register(&imx6q_pinctrl_driver);
}

首先跟踪代码进行分析:
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;
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;
/
Create state holders etc for this driver */
// imx_pinctrl imx引脚控制寄存器的描述
ipctl = devm_kzalloc(&pdev->dev, sizeof(*ipctl), GFP_KERNEL);
if (!ipctl)
return -ENOMEM;
//pin的寄存器地址映射, mux_reg conf_reg
info->pin_regs = devm_kmalloc(&pdev->dev, sizeof(*info->pin_regs) *
info->npins, GFP_KERNEL);
if (!info->pin_regs)
return -ENOMEM;
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);
//获取imx pinctrl的寄存器基地址
ipctl->base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(ipctl->base))
return PTR_ERR(ipctl->base);
//从设备树中读取"fsl,input-sel"中的相关属性,在imx6q中未见相关设置,不予分析
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->name = dev_name(&pdev->dev);
imx_pinctrl_desc->pins = info->pins;
imx_pinctrl_desc->npins = info->npins;
imx_pinctrl_desc->pctlops = &imx_pctrl_ops; //Pin管脚的控制集合
imx_pinctrl_desc->pmxops = &imx_pmx_ops; //Pin管脚的复用集合
imx_pinctrl_desc->confops = &imx_pinconf_ops; //Pin管脚的配置集合
imx_pinctrl_desc->owner = THIS_MODULE;
//以上引脚的复用配置等工作 应该集中在imx_pctrl_ops imx_pmx_ops imx_pinconf_ops 三个操作集合中
//从设备树中读取相关配置到info中
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);
//注册pin ctrl的dev节点
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;
}


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;
}
//有多少个子节点,就有多少Pin的功能和分组
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 = 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;
}


static int imx_pinctrl_parse_functions(struct device_node *np,
struct imx_pinctrl_soc_info *info,
u32 index)
{
//参数np传入的已经是fsl,imx6q-iomuxc节点下的一级子节点
struct device_node *child;
struct imx_pmx_func func;
struct imx_pin_group grp;
u32 i = 0;
dev_dbg(info->dev, “parse function(%d): %s\n”, index, np->name);
//获取当前节点的复用功能描述
func = &info->functions[index];
/
Initialise function 初始化复用功能
/
func->name = np->name;
func->num_groups = of_get_child_count(np);
if (func->num_groups == 0) {
dev_err(info->dev, “no groups defined in %s\n”, np->full_name);
return -EINVAL;
}
func->groups = devm_kzalloc(info->dev,
func->num_groups * sizeof(char *), GFP_KERNEL);
//从子节点中解析pin groups
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;
}


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);
if (info->flags & SHARE_MUX_CONF_REG)
pin_size = SHARE_FSL_PIN_SIZE;
else
pin_size = FSL_PIN_SIZE;
//Pin_size的作用
/
Initialise group /
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, “no fsl,pins property in node %s\n”, np->full_name);
return -EINVAL;
}
/
we do not check return since it’s safe node passed down /
if (!size || size % pin_size) {
dev_err(info->dev, “Invalid fsl,pins property in node %s\n”, np->full_name);
return -EINVAL;
}
//pin 的数量
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;
/

从fsl pins属性中解析出需要配置的寄存器内容
<mux_reg conf_reg input_reg mux_mode input_val>
0x35c 0x744 0x000 0x2 0x0 0x1b0b1
注意这里list的使用方法
*/
for (i = 0; i < grp->npins; i++) {
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];
if (!(info->flags & ZERO_OFFSET_VALID) && !mux_reg)
mux_reg = -1;
if (info->flags & 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;
}
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 bit is in mux register */
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;
}


imx_pinctrl_desc->pctlops = &imx_pctrl_ops; //Pin管脚的控制集合
imx_pinctrl_desc->pmxops = &imx_pmx_ops; //Pin管脚的复用集合
imx_pinctrl_desc->confops = &imx_pinconf_ops; //Pin管脚的配置集合
imx中的PinCtl 底层的寄存器设置工作集中在以上的三个操作集合中,其调用主要集中在Linux的pinctrl核心子系统 drivers/pinctl/core.c,初始化入口 core_initcall(pinctrl_init)。
static int __init pinctrl_init(void)
{
pr_info(“initialized pinctrl subsystem\n”);
pinctrl_init_debugfs();
return 0;
}
在其他驱动程序加载之前,需要首先加载pinctrl_init子系统,进行Pin的复用设置之后再加载其他驱动。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值