本文从以下几个方面来学习和研究pinctrl子系统
- pinctrl的初始化
- pinctrl控制器的注册
- pinctrl的使用
- 示例
pinctrl的初始化
c
static int __init pinctrl_init(void)
{
pr_info("initialized pinctrl subsystem\n");
pinctrl_init_debugfs();
return 0;
}
core_initcall(pinctrl_init);
c
static void pinctrl_init_debugfs(void)
{
debugfs_root = debugfs_create_dir("pinctrl", NULL);
if (IS_ERR(debugfs_root) || !debugfs_root) {
pr_warn("failed to create debugfs directory\n");
debugfs_root = NULL;
return;
}
debugfs_create_file("pinctrl-devices", 0444,
debugfs_root, NULL, &pinctrl_devices_fops);
debugfs_create_file("pinctrl-maps", 0444,
debugfs_root, NULL, &pinctrl_maps_fops);
debugfs_create_file("pinctrl-handles", 0444,
debugfs_root, NULL, &pinctrl_fops);
}
初始化主要工作就是在/sys/kernel/debug目录下创建pinctrl目录并在目录创建三个文件节点。
pinctrl控制器的注册
注册控制器一般有以下几种试:
- devm_pinctrl_register
- pinctrl_register
- devm_pinctrl_register_and_init
- pinctrl_enable
- pinctrl_register_and_init
- pinctrl_enable
虽然方式不太一样,但是殊途同归这里就以pinctrl_register来分析
- pinctrl_enable
pinctrl_register
c
struct pinctrl_dev *pinctrl_register(struct pinctrl_desc *pctldesc,
struct device *dev, void *driver_data)
{
struct pinctrl_dev *pctldev;
int error;
pctldev = pinctrl_init_controller(pctldesc, dev, driver_data);
if (IS_ERR(pctldev))
return pctldev;
error = pinctrl_enable(pctldev);
if (error)
return ERR_PTR(error);
return pctldev;
}
这个函数主要有两操作
- 初始化控制器设备
- 将控制器设备添加到pinctrldev_list链表上
c
struct pinctrl_desc {
const char *name;
const struct pinctrl_pin_desc *pins;
unsigned int npins;
const struct pinctrl_ops *pctlops;
const struct pinmux_ops *pmxops;
const struct pinconf_ops *confops;
struct module *owner;
#ifdef CONFIG_GENERIC_PINCONF
unsigned int num_custom_params;
const struct pinconf_generic_params *custom_params;
const struct pin_config_item *custom_conf_items;
#endif
bool link_consumers;
};
pinctrl_desc pin控制器设备描述结构体
- name :控制器名
- pins : 一组引脚描述符,描述了此引脚控制器处理的所有引脚
- npins :引脚的数量
- pctlops :引脚分组
- pmxops :引脚功能复用
- confops :引脚配置
pinctrl_init_controller

pinctrl_enable
c
int pinctrl_enable(struct pinctrl_dev *pctldev)
{
int error;
error = pinctrl_claim_hogs(pctldev);
if (error) {
dev_err(pctldev->dev, "could not claim hogs: %i\n",
error);
pinctrl_free_pindescs(pctldev, pctldev->desc->pins,
pctldev->desc->npins);
mutex_destroy(&pctldev->mutex);
kfree(pctldev);
return error;
}
mutex_lock(&pinctrldev_list_mutex);
list_add_tail(&pctldev->node, &pinctrldev_list);
mutex_unlock(&pinctrldev_list_mutex);
pinctrl_init_device_debugfs(pctldev);
return 0;
}
- 调用pinctrl_claim_hogs生成pinctrl并添加到相应链表,读取设备树并设置成默认状态
- 将pinctrldev添加到设备链表上
pinctrl_claim_hogs

到这里pincrtl控制器注册流程就走完了,总结下:
- 每个控制器都会生成pinctrldev,对应着控制器设备
- 生成pinctrl,对应着具体的pin角配置
pinctrl的使用
获取pinctrl的大体流程如下图所示:

pinctrl_get

find_pinctrl

这里需要注意的是:pinctrl_list是用于管理pinctrl的链表,pinctrldev_list是用于管理pinctrl控制器的链表
create_pinctrl

pinctrl_dt_to_map

dt_to_map_one_config

dt_remember_or_free_map

add_setting

c
enum pinctrl_map_type {
PIN_MAP_TYPE_INVALID,
PIN_MAP_TYPE_DUMMY_STATE,
PIN_MAP_TYPE_MUX_GROUP,
PIN_MAP_TYPE_CONFIGS_PIN,
PIN_MAP_TYPE_CONFIGS_GROUP,
};
pinctrl_select_state
c
int pinctrl_select_state(struct pinctrl *p, struct pinctrl_state *state)
{
if (p->state == state)
return 0;
return pinctrl_commit_state(p, state);
}
pinctrl_commit_state

示例
pinctrl设备树

pinctrl控制器
源码位置:linux-6.4\linux-6.4\drivers\pinctrl\sprd\Pinctrl-sprd-sc9860.c
c
static int sprd_pinctrl_probe(struct platform_device *pdev)
{
return sprd_pinctrl_core_probe(pdev, sprd_sc9860_pins_info,
ARRAY_SIZE(sprd_sc9860_pins_info));
}
static const struct of_device_id sprd_pinctrl_of_match[] = {
{
.compatible = "sprd,sc9860-pinctrl",
},
{ },
};
MODULE_DEVICE_TABLE(of, sprd_pinctrl_of_match);
static struct platform_driver sprd_pinctrl_driver = {
.driver = {
.name = "sprd-pinctrl",
.of_match_table = sprd_pinctrl_of_match,
},
.probe = sprd_pinctrl_probe,
.remove = sprd_pinctrl_remove,
.shutdown = sprd_pinctrl_shutdown,
};
module_platform_driver(sprd_pinctrl_driver);
其支持的pin脚定义:

控制器回调函数的赋值:

probe

对pinctrl典型使用
