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 = {