linux pinctrl

本文从以下几个方面来学习和研究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_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典型使用

相关推荐
en.en..2 小时前
Linux系统编程:fcntl 与 ioctl
linux·运维·服务器
自动化监测Learner3 小时前
Navicat Premium 17 中文版安装教程(2026最新版)
java·linux·数据库
pingglala4 小时前
ubuntu-nat模式不能上网解决方法
linux·运维·ubuntu
Zixhy5 小时前
多点巡检机器人项目技术总结
linux·c++·机器人·自动驾驶
雯宝5 小时前
7. USB 网络适配器驱动
linux
rest10245 小时前
使用内存探测bpf
linux
重生之我来学Python6 小时前
Docker套装的简介、安装、超级详细教程
linux·docker·容器·eureka·github
Ruiery6 小时前
Linux 6.6内核 PCIe 深度解析(十):PCIe Port Driver(portdrv)— 一个物理 Port,拆出五个逻辑服务
linux·运维·服务器
码农小韩8 小时前
Linux应用开发(二)——Linux的文件IO
linux·嵌入式软件·嵌入式操作系统·linux应用