117 imx_pinctrl和pinctrl_dev:引脚名字和编号该存在哪里?

本文详细介绍了Linux内核中的pinctrl子系统,包括imx6ul_pinctrl驱动的结构和工作流程,如imx6ul_pinctrl_probe函数、of_device_get_match_data和of_match_device函数的用途,以及PINCTRL_PIN宏和引脚配置信息的存储方式。pinctrl子系统用于管理SoC的引脚配置,确保引脚的正确复用和状态管理。
摘要由CSDN通过智能技术生成

一、pinctrl子系统简介

pinctrl子系统的平台设备驱动文件:drivers/pinctrl/freescale/pinctrl-imx6ul.c

pinctrl子系统预先确定引脚的数量和名字:
1、为每个引脚的配置信息分配内存
2、管理每个引脚的使用状态

平台驱动结构体如下:

static struct platform_driver imx6ul_pinctrl_driver = {
	.driver = {
		.name = "imx6ul-pinctrl",
		.owner = THIS_MODULE,
		// #define of_match_ptr(_ptr)	(_ptr)
		// imx6ul_pinctrl_of_match 详见下
		.of_match_table = of_match_ptr(imx6ul_pinctrl_of_match),
	},
	.probe = imx6ul_pinctrl_probe,
	.remove = imx_pinctrl_remove,
};

此平台驱动的设备匹配表:imx6ul_pinctrl_of_match

static struct of_device_id imx6ul_pinctrl_of_match[] = {
	// imx6ul_pinctrl_info 存放pin的名字、编号、总数等。
	{ .compatible = "fsl,imx6ul-iomuxc", .data = &imx6ul_pinctrl_info, },
	{ .compatible = "fsl,imx6ull-iomuxc-snvs", .data = &imx6ull_snvs_pinctrl_info, },
	{ /* sentinel */ }
};

/*
 * Struct used for matching a device
 */
struct of_device_id {
	char	name[32];
	char	type[32];
	char	compatible[128];
	const void *data;
};

pin信息:imx6ul_pinctrl_info

static struct imx_pinctrl_soc_info imx6ul_pinctrl_info = {
	// 指向一个结构体数组,主要保存 pin 的名字和编号
	.pins = imx6ul_pinctrl_pads,
	// 上面数组的 size
	.npins = ARRAY_SIZE(imx6ul_pinctrl_pads),
};

struct imx_pinctrl_soc_info {
	struct device *dev;
	const struct pinctrl_pin_desc *pins;
	unsigned int npins;
	struct imx_pin_reg *pin_regs;
	struct imx_pin_group *groups;
	unsigned int ngroups;
	struct imx_pmx_func *functions;
	unsigned int nfunctions;
	unsigned int flags;
	u32 grp_index;
};

imx6ul_pinctrl_pads保存pin的名字和编号(编号和pin mux reg 的 offset 成正比)

/* Pad names for the pinmux subsystem */
static const struct pinctrl_pin_desc imx6ul_pinctrl_pads[] = {
	// MX6UL_PAD_RESERVE0 = 0,
	// #define IMX_PINCTRL_PIN(pin) PINCTRL_PIN(pin, #pin)
	// #define PINCTRL_PIN(a, b) { .number = a, .name = b }
	IMX_PINCTRL_PIN(MX6UL_PAD_RESERVE0),
	// MX6UL_PAD_RESERVE1 = 1,此值与 对应 pin 的 mux reg offset 成 4 倍关系
	IMX_PINCTRL_PIN(MX6UL_PAD_RESERVE1), 
	...
	IMX_PINCTRL_PIN(MX6UL_PAD_CSI_DATA07),
};

/**
 * struct pinctrl_pin_desc - boards/machines provide information on their
 * pins, pads or other muxable units in this struct
 * @number: unique pin number from the global pin number space
 * @name: a name for this pin
 * @drv_data: driver-defined per-pin data. pinctrl core does not touch this
 */
struct pinctrl_pin_desc {
	unsigned number;
	const char *name;
	void *drv_data;
};
imx6ul_pinctrl_probe()函数

pinctrl子系统驱动文件:drivers/pinctrl/freescale/pinctrl-imx6ul.c

static int imx6ul_pinctrl_probe(struct platform_device *pdev)
{
	const struct imx_pinctrl_soc_info *pinctrl_info;
	const struct of_device_id *match;

	pinctrl_info = of_device_get_match_data(&pdev->dev);
	if (!pinctrl_info)
		return -ENODEV;

	match = of_match_device(imx6ul_pinctrl_of_match, &pdev->dev);

	if (!match)
		return -ENODEV;

	pinctrl_info = (struct imx_pinctrl_soc_info *) match->data;

	return imx_pinctrl_probe(pdev, pinctrl_info);
}
// 此结构体一般嵌在下面的结构体中
struct pinctrl_pin_desc {
	// 引脚编号,和 mux_reg 也就是服用寄存器offset值成4倍关系
	unsigned number;
	// 引脚名字
	const char *name;
	void *drv_data;
};

// 此结构体一般嵌在下面的结构体的data成员中
struct imx_pinctrl_soc_info {
	// 指向一个结构体数组
	const struct pinctrl_pin_desc *pins;
	// 上面数组的长度
	unsigned int npins;
	unsigned int flags;
	const char *gpr_compatible;
	...
	}

/*
 * Struct used for matching a device
 */
struct of_device_id {
	char	name[32];
	char	type[32];
	char	compatible[128];
	const void *data;
};
of_device_get_match_data()函数

drivers/of/device.c

const void *of_device_get_match_data(const struct device *dev)
{
	const struct of_device_id *match;

	match = of_match_device(dev->driver->of_match_table, dev);
	if (!match)
		return NULL;

	return match->data;
}
of_match_device()函数
const struct of_device_id *of_match_device(const struct of_device_id *matches,
					   const struct device *dev)
{
	if ((!matches) || (!dev->of_node))
		return NULL;
	return of_match_node(matches, dev->of_node);
}
imx6ul_pinctrl_pads
  • 引脚的编号和名字表
IMX_PINCTRL_PIN宏

drivers/pinctrl/freescale/pinctrl-imx.h

#define IMX_PINCTRL_PIN(pin) PINCTRL_PIN(pin, #pin)
PINCTRL_PIN宏

include/linux/pinctrl/pinctrl.h

// number 表示 pin 的编号,与此pin的 mux 寄存器的偏移地址成正比,4倍关系
#define PINCTRL_PIN(a, b) { .number = a, .name = b }
引脚编号与复用寄存器的关系

pin.num = mux/4

imx_pinctrl:存储引脚的名字和编号原始表
imx_pinctrl_probe()函数
int imx_pinctrl_probe(struct platform_device *pdev,
		      const struct imx_pinctrl_soc_info *info)
{
	struct imx_pinctrl *ipctl;
	struct pinctrl_desc *imx_pinctrl_desc;
	...
	ipctl = devm_kzalloc(&pdev->dev, sizeof(*ipctl), GFP_KERNEL);
	...
	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	ipctl->base = devm_ioremap_resource(&pdev->dev, res);
	...
	imx_pinctrl_desc = devm_kzalloc(&pdev->dev, sizeof(*imx_pinctrl_desc),GFP_KERNEL);
	...
	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;
	imx_pinctrl_desc->pmxops = &imx_pmx_ops;
	imx_pinctrl_desc->confops = &imx_pinconf_ops;
	imx_pinctrl_desc->owner = THIS_MODULE;
	...
	ipctl->info = info;
	ipctl->dev = &pdev->dev;
	platform_set_drvdata(pdev, ipctl);
	...
	ret = devm_pinctrl_register_and_init(&pdev->dev,
					     imx_pinctrl_desc, ipctl,
					     &ipctl->pctl);
	...
	ret = imx_pinctrl_probe_dt(pdev, ipctl);
	...
	return pinctrl_enable(ipctl->pctl);
	...
	return ret;
}
	
pinctrl_desc:以基数树的方式存储引脚的名字,记录引脚的使用状态
devm_pinctrl_register_and_init()函数

drivers/pinctrl/core.c

int pinctrl_register_and_init(struct pinctrl_desc *pctldesc,
			      struct device *dev, void *driver_data,
			      struct pinctrl_dev **pctldev)
{
	struct pinctrl_dev *p;

	p = pinctrl_init_controller(pctldesc, dev, driver_data);
	if (IS_ERR(p))
		return PTR_ERR(p);

	*pctldev = p;

	return 0;
}
pinctrl_init_controller()函数

drivers/pinctrl/core.c

static struct pinctrl_dev *
pinctrl_init_controller(struct pinctrl_desc *pctldesc, struct device *dev,
			void *driver_data)
{
	struct pinctrl_dev *pctldev;
	...
	pctldev = kzalloc(sizeof(*pctldev), GFP_KERNEL);
	...
	pctldev->owner = pctldesc->owner;
	pctldev->desc = pctldesc;
	pctldev->driver_data = driver_data;
	/*初始化基数树*/
	INIT_RADIX_TREE(&pctldev->pin_desc_tree, GFP_KERNEL);
	...
	pctldev->dev = dev;
	...
	ret = pinctrl_register_pins(pctldev, pctldesc->pins, pctldesc->npins);
	...
	return pctldev;
	...
}
pinctrl_register_pins()函数

drivers/pinctrl/core.c

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

	for (i = 0; i < num_descs; i++) {
		ret = pinctrl_register_one_pin(pctldev, &pins[i]);
		if (ret)
			return ret;
	}

	return 0;
}
pinctrl_register_one_pin()函数

drivers/pinctrl/core.c

static int pinctrl_register_one_pin(struct pinctrl_dev *pctldev,
				    const struct pinctrl_pin_desc *pin)
{
	struct pin_desc *pindesc;

	pindesc = pin_desc_get(pctldev, pin->number);
	if (pindesc) {
		dev_err(pctldev->dev, "pin %d already registered\n",
			pin->number);
		return -EINVAL;
	}

	pindesc = kzalloc(sizeof(*pindesc), GFP_KERNEL);
	...
	pindesc->pctldev = pctldev;
	...
	if (pin->name) {
		pindesc->name = pin->name;
	} else {
		pindesc->name = kasprintf(GFP_KERNEL, "PIN%u", pin->number);
		if (!pindesc->name) {
			kfree(pindesc);
			return -ENOMEM;
		}
		pindesc->dynamic_name = true;
	}
	...
	radix_tree_insert(&pctldev->pin_desc_tree, pin->number, pindesc);
	...
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
IMX_GPIO_NR是**用于确定GPIO(General-Purpose Input/Output,通用输入输出)端口号的宏定义**。 在嵌入式系统开发中,特别是在使用i.MX系列处理器时,IMX_GPIO_NR用于计算特定的GPIO端口号。这个宏通常在硬件抽象层(HAL)或驱动程序中定义,以便在不同的硬件平台上对GPIO进行统一操作。具体来说,IMX_GPIO_NR的公式是`((bank) - 1) * 32 + (nr))`,其中`bank`表示GPIO所在的银行编号,而`nr`表示在该银行内的GPIO编号。 以下是一些关于IMX_GPIO_NR的关键点: 1. **函数原型**:IMX_GPIO_NR通常在头文件如`hardware.h`中定义,作为计算GPIO端口号的函数原型参数。 2. **计算方法**:通过公式`((bank) - 1) * 32 + (nr))`可以计算出具体的GPIO端口号。例如,IMX_GPIO_NR(6,4)将会计算出164作为端口号。 3. **用途**:这个宏主要用于设置GPIO的方向(输入或输出),以及读取或写入GPIO的值。例如,`gpio_direction_output(IMX_GPIO_NR(3, 0), 1);`这行代码将GPIO3_IO00设置为高电平。 4. **硬件结构**:GPIO是微控制器芯片上的一种通用可编程I/O接口,它至少包含数据寄存器和控制寄存器两个部分。数据寄存器的位直接引到芯片外部,而控制寄存器则对数据寄存器中的每一位进行独立设置。 5. **操作系统兼容性**:在Linux操作系统中,GPIO操作接口允许用户通过统一的API来操作不同的GPIO,这样可以在不同的平台上复用相同的代码。 综上所述,了解IMX_GPIO_NR对于进行嵌入式系统开发,尤其是在使用i.MX处理器系列的项目中,是非常重要的。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值