GPIO子系统

一、旧版的gpio子系统

1、函数接口

static inline int  of_get_gpio(struct device_node *np, int index) //从设备树获取 gpio
static inline int  gpio_request(unsigned gpio, const char *label)   //拿到gpio引脚使用权
static inline void gpio_free(unsigned gpio)            //释放gpio引脚使用权
static inline int  gpio_direction_input(unsigned gpio)  //将gpio设置为输入
static inline int  gpio_direction_output(unsigned gpio, int value)  //将gpio设置为输出,同时输出高低电平
static inline int  gpio_get_value(unsigned gpio)         //获取gpio引脚的数据
static inline void gpio_set_value(unsigned gpio, int value)  //设置gpio引脚的数据

2、设备树节点

led_test2:stm32mp157_led_test2 {
        compatible = "stm32mp157_led_test,old_gpios";
        led_name = "led_dev";
        //gpio = <&gpioz 5 GPIO_ACTIVE_HIGH>, <&gpioz 6 GPIO_ACTIVE_HIGH>, <&gpioz 7 GPIO_ACTIVE_HIGH>; //不可以这样写
        gpios = <&gpioz 5 GPIO_ACTIVE_HIGH>, <&gpioz 6 GPIO_ACTIVE_HIGH>, <&gpioz 7 GPIO_ACTIVE_HIGH>;
    };

 使用 gpios,不能使用 gpio

3、使用方法

int gpioz_5;
int gpioz_6;
int gpioz_7;

int led_pdrv_probe(struct platform_device *pdev)
{
    /...其他代码.../
    gpioz_5 = of_get_gpio(np, 0);
    gpioz_6 = of_get_gpio(np, 1);
    gpioz_7 = of_get_gpio(np, 2);

    gpio_request(gpioz_5, "gpioz_5");
    gpio_request(gpioz_6, "gpioz_6");
    gpio_request(gpioz_7, "gpioz_7");

    gpio_direction_output(gpioz_5, 0);
    gpio_direction_output(gpioz_6, 0);
    gpio_direction_output(gpioz_7, 0);
    /...其他代码.../
}

int led_pdrv_remove(struct platform_device *pdev)
{
    /...其他代码.../
    gpio_free(gpioz_5);
    gpio_free(gpioz_6);
    gpio_free(gpioz_7);
    /...其他代码.../
}

//使用 platform_device 时用于匹配 pdev.name
const struct platform_device_id led_id_table[] = {
    {"led_pdev", 0x12},
    {"led_pdev1", 0x34},
};

//设备树 compatible 匹配
const struct of_device_id led_of_match_table[] = {
    {.compatible = "stm32mp157_led_test,old_gpios",},
};

struct platform_driver led_pdrv = {
    .probe = led_pdrv_probe,
    .remove = led_pdrv_remove,
    .driver = {
        .name = "led_driver_override",
        .of_match_table = led_of_match_table,
    },
    .id_table = led_id_table,
};

static int __init led_pdrv_init(void)
{
    printk("---------[%s]--------------\n", __FUNCTION__);

    return platform_driver_register(&led_pdrv);
}

static void __exit led_pdrv_exit(void)
{
    printk("---------[%s]--------------\n", __FUNCTION__);

    platform_driver_unregister(&led_pdrv);
}

module_init(led_pdrv_init);
module_exit(led_pdrv_exit);
MODULE_LICENSE("GPL");

使用 gpio_request 的意义在于,用于申请一个GPIO资源,确保在后续的操作中该资源不会被其他设备或驱动占用,起到引用计数+1的效果。

 二、新版的gpio子系统

1、函数接口

struct gpio_desc *gpiod_get(struct device *dev,const char *con_id, enum gpiod_flags flags);//获取gpio引脚对象指针
struct gpio_desc *gpiod_get_index(struct device *dev,const char *con_id, int index, enum gpiod_flags flags);

static inline void gpiod_put(struct gpio_desc *desc)      //释放gpio引脚对象
int gpiod_direction_input(struct gpio_desc *desc);      //将gpio设置为输入
int gpiod_direction_output(struct gpio_desc *desc, int value);	  //将gpio设置为输出,同时输出高低电平
int gpiod_get_value(const struct gpio_desc *desc);     //获取gpio引脚的数据
void gpiod_set_value(struct gpio_desc *desc, int value);  //设置gpio引脚的数据

