pinctrl设备及其结构体

pinctrl设备及其结构体


文章目录

  • pinctrl设备及其结构体
  • imx6ul_pinctrl的platform_driver
  • struct pinctrl_desc


imx6ul_pinctrl的platform_driver

所有的东西都已经准备好了,包括寄存器地址和寄存器值, Linux 内核相应的驱动文件就会根据这些值来做相应的初始化。接下来就找一下哪个驱动文件来做这一件事情, iomuxc 节点中 compatible 属性的值为“fsl,imx6ul-iomuxc”,在 Linux 内核中全局搜索“fsl,imx6ul-iomuxc”字符串就会找到对应的驱动文件。在文件drivers/pinctrl/freescale/pinctrl-imx6ul.c中有如下内容:

pinctrl设备及其结构体_第1张图片

static struct of_device_id imx6ul_pinctrl_of_match[] = {
    { .compatible = "fsl,imx6ul-iomuxc", .data = &imx6ul_pinctrl_info, },  // 匹配设备的兼容性,使用imx6ul-iomuxc驱动,使用imx6ul_pinctrl_info配置信息
    { .compatible = "fsl,imx6ull-iomuxc-snvs", .data = &imx6ull_snvs_pinctrl_info, },  // 匹配设备的兼容性,使用imx6ull-iomuxc-snvs驱动,使用imx6ull_snvs_pinctrl_info配置信息
    { /* sentinel */ }
};

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

    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);  // 调用imx_pinctrl_probe函数进行设备探测
}

static struct platform_driver imx6ul_pinctrl_driver = {
    .driver = {
        .name = "imx6ul-pinctrl",  // 驱动名称
        .owner = THIS_MODULE,
        .of_match_table = of_match_ptr(imx6ul_pinctrl_of_match),  // 匹配设备的表格
    },
    .probe = imx6ul_pinctrl_probe,  // 设备探测函数
    .remove = imx_pinctrl_remove,  // 设备移除函数
};

static int __init imx6ul_pinctrl_init(void)
{
    return platform_driver_register(&imx6ul_pinctrl_driver);  // 注册平台驱动
}
arch_initcall(imx6ul_pinctrl_init);  // 模块初始化函数

static void __exit imx6ul_pinctrl_exit(void)
{
    platform_driver_unregister(&imx6ul_pinctrl_driver);  // 注销平台驱动
}
module_exit(imx6ul_pinctrl_exit);  // 模块退出函数

这段代码是与 i.MX6UL 和 i.MX6ULL SoC 的引脚控制器 (pinctrl) 相关的驱动代码。让我们逐行详细分析:
imx6ul_pinctrl_of_match 是一个静态数组,其中存储了用于设备树匹配的信息。数组的元素类型是 struct of_device_id,包含两个字段:compatible 和 data。compatible 字段用于指定设备树中设备节点的兼容性字符串,data 字段则用于存储与该设备匹配时需要使用的数据。在这个例子中,数组中有两个元素,分别用于匹配 “fsl,imx6ul-iomuxc” 和 “fsl,imx6ull-iomuxc-snvs”。
imx6ul_pinctrl_probe 是一个设备探测函数,当与驱动程序匹配的设备被发现时会被调用。它接收一个指向 struct platform_device 的指针作为参数。函数内部首先声明了两个变量:match 和 pinctrl_info。match 是一个指向 struct of_device_id 的指针,用于存储与设备匹配的结果。pinctrl_info 是一个指向 struct imx_pinctrl_soc_info 的指针,用于存储与设备匹配时需要使用的数据。
match = of_match_device(imx6ul_pinctrl_of_match, &pdev->dev); 这行代码使用 of_match_device 函数在设备树匹配数组 imx6ul_pinctrl_of_match 中查找与当前设备匹配的项。pdev->dev 是传递给设备探测函数的设备结构体,它包含设备的有关信息。如果找到匹配项,将返回一个指向匹配项的指针,否则返回 NULL。
if (!match) return -ENODEV; 如果没有找到匹配项,说明当前设备与该驱动程序不匹配,函数返回 -ENODEV 表示设备不存在或不支持。
pinctrl_info = (struct imx_pinctrl_soc_info *) match->data; 这行代码将匹配项中的 data 字段赋值给 pinctrl_info,并进行类型转换,使其指向 struct imx_pinctrl_soc_info 类型的数据。data 字段在之前的 of_device_id 数组中被初始化为对应设备需要的数据。
return imx_pinctrl_probe(pdev, pinctrl_info); 这行代码调用了 imx_pinctrl_probe 函数,并传递了设备结构体和 pinctrl_info 作为参数。这个函数用于执行与引脚控制器相关的初始化操作,并可能执行其他与该设备相关的功能。
imx6ul_pinctrl_driver是一个 platform_driver 结构体,其中定义了与驱动程序相关的信息。它的 .driver 字段包含了驱动程序的名称、所有者和设备树匹配表。.probe 字段指向 imx6ul_pinctrl_probe 函数,.remove 字段指向 imx_pinctrl_remove 函数(未在提供的代码片段中包含)。
imx6ul_pinctrl_init 是一个模块初始化函数,它在驱动程序加载时被调用。它注册了 imx6ul_pinctrl_driver 平台驱动程序,并将其返回值作为初始化函数的返回值。
arch_initcall(imx6ul_pinctrl_init); 这行代码使用 arch_initcall 宏将 imx6ul_pinctrl_init 函数注册为体系结构初始化阶段的回调函数。这意味着在系统引导过程中的适当时机调用该函数进行初始化。
imx6ul_pinctrl_exit是一个模块退出函数,它在驱动程序被卸载时被调用。它调用 platform_driver_unregister 函数,注销 imx6ul_pinctrl_driver 平台驱动程序。
总体来说,这段代码实现了一个用于 i.MX6UL 和 i.MX6ULL SoC 的引脚控制器驱动程序。它通过设备树匹配来确定是否支持当前的硬件设备,并在成功匹配时执行相应的初始化操作。该驱动程序在模块加载时注册,并在模块卸载时注销。
pinctrl驱动是在加载p地驱动时设置的引脚,还是在加载模块时设置的引脚复用呢?还是说会设置成俩次呢?

struct pinctrl_desc

include\linux\pinctrl\pinctrl.h

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;
    /* 如何在debugfs中打印@params的信息,必须与@custom_params的大小相同,即@num_custom_params */
    const struct pin_config_item *custom_conf_items;
#endif
};

这是一个名为 pinctrl_desc 的结构体,用于描述引脚控制器的属性和操作。让我们逐个字段进行总结:
const char *name;:引脚控制器的名称。
struct pinctrl_pin_desc const *pins;:指向引脚描述符数组的指针,描述了由该引脚控制器处理的所有引脚。
unsigned int npins;:引脚描述符数组的大小,即描述符数量。
const struct pinctrl_ops *pctlops;:引脚控制操作的虚拟函数表指针。用于支持引脚分组等全局概念。这是可选的,因此可以为NULL。
const struct pinmux_ops *pmxops;:引脚复用操作的虚拟函数表指针。如果驱动程序支持引脚复用,则可以使用该函数表提供相关的操作。同样,这也是可选的,可以为NULL。
const struct pinconf_ops *confops;:引脚配置操作的虚拟函数表指针。如果驱动程序支持引脚配置,则可以使用该函数表提供相关的操作。同样,这也是可选的,可以为NULL。
struct module *owner;:引脚控制器所属的模块,用于引用计数。
unsigned int num_custom_params;:驱动程序特定的自定义参数的数量。这些参数是从硬件描述中解析出来的。
const struct pinconf_generic_params *custom_params;:驱动程序特定的自定义参数列表。这些参数是从硬件描述中解析出来的。
const struct pin_config_item *custom_conf_items;:用于在debugfs中打印参数信息的配置项。它与custom_params的大小相同(即num_custom_params),用于与自定义参数对应。
该结构体用于描述引脚控制器的属性和操作,包括引脚描述符、操作函数表、自定义参数等。不同的驱动程序可以根据需要选择性地填充和使用这些字段。

你可能感兴趣的:(#,pinctrl子系统,Linux驱动,驱动开发,arm开发,嵌入式,Linux,Linux驱动,bsp,pinctrl,IMX6ULL)