1、pinctrl的概述
pinctrl即Pin Control,是Linux内核中用于管理芯片引脚的一个框架。它通过驱动程序来管理芯片引脚的模式和状态,从而为内核中其他驱动程序提供方便。
pinctrl框架支持按编译时硬编码、设备树以及绑定在驱动程序中等方式来进行配置,同时也支持使用sysfs和ioctl等方式来动态配置。这一框架在创建新的硬件平台、实现新的芯片支持以及进行动态GPIO配置等方面非常的方便。
2、pinctrl的使用
在Linux内核中,pinctrl的使用通常需要经过以下几个步骤:
3、Linux内核中的pinctrl例子:
以下是一个简单的pinctrl例子,它使用基于设备树的pinctrl配置方式,实现对GPIO控制的初始化和操作。
/* 步骤1:定义一个pinctrl配置 */
static const struct pinctrl_gpio_state gpio_out[] = {
{ .gpio = 25, .flags = GPIOF_OUT_INIT_LOW, .name = "out1" },
{ .gpio = 26, .flags = GPIOF_OUT_INIT_LOW, .name = "out2" },
};
static const struct pinctrl_state my_pinctrl_states[] = {
{
.name = "pinctrl_gpio_out",
.state = gpio_out,
.nstates = ARRAY_SIZE(gpio_out),
},
};
/* 步骤2:绑定pinctrl */
static int my_device_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct pinctrl *p = NULL;
struct pinctrl_state *state = NULL;
/* 获取pinctrl */
p = devm_pinctrl_get(dev);
if (IS_ERR(p)) {
dev_err(dev, "no pinctrl mapping found\n");
return PTR_ERR(p);
}
/* 获取配置文件 */
state = pinctrl_lookup_state(p, "pinctrl_gpio_out");
if (IS_ERR(state)) {
dev_err(dev, "no pinctrl state found\n");
return PTR_ERR(state);
}
/* 应用pinctrl配置 */
return pinctrl_select_state(p, state);
}
/* 步骤3:使用pinctrl进行GPIO控制 */
static ssize_t output_show(struct device *dev, struct device_attribute *attr, char *buf)
{
struct my_device *my_dev = dev_get_drvdata(dev);
if (gpio_get_value(my_dev->gpio_out1))
return sprintf(buf, "1\n");
else
return sprintf(buf, "0\n");
}
static ssize_t output_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
struct my_device *my_dev = dev_get_drvdata(dev);
int val;
if (kstrtoint(buf, 10, &val))
return -EINVAL;
gpio_set_value(my_dev->gpio_out1, val);
return count;
}
static DEVICE_ATTR(output, 0664, output_show, output_store);
static struct attribute *my_device_attrs[] = {
&dev_attr_output.attr,
NULL
};
static const struct attribute_group my_device_attr_group = {
.attrs = my_device_attrs,
};
static int my_device_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct my_device *my_dev = NULL;
int ret = 0;
/* 分配my_device结构体 */
my_dev = devm_kzalloc(dev, sizeof(struct my_device), GFP_KERNEL);
if (!my_dev) {
dev_err(dev, "failed to allocate memory\n");
return -ENOMEM;
}
/* 注册设备 */
my_dev->dev = device_create_with_groups(my_class, NULL, 0, my_dev, &my_device_attr_group, "my-device");
if (IS_ERR(my_dev->dev)) {
dev_err(dev, "failed to register device\n");
return PTR_ERR(my_dev->dev);
}
/* 获取GPIO */
my_dev->gpio_out1 = of_get_gpio(dev->of_node, 0);
if (!gpio_is_valid(my_dev->gpio_out1)) {
dev_err(dev, "failed to get gpio-out1\n");
return -EINVAL;
}
/* 自动请求GPIO并输出初始化值 */
ret = devm_gpio_request_one(dev, my_dev->gpio_out1, GPIOF_OUT_INIT_LOW, "out1");
if (ret) {
dev_err(dev, "failed to request gpio-out1\n");
return ret;
}
return 0;
}
static int my_device_remove(struct platform_device *pdev)
{
struct my_device *my_dev = platform_get_drvdata(pdev);
/* 删除设备 */
device_destroy(my_class, my_dev->dev->devt);
return 0;
}
static const struct of_device_id my_of_match[] = {
{ .compatible = "my-device", },
{},
};
MODULE_DEVICE_TABLE(of, my_of_match);
static struct platform_driver my_driver = {
.driver = {
.name = "my-device",
.owner = THIS_MODULE,
.of_match_table = my_of_match,
},
.probe = my_device_probe,
.remove = my_device_remove,
};
module_platform_driver(my_driver);
MODULE_DESCRIPTION("My Test Driver");
MODULE_AUTHOR("Alice");
MODULE_LICENSE("GPL");