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

原創文章,作者:小藍,如若轉載,請註明出處:https://www.506064.com/zh-hant/n/251919.html

(0)
打賞 微信掃一掃 微信掃一掃 支付寶掃一掃 支付寶掃一掃
小藍的頭像小藍
上一篇 2024-12-13 17:33
下一篇 2024-12-13 17:33

發表回復

登錄後才能評論