struct gpio_desc *devm_gpiod_get(struct device *dev,  const char *con_id,enum gpiod_flags flags);//获取gpio引脚对象指针
struct gpio_desc *devm_gpiod_get_index(struct device *dev,  const char *con_id, int index, enum gpiod_flags flags);

void devm_gpiod_put(struct device *dev, struct gpio_desc *desc);  //释放gpio引脚对象

 devm_gpiod_get和 devm_gpiod_get_index 调用后,当设备被销毁或卸载时,内核会自动遍历并释放该设备所持有的所有资源。

如果想在设备被销毁或卸载时前释放资源,应调用 devm_gpiod_put

2、设备树节点

led_test3:stm32mp157_led_test3_name {
        compatible = "stm32mp157_led_test,new_gpios";
        led_name = "led_dev";
        //gpios = <&gpioz 5 GPIO_ACTIVE_HIGH>, <&gpioz 6 GPIO_ACTIVE_HIGH>, <&gpioz 7 GPIO_ACTIVE_HIGH>;
        //gpio = <&gpioz 5 GPIO_ACTIVE_HIGH>, <&gpioz 6 GPIO_ACTIVE_HIGH>, <&gpioz 7 GPIO_ACTIVE_HIGH>;
        //led-gpio = <&gpioz 5 GPIO_ACTIVE_HIGH>, <&gpioz 6 GPIO_ACTIVE_HIGH>, <&gpioz 7 GPIO_ACTIVE_HIGH>;
        led-gpios = <&gpioz 5 GPIO_ACTIVE_HIGH>, <&gpioz 6 GPIO_ACTIVE_HIGH>, <&gpioz 7 GPIO_ACTIVE_HIGH>;
    };

 可以使用 gpios,gpio,led-gpio,led-gpios

3、使用方法

struct gpio_desc gpioz[3];

int led_pdrv_probe(struct platform_device *pdev)
{
    int i = 0;
    /...其他代码.../
    for (i = 0; i < ARRAY_SIZE(gpioz); ++i)
    {
        //gpioz[i] = devm_gpiod_get_index(&pdev->dev, NULL, i, GPIOD_OUT_LOW);
        gpioz[i] = devm_gpiod_get_index(&pdev->dev, "led", i, GPIOD_OUT_LOW);
        //gpioz[i] = gpiod_get_index(&pdev->dev, "led", i, GPIOD_OUT_LOW);

        gpiod_direction_output(gpioz[i], 0);
    }
    /...其他代码.../
}

int led_pdrv_remove(struct platform_device *pdev)
{
    /...其他代码.../
    //devm_gpiod_put(&pdev->dev, led->gpioz[i]);//调用 devm_gpiod_get_index 会自动释放内存资源
    //gpiod_put(led->gpioz[i]);
    /...其他代码.../
}

//使用 platform_device 时用于匹配 pdev.name
const struct platform_device_id led_id_table[] = {
    {"led_pdev", 0x12},
    {"led_pdev1", 0x34},
};

//设备树 compatible 匹配
const struct of_device_id led_of_match_table[] = {
    {.compatible = "stm32mp157_led_test,old_gpios",},
};

struct platform_driver led_pdrv = {
    .probe = led_pdrv_probe,
    .remove = led_pdrv_remove,
    .driver = {
        .name = "led_driver_override",
        .of_match_table = led_of_match_table,
    },
    .id_table = led_id_table,
};

static int __init led_pdrv_init(void)
{
    printk("---------[%s]--------------\n", __FUNCTION__);

    return platform_driver_register(&led_pdrv);
}

static void __exit led_pdrv_exit(void)
{
    printk("---------[%s]--------------\n", __FUNCTION__);

    platform_driver_unregister(&led_pdrv);
}

module_init(led_pdrv_init);
module_exit(led_pdrv_exit);
MODULE_LICENSE("GPL");

 当设备树描述为gpio/gpios时,使用 gpioz[i] = devm_gpiod_get_index(&pdev->dev, NULL, i, GPIOD_OUT_LOW);

调用 gpiod_get_index 后,需要使用 gpiod_put 释放资源。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

搁い浅

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值