第20章 Linux芯片级移植及底层驱动之pinctrl驱动

本文详细介绍了Linux内核中pinctrl驱动的工作原理和功能,包括配置引脚、引脚分组、引脚配置、与GPIO子系统的交互、引脚复用等关键操作,展示了如何在驱动中实现这些功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

20.7 pinctrl驱动

    许多SoC内部都包含pin(管脚/引脚)控制器,通过pin控制器的寄存器,可以配置一个或者一组引脚的功能和

特性。在软件上,Linux内核的pinctrl驱动可以操作pin控制器完成如下工作:

    枚举并且命名pin控制器可控制的所有引脚;

    提供引脚复用的能力;

    提供配置引脚的能力,如驱动能力、上拉下拉、开漏(Open Drain)等。

1.pinctrl和引脚

    在特定SoC的pinctrl驱动中,需要定义引脚。假设有一个PGA(Pin Grid Array Package 插针网格阵列封装技术)封装的芯片的引脚排布如图20.9所示。


    图20.9 一个PGA封装的芯片的引脚排布

    在pinctrl驱动初始化时,向pinctrl子系统注册一个pinctrl_desc描述符,该描述符的pins成员中包含所有引脚的列表。通过代码清单20.16的方法来注册这个pin控制器并命名它的所有引脚。

代码清单20.16 pinctrl引脚描述

Documentation/driver-api/pinctl.rst

        #include <linux/pinctrl/pinctrl.h>
        const struct pinctrl_pin_desc foo_pins[] = {
                PINCTRL_PIN(0, "A8"),
                PINCTRL_PIN(1, "B8"),
                PINCTRL_PIN(2, "C8"),
                               ...
                PINCTRL_PIN(61, "F1"),
                PINCTRL_PIN(62, "G1"),
                PINCTRL_PIN(63, "H1"),
        };

        static struct pinctrl_desc foo_desc = {
                .name = "foo",
                .pins = foo_pins,
                .npins = ARRAY_SIZE(foo_pins),
                .owner = THIS_MODULE,
        };

        int __init foo_probe(void)
        {
                int error;
                struct pinctrl_dev *pctl;

                error = pinctrl_register_and_init(&foo_desc, <PARENT>, NULL, &pctl);
                if (error)
                        return error;

                return pinctrl_enable(pctl);
        }

2.引脚组(Pin Group)

    在pinctrl子系统中,支持将一组引脚绑定为同一功能。假设{0,8,16,24}这一组引脚承担SPI的功能,而{24,25}这一组引脚承担I 2 C接口功能。在驱动代码中,需体现这个分组关系,并且为这些分组实现pinctrl_ops的成员函数get_groups_count()、get_group_name()和get_group_pins(),将pinctrl_ops填充到前文pinctrl_desc的实例foo_desc中,如代码清单20.17所示。

    代码清单20.17 pinctrl驱动对引脚分组

        #include <linux/pinctrl/pinctrl.h>

        struct foo_group {
                const char *name;
                const unsigned int *pins;
                const unsigned num_pins;
        };

        static const unsigned int spi0_pins[] = { 0, 8, 16, 24 };
        static const unsigned int i2c0_pins[] = { 24, 25 };

        static const struct foo_group foo_groups[] = {
                {
                        .name = "spi0_grp",
                        .pins = spi0_pins,
                        .num_pins = ARRAY_SIZE(spi0_pins),
                },
                {
                        .name = "i2c0_grp",
                        .pins = i2c0_pins,
                        .num_pins = ARRAY_SIZE(i2c0_pins),
                },
        };

        static int foo_get_groups_count(struct pinctrl_dev *pctldev)
        {
                return ARRAY_SIZE(foo_groups);
        }

        static const char *foo_get_group_name(struct pinctrl_dev *pctldev, unsigned selector)
        {
                return foo_groups[selector].name;
        }

        static int foo_get_group_pins(struct pinctrl_dev *pctldev, unsigned selector,
                                const unsigned **pins,
                                unsigned *num_pins)
        {
                *pins = (unsigned *) foo_groups[selector].pins;

                *num_pins = foo_groups[selector].num_pins;

                 return 0;
        }

        static struct pinctrl_ops foo_pctrl_ops = {
                .get_groups_count = foo_get_groups_count,
                .get_group_name = foo_get_group_name,
                .get_group_pins = foo_get_group_pins,
        };

        static struct pinctrl_desc foo_desc = {
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值