Linux内核pinctrl子系统驱动所做的关键工作

发布时间:2024年01月22日

一. 简介

上一篇文章简单了解了 pinctrl子系统驱动框架,文章地址如下:

Linux内核pinctrl子系统驱动说明一-CSDN博客

本文继上一篇文章pinctrl子系统驱动代码的学习,具体来了解 pinctrl子系统驱动所做的最关键的工作。

二.? pinctrl子系统驱动所做的最关键的工作

1.? pinctrl子系统驱动思路

上一篇文章的学习中可以知道,设备树中的 compatible 属性值会和 of_device_id 中的所有兼容性字符串比较,查看是否可以使用此驱动。

imx6ul_pinctrl_of_match 结构体数组一共有两个兼容性字符串,分别为“fsl,imx6ul-iomuxc”和“fsl,imx6ull-iomuxc-snvs”,因此 iomuxc 节点与此驱动匹配,所以 pinctrl-imx6ul.c 会完成 I.MX6ULL PIN 配置工作。

当设备和驱动匹配成功以后, platform_driver probe 成员变量所代表的函数就会执行,在代码中设置 probe 成员变量为 imx6ul_pinctrl_probe 函数,因此, imx6ul_pinctrl_probe 这个函数就会执行,可 以认为 imx6ul_pinctrl_probe 函数,就是 I.MX6ULL 这个 SOC PIN 配置入口函数。以此为入口,如下图的函数调用路径:

2.? pinctrl子系统驱动所做的最关键的工作

(1)? 获取设备树中关于 PIN 的配置信息

imx_pinctrl_parse_groups 函数 负责获取设备树中关于 PIN 的配置信息,也就是我们前面分析的那 6 u32 类型的值。处理过程如下所示:
static int imx_pinctrl_parse_groups(struct device_node *np, struct imx_pin_group *grp,
				    struct imx_pinctrl_soc_info *info, u32 index)
{
	int size, pin_size;
	const __be32 *list;
	int i;
...........
		pin_id = (mux_reg != -1) ? mux_reg / 4 : conf_reg / 4;
		pin_reg = &info->pin_regs[pin_id];
		pin->pin = pin_id;
		grp->pin_ids[i] = pin_id;
		pin_reg->mux_reg = mux_reg;
		pin_reg->conf_reg = conf_reg;
		pin->input_reg = be32_to_cpu(*list++);
		pin->mux_mode = be32_to_cpu(*list++);
		pin->input_val = be32_to_cpu(*list++);

		/* SION bit is in mux register */
		config = be32_to_cpu(*list++);
		if (config & IMX_PAD_SION)
			pin->mux_mode |= IOMUXC_CONFIG_SION;
		pin->config = config & ~IMX_PAD_SION;
............
	}

	return 0;
}

1~2 行,设备树中的 mux_reg conf_reg 值会保存在 info 参数中, input_reg mux_mode input_val config 值会保存在 grp 参数中。
14~ 18 行,获取 mux_reg conf_reg input_reg mux_mode input_val 值。
24 行,获取 config 值。

(2) 注册PIN控制器

下来看一下函数 pinctrl_register,此函数用于向 Linux 内核注册一个 PIN 控制器,此函数原型如下:

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

参数 pctldesc 非常重要,因为此参数就是要注册的 PIN 控制器,PIN 控制器用于配置 SOC PIN 复用功能和电气特性。参数 pctldesc pinctrl_desc 结构体类型指针,pinctrl_desc 结构体如下所示:

struct pinctrl_desc {
	const char *name;
	struct pinctrl_pin_desc const *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
};

5~7 行,这三个 “ _ops ” 结构体指针非常重要!!!因为这三个结构体就是 PIN 控制器的 “工具”,这三个结构体里面包含了很多操作函数,通过这些操作函数就可以完成对某一个 PIN 的配置。
pinctrl_desc 结构体需要由用户提供,结构体里面的成员变量也是用户提供的 是这个用户并不是我们这些使用芯片的程序员,而是半导体厂商,半导体厂商发布的 Linux 核源码中,已经把这些工作做完了。例如,在 imx_pinctrl_probe 函数中可以找到如下所示代码:
int imx_pinctrl_probe(struct platform_device *pdev, struct imx_pinctrl_soc_info *info)
{
    struct device_node *dev_np = pdev->dev.of_node;
    struct device_node *np;
     struct imx_pinctrl *ipctl;
     struct resource *res;
     struct pinctrl_desc *imx_pinctrl_desc;
......
    imx_pinctrl_desc = devm_kzalloc(&pdev->dev, sizeof(*imx_pinctrl_desc), GFP_KERNEL);
     if (!imx_pinctrl_desc)
         return -ENOMEM;
......
    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->pctl = pinctrl_register(imx_pinctrl_desc, &pdev->dev, ipctl);
......
 }

5 行,定义结构体指针变量 imx_pinctrl_desc
9 行,向指针变量 imx_pinctrl_desc 分配内存。
15~21 行,初始化 imx_pinctrl_desc 结构体指针变量,重点是 pctlops pmxops confops 这三个成员变量,分别对应 imx_pctrl_ops imx_pmx_ops imx_pinconf_ops 这三个结构体。
23 行,调用函数 pinctrl_register ,向 Linux 内核注册 imx_pinctrl_desc ,注册以后 Linux 核就有了对 I.MX6ULL PIN 进行配置的工具。

imx_pctrl_ops imx_pmx_ops imx_pinconf_ops 这三个结构体定义如下:
static const struct pinctrl_ops imx_pctrl_ops = {
	.get_groups_count = imx_get_groups_count,
	.get_group_name = imx_get_group_name,
	.get_group_pins = imx_get_group_pins,
	.pin_dbg_show = imx_pin_dbg_show,
	.dt_node_to_map = imx_dt_node_to_map,
	.dt_free_map = imx_dt_free_map,

};

static const struct pinmux_ops imx_pmx_ops = {
	.get_functions_count = imx_pmx_get_funcs_count,
	.get_function_name = imx_pmx_get_func_name,
	.get_function_groups = imx_pmx_get_groups,
	.set_mux = imx_pmx_set,
	.gpio_request_enable = imx_pmx_gpio_request_enable,
	.gpio_set_direction = imx_pmx_gpio_set_direction,
};

static const struct pinconf_ops imx_pinconf_ops = {
	.pin_config_get = imx_pinconf_get,
	.pin_config_set = imx_pinconf_set,
	.pin_config_dbg_show = imx_pinconf_dbg_show,
	.pin_config_group_dbg_show = imx_pinconf_group_dbg_show,
};

这三个结构体下的所有函数就是 I.MX6ULL PIN 配置函数,我们就 不再去分析这些函数了,有兴趣的可以去看一下。

文章来源:https://blog.csdn.net/wojiaxiaohuang2014/article/details/135738484
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。