当前位置:首页>Linux>嵌入式linux中pinctrl子系统驱动代码

嵌入式linux中pinctrl子系统驱动代码

  • 2026-10-07 11:21:06
嵌入式linux中pinctrl子系统驱动代码
Linux 中的 pinctrl 子系统(Pin Control Subsystem) 是一个用于管理和配置通用输入/输出(GPIO) 引脚的框架。 它提供了一种标准化的方法, 以在 Linux 内核中对 GPIO 引脚进行配置、分配和控制, 从而适应不同的硬件平台和设备。
一、pinctrl 设备树

设备树的 pinctrl可以分为客户端和服务端两个部分:
  • pinctrl 客户端可以指定引脚描述、 引脚组描述和配置描述, 以满足其特定的功能和需求, 不同厂商在客户端内容的编写格式是相同的。
  • pinctrl 服务端是指提供 GPIO 引脚配置的 pinctrl 设备树节点, 它是描述 GPIO 引脚配置和使用规则的节点, 定义了一组 GPIO 引脚的配置选项, 以及这些选项对应的引脚功能和电气特性。
目录:kernel/arch/arm64/boot/dts/rockchip/rk3568.dtsi
在上面的 pinctrl 节点中, 描述了 RK3568 GPIO 控制器的配置和使用方式, pinctrl 节点总共描述了五个 GPIO 控制器, 分别是 gpio0、 gpio1、 gpio2、 gpio3 和 gpio4。 通过这些 GPIO 控制器节点, 可以在设备树中配置和控制 RK3568 芯片上的 GPIO 引脚, 包括设置引脚功能、 中断处理等。
在设备树的最下方通过 include 包含了 rk3568-pinctrl.dtsi 设备树, 该设备树中包含了所有复用功能的配置, 具体内容如下所示:
无论是 rk3568.dtsi 设备树中的 pinctrl 节点, 还是上面 rk3568-pinctrl.dtsi 设备树中的一系列复用关系都是由瑞芯微原厂 BSP 工程师编写的, 我们只需知道如何使用即可, 而 pinctrl 客户端设备树是由我们自己根据特定需求来编写的。
设备树中存放的只是设备的描述信息, 而具体的功能实现取决于相应的 pinctrl 驱动, 根据rk3568.dtsi 设备树中 pinctrl 节点的 compatible 属性进行查找, 可以查找到 pinctrl 的驱动文件是内核源码的“/driver/pinctrl/pinctrl-rockchip.c” , 如下所示:
二、pinctrl 驱动

首先进入到内核源码目录下的“/drivers/pinctrl/pinctrl-rockchip.c” 驱动文件中, 找到驱动的入口函数, 具体内容如下所示:
可以看到 pinctrl 驱动使用的是 platform 总线, 当设备和驱动匹配成功之后会进入rockchip_pinctrl_probe 函数进行初始化, probe 函数的具体内容如下所示:
static int rockchip_pinctrl_probe(struct platform_device *pdev){        struct rockchip_pinctrl *info;  // Rockchip GPIO 控制器的信息结构体指针        struct device *dev = &pdev->dev; // 设备结构体指针        struct rockchip_pin_ctrl *ctrl;  // Rockchip GPIO 控制器的配置结构体指针        struct device_node *np = pdev->dev.of_node, *node; // 设备节点指针        struct resource *res;        void __iomem *base;        int ret;if (!dev->of_node) {                dev_err(dev, "device tree node not found\n");return -ENODEV;        }// 分配并初始化一个 rockchip_pinctrl 结构体        info = devm_kzalloc(dev, sizeof(*info), GFP_KERNEL);if (!info)return -ENOMEM;        info->dev = dev;// 获取并设置与 pdev 相关的 rockchip_pin_ctrl 结构体        ctrl = rockchip_pinctrl_get_soc_data(info, pdev);if (!ctrl) {                dev_err(dev, "driver data not available\n");return -EINVAL;        }        info->ctrl = ctrl;// 解析设备树中的"rockchip,grf"节点, 获取寄存器映射基地址        node = of_parse_phandle(np, "rockchip,grf", 0);if (node) {                info->regmap_base = syscon_node_to_regmap(node);if (IS_ERR(info->regmap_base))return PTR_ERR(info->regmap_base);        } else {                res = platform_get_resource(pdev, IORESOURCE_MEM, 0);                base = devm_ioremap_resource(&pdev->dev, res);if (IS_ERR(base))return PTR_ERR(base);                rockchip_regmap_config.max_register = resource_size(res) - 4;                rockchip_regmap_config.name = "rockchip,pinctrl";                info->regmap_base = devm_regmap_init_mmio(&pdev->dev, base,                                                    &rockchip_regmap_config);/* to check for the old dt-bindings */                info->reg_size = resource_size(res);/* Honor the old binding, with pull registers as 2nd resource */if (ctrl->type == RK3188 && info->reg_size < 0x200) {                        res = platform_get_resource(pdev, IORESOURCE_MEM, 1);                        base = devm_ioremap_resource(&pdev->dev, res);if (IS_ERR(base))return PTR_ERR(base);                        rockchip_regmap_config.max_register =                                                        resource_size(res) - 4;                        rockchip_regmap_config.name = "rockchip,pinctrl-pull";                        info->regmap_pull = devm_regmap_init_mmio(&pdev->dev,                                                    base,                                                    &rockchip_regmap_config);                }        }/* try to find the optional reference to the pmu syscon */        node = of_parse_phandle(np, "rockchip,pmu", 0);if (node) {                info->regmap_pmu = syscon_node_to_regmap(node);if (IS_ERR(info->regmap_pmu))return PTR_ERR(info->regmap_pmu);        }/* Special handle for some Socs */if (ctrl->soc_data_init) {                ret = ctrl->soc_data_init(info);if (ret)return ret;        }        ret = rockchip_pinctrl_register(pdev, info);if (ret)return ret;        platform_set_drvdata(pdev, info);        ret = of_platform_populate(np, rockchip_bank_match, NULL, NULL);if (ret) {                dev_err(&pdev->dev, "failed to register gpio device\n");return ret;        }        dev_info(dev, "probed %s\n", dev_name(dev));return0;}
上面 Probe 函数的作用是初始化和配置 Rockchip GPIO 控制器, 并将相关信息存储在rockchip_pinctrl 结构体中, 最后注册相关设备和GPIO 接口
那 pinctrl 子系统是什么时候对该引脚进行的复用呢?   

最新文章

随机文章