pinctrl_desc结构体注册

pinctrl_desc结构体注册



在这里插入图片描述

pinctrl_register

构建好struct pinctrl_desc结构以后,会调用pinctrl_register函数注册一个pinctrl控制器,得到一个pinctrl_dev

struct pinctrl_dev *pinctrl_register(struct pinctrl_desc *pctldesc,
                struct device *dev, void *driver_data);

/**
 * pinctrl_register() - register a pin controller device
 * @pctldesc: descriptor for this pin controller
 * @dev: parent device for this pin controller
 * @driver_data: private pin controller data for this pin controller
 */
struct pinctrl_dev *pinctrl_register(struct pinctrl_desc *pctldesc,
                    struct device *dev, void *driver_data)
{
    // 分配内存空间用于存储 pinctrl_dev 结构体
    struct pinctrl_dev *pctldev;
    int ret;

    // 检查 pctldesc 是否为空
    if (!pctldesc)
        return NULL;
    // 检查 pctldesc 的名称是否为空
    if (!pctldesc->name)
        return NULL;

    // 分配内存空间用于存储 pinctrl_dev 结构体
    pctldev = kzalloc(sizeof(*pctldev), GFP_KERNEL);
    if (pctldev == NULL) {
        dev_err(dev, "failed to alloc struct pinctrl_dev\n");
        return NULL;
    }

    /* 初始化 pin control 设备结构体 */
    pctldev->owner = pctldesc->owner;
    pctldev->desc = pctldesc;
    pctldev->driver_data = driver_data;
    INIT_RADIX_TREE(&pctldev->pin_desc_tree, GFP_KERNEL);
    INIT_LIST_HEAD(&pctldev->gpio_ranges);
    pctldev->dev = dev;
    mutex_init(&pctldev->mutex);

    /* 检查核心操作是否正常 */
    if (pinctrl_check_ops(pctldev)) {
        dev_err(dev, "pinctrl ops lacks necessary functions\n");
        goto out_err;
    }

    /* 如果实现了 pinmuxing,则检查操作是否正常 */
    if (pctldesc->pmxops) {
        if (pinmux_check_ops(pctldev))
            goto out_err;
    }

    /* 如果实现了 pinconfig,则检查操作是否正常 */
    if (pctldesc->confops) {
        if (pinconf_check_ops(pctldev))
            goto out_err;
    }

    /* pinctrl_register_pins注册所有的引脚 */
    dev_dbg(dev, "try to register %d pins ...\n",  pctldesc->npins);
    ret = pinctrl_register_pins(pctldev, pctldesc->pins, pctldesc->npins);
    if (ret) {
        dev_err(dev, "error during pin registration\n");
        pinctrl_free_pindescs(pctldev, pctldesc->pins,
                      pctldesc->npins);
        goto out_err;
    }

    mutex_lock(&pinctrldev_list_mutex);  // 加锁以保证互斥访问 pinctrldev_list
    list_add_tail(&pctldev->node, &pinctrldev_list);  // 将当前 pctldev 添加到 pinctrldev_list 的尾部
    mutex_unlock(&pinctrldev_list_mutex);  // 解锁 pinctrldev_list

    pctldev->p = pinctrl_get(pctldev->dev);  // 获取 pctldev 的 pinctrl 结构体指针

    if (!IS_ERR(pctldev->p)) {  // 如果 pctldev 的 pinctrl 结构体指针有效
        pctldev->hog_default =  // 获取默认状态的 pinctrl_state 结构体指针
            pinctrl_lookup_state(pctldev->p, PINCTRL_STATE_DEFAULT);
        if (IS_ERR(pctldev->hog_default)) {  // 如果获取默认状态失败
            dev_dbg(dev, "failed to lookup the default state\n");  // 输出调试信息
        } else {
            if (pinctrl_select_state(pctldev->p,  // 选择默认状态
                        pctldev->hog_default))
                dev_err(dev,
                    "failed to select default state\n");  // 输出错误信息
        }

        pctldev->hog_sleep =  // 获取睡眠状态的 pinctrl_state 结构体指针
            pinctrl_lookup_state(pctldev->p,
                            PINCTRL_STATE_SLEEP);
        if (IS_ERR(pctldev->hog_sleep))  // 如果获取睡眠状态失败
            dev_dbg(dev, "failed to lookup the sleep state\n");  // 输出调试信息
    }

    pinctrl_init_device_debugfs(pctldev);  // 初始化 pctldev 的 debugfs

    return pctldev;  // 返回 pctldev 结构体指针

out_err:
    mutex_destroy(&pctldev->mutex);  // 销毁互斥锁
    kfree(pctldev);  // 释放内存空间
    return NULL;  // 返回空指针
}
EXPORT_SYMBOL_GPL(pinctrl_register);

这是一个名为 pinctrl_register 的函数,用于注册一个引脚控制器设备。以下是该函数的详细分析:
首先,函数会检查传入的 pctldesc 是否为空,以及 pctldesc->name 是否为空,如果为空,则返回空指针。
接着,函数会分配内存空间来存储 pinctrl_dev 结构体,并对分配的内存空间进行初始化。如果分配内存失败,则会打印错误信息并返回空指针。
然后,函数会对 pctldev 结构体的各个成员进行初始化,包括 owner、desc、driver_data、pin_desc_tree、gpio_ranges、dev 和 mutex 等。
接下来,函数会检查引脚控制器的操作函数是否正常。如果检查不通过,则会打印错误信息并跳转到错误处理标签 out_err。
如果引脚控制器实现了引脚复用操作 (pinmux),则会检查引脚复用操作的函数是否正常。如果检查不通过,则会跳转到错误处理标签 out_err。
如果引脚控制器实现了引脚配置操作 (pinconfig),则会检查引脚配置操作的函数是否正常。如果检查不通过,则会跳转到错误处理标签 out_err。
接着,函数会注册所有的引脚,调用 pinctrl_register_pins 函数进行引脚的注册。如果注册过程中发生错误,则会打印错误信息,释放已注册的引脚描述符,并跳转到错误处理标签 out_err。
在互斥锁保护下,将当前的 pctldev 添加到全局链表 pinctrldev_list 的尾部。
获取 pctldev 的 pinctrl 结构体指针,并尝试选择默认状态和睡眠状态。
初始化 pctldev 的 debugfs 接口,用于调试和配置。
返回 pctldev 结构体指针,表示引脚控制器注册成功。
如果在注册过程中发生错误,会清理已分配的资源,包括销毁互斥锁和释放内存空间,并返回空指针。

综上所述,pinctrl_register 函数用于注册一个引脚控制器设备,并进行必要的初始化操作。它会校验和初始化设备结构体,注册引脚,选择默认状态和睡眠状态,并提供调试接口。

pinctrl_register_pins注册所有的引脚

static int pinctrl_register_one_pin(struct pinctrl_dev *pctldev,
                    unsigned number, const char *name)
{
    // 获取pin描述符
    struct pin_desc *pindesc;

    // 检查pin是否已经在pinctrldev上注册
    pindesc = pin_desc_get(pctldev, number);
    if (pindesc != NULL) {
        pr_err("pin %d already registered on %s\n", number,
               pctldev->desc->name);
        return -EINVAL;
    }

    // 分配并初始化pin描述符
    pindesc = kzalloc(sizeof(*pindesc), GFP_KERNEL);
    if (pindesc == NULL) {
        dev_err(pctldev->dev, "failed to alloc struct pin_desc\n");
        return -ENOMEM;
    }

    /* 设置拥有者 */
    pindesc->pctldev = pctldev;

    /* 复制基本的pin信息 */
    if (name) {
        pindesc->name = name;
    } else {
        pindesc->name = kasprintf(GFP_KERNEL, "PIN%u", number);
        if (pindesc->name == NULL) {
            kfree(pindesc);
            return -ENOMEM;
        }
        pindesc->dynamic_name = true;
    }

    // 将pin描述符插入到pin描述符树中
    radix_tree_insert(&pctldev->pin_desc_tree, number, pindesc);
    pr_debug("registered pin %d (%s) on %s\n",
         number, pindesc->name, pctldev->desc->name);
    return 0;
}

static int pinctrl_register_pins(struct pinctrl_dev *pctldev,
                 struct pinctrl_pin_desc const *pins,
                 unsigned num_descs)
{
    unsigned i;
    int ret = 0;

    // 遍历所有的pin描述符
    for (i = 0; i < num_descs; i++) {
        // 注册单个pin
        ret = pinctrl_register_one_pin(pctldev,
                           pins[i].number, pins[i].name);
        if (ret)
            return ret;
    }

    return 0;
}

这里给出了两个函数:pinctrl_register_one_pin 和 pinctrl_register_pins,它们用于在引脚控制器中注册引脚。
函数 pinctrl_register_one_pin 的功能是注册单个引脚。它的主要步骤包括:
首先,函数会检查该引脚是否已经在引脚控制器上注册过,通过调用 pin_desc_get 函数来获取对应引脚的描述符。如果已经注册过,则会打印错误信息并返回错误码 -EINVAL。
如果该引脚还未注册过,函数会分配内存空间来存储引脚描述符,并对分配的内存空间进行初始化。

设置引脚描述符的拥有者为当前的引脚控制器。

复制基本的引脚信息,包括引脚名称。如果名称已经提供,则直接使用提供的名称;否则,会生成一个默认的名称,并将其存储在引脚描述符中。如果生成默认名称的过程中出现内存分配失败,则会释放已分配的内存空间并返回错误码 -ENOMEM。

将引脚描述符插入到引脚描述符树中,使用引脚的编号作为键值。

打印调试信息,表示成功注册了该引脚。

返回 0,表示引脚注册成功。

函数 pinctrl_register_pins 的功能是注册一组引脚。它的主要步骤包括:
遍历所有的引脚描述符。

对于每个引脚描述符,调用 pinctrl_register_one_pin 函数来注册单个引脚。如果注册过程中发生错误,则直接返回错误码。
如果所有引脚都成功注册,则返回 0,表示引脚注册成功。

综上所述,这两个函数用于在引脚控制器中注册引脚。首先,pinctrl_register_one_pin 函数用于注册单个引脚,它分配内存并初始化引脚描述符,然后将其插入到引脚描述符树中。其次,pinctrl_register_pins 函数用于注册一组引脚,它遍历引脚描述符数组并调用 pinctrl_register_one_pin 函数来逐个注册引脚。这些函数为引脚控制器的引脚注册提供了必要的功能和接口。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

苦梨甜

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值