您的位置:

pinctrl的介绍与使用

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");