pinctrl_desc结构体注册
文章目录
- pinctrl_desc结构体注册
- pinctrl_register
- pinctrl_register_pins注册所有的引脚
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 函数来逐个注册引脚。这些函数为引脚控制器的引脚注册提供了必要的功能和接口。