Linux下GPIO驱动(三) ----gpio_desc()的分析

发布者:快乐飞跃最新更新时间:2025-02-05 来源: cnblogs关键字:Linux  GPIO驱动 手机看文章 扫描二维码
随时随地手机看文章

上篇最后提出的疑问是结构体gpio_chip中的成员函数set等是怎么实现的,在回答之前先介绍下gpio_desc这个结构体。 

 

 

     如上图所示,右上方部分为GPIO驱动对其它驱动提供的GPIO操作接口,其对应的右下方部分为GPIO硬件操作接口,也就是说对外提供的接口最终会一一对应的对硬件GPIO进行操作。

     再来看左边部分,左上方部分为一全局数组,记录各个GPIO的描述符,即对应左下方的gpio_desc结构体,其中gpio_chip指向硬件层的GPIO,flags为一标志位,用来指示当前GPIO是否已经占用,当用gpio_request申请GPIO资源时,flags位就会置位,当调用gpio_free释放GPIO资源时,flags就会清零。label是一个字符串指针,用来作说明。

     在软件上,我们首先通过函数gpiochip_add注册一个gpio_chip对应的gpio_desc到全局数组gpio描述符中。其中,一个描述符对应一个GPIO,所以如果我们要使用多个GPIO,那么就在gpio_chip结构体的ngpio指定个数,base为起始的GPIO号。


//每个引脚分配一个gpio_desc数据结构

struct gpio_desc {

    struct gpio_chip    *chip;

    unsigned long        flags;

};

 

/**

 * struct gpio_chip - abstract a GPIO controller

 * @label: for diagnostics

 * @dev: optional device providing the GPIOs

 * @owner: helps prevent removal of modules exporting active GPIOs

 * @request: optional hook for chip-specific activation, such as

 *    enabling module power and clock; may sleep

 * @free: optional hook for chip-specific deactivation, such as

 *    disabling module power and clock; may sleep

 * @direction_input: configures signal 'offset' as input, or returns error

 * @get: returns value for signal 'offset'; for output signals this

 *    returns either the value actually sensed, or zero

 * @direction_output: configures signal 'offset' as output, or returns error

 * @set: assigns output value for signal 'offset'

 * @to_irq: optional hook supporting non-static gpio_to_irq() mappings;

 *    implementation may not sleep

 * @dbg_show: optional routine to show contents in debugfs; default code

 *    will be used when this is omitted, but custom code can show extra

 *    state (such as pullup/pulldown configuration).

 * @base: identifies the first GPIO number handled by this chip; or, if

 *    negative during registration, requests dynamic ID allocation.

 * @ngpio: the number of GPIOs handled by this controller; the last GPIO

 *    handled is (base + ngpio - 1).

 * @can_sleep: flag must be set iff get()/set() methods sleep, as they

 *    must while accessing GPIO expander chips over I2C or SPI

 * @names: if set, must be an array of strings to use as alternative

 *      names for the GPIOs in this chip. Any entry in the array

 *      may be NULL if there is no alias for the GPIO, however the

 *      array must be @ngpio entries long.  A name can include a single printk

 *      format specifier for an unsigned int.  It is substituted by the actual

 *      number of the gpio.

 *

 * A gpio_chip can help platforms abstract various sources of GPIOs so

 * they can all be accessed through a common programing interface.

 * Example sources would be SOC controllers, FPGAs, multifunction

 * chips, dedicated GPIO expanders, and so on.

 *

 * Each chip controls a number of signals, identified in method calls

 * by 'offset' values in the range 0..(@ngpio - 1).  When those signals

 * are referenced through calls like gpio_get_value(gpio), the offset

 * is calculated by subtracting @base from the gpio number.

 */

struct gpio_chip {

//这些函数实现在archarmmach-s5pv210gpiolib.c    

    const char        *label;

    struct device        *dev;

    struct module        *owner;


    int            (*request)(struct gpio_chip *chip,

                        unsigned offset);

    void            (*free)(struct gpio_chip *chip,

                        unsigned offset);


    int            (*direction_input)(struct gpio_chip *chip,

                        unsigned offset);

    int            (*get)(struct gpio_chip *chip,

                        unsigned offset);

    int            (*direction_output)(struct gpio_chip *chip,

                        unsigned offset, int value);

    int            (*set_debounce)(struct gpio_chip *chip,

                        unsigned offset, unsigned debounce);


    void            (*set)(struct gpio_chip *chip,

                        unsigned offset, int value);


    int            (*to_irq)(struct gpio_chip *chip,

                        unsigned offset);


    void            (*dbg_show)(struct seq_file *s,

                        struct gpio_chip *chip);

    int            base;

    u16            ngpio;

    const char        *const *names;

    unsigned        can_sleep:1;

    unsigned        exported:1;

};


下面分析gpio_desc中成员chip的成员函数的实现:


__init int s5pv210_gpiolib_init(void)//在Linux初始化期间,此函数就执行了

{

    struct s3c_gpio_chip *chip = s5pv210_gpio_4bit;

    int nr_chips = ARRAY_SIZE(s5pv210_gpio_4bit);

    int i = 0;


    for (i = 0; i < nr_chips; i++, chip++) {

        if (chip->config == NULL)

            chip->config = &gpio_cfg;

        if (chip->base == NULL)

            chip->base = S5PV210_BANK_BASE(i);

    }


    samsung_gpiolib_add_4bit_chips(s5pv210_gpio_4bit, nr_chips);


    return 0;

}


void __init samsung_gpiolib_add_4bit_chips(struct s3c_gpio_chip *chip,

                       int nr_chips)

{

    for (; nr_chips > 0; nr_chips--, chip++) {

        samsung_gpiolib_add_4bit(chip);

        s3c_gpiolib_add(chip);


    }

}


void __init samsung_gpiolib_add_4bit(struct s3c_gpio_chip *chip)

{

    chip->chip.direction_input = samsung_gpiolib_4bit_input;

    chip->chip.direction_output = samsung_gpiolib_4bit_output;

    chip->pm = __gpio_pm(&s3c_gpio_pm_4bit);

}


__init void s3c_gpiolib_add(struct s3c_gpio_chip *chip)

{

    struct gpio_chip *gc = &chip->chip;

    int ret;


    BUG_ON(!chip->base);

    BUG_ON(!gc->label);

    BUG_ON(!gc->ngpio);


    spin_lock_init(&chip->lock);// 初始化s3c_gpio_chip的自旋锁

if (!gc->direction_input)

        gc->direction_input = s3c_gpiolib_input;//chip->direction_input

    if (!gc->direction_output)

        gc->direction_output = s3c_gpiolib_output;//chip->direction_output

    if (!gc->set)

        gc->set = s3c_gpiolib_set;//chip->set此处就回答了上篇的疑问

    if (!gc->get)

        gc->get = s3c_gpiolib_get;//chip->get


#ifdef CONFIG_PM

    if (chip->pm != NULL) {

        if (!chip->pm->save || !chip->pm->resume)

            printk(KERN_ERR 'gpio: %s has missing PM functionsn',

                   gc->label);

    } else

        printk(KERN_ERR 'gpio: %s has no PM functionn', gc->label);

#endif


    /* gpiochip_add() prints own failure message on error. */

    ret = gpiochip_add(gc);

    if (ret >= 0)

        s3c_gpiolib_track(chip);

}


/**

 * gpiochip_add() - register a gpio_chip

 * @chip: the chip to register, with chip->base initialized

 * Context: potentially before irqs or kmalloc will work

 *

 * Returns a negative errno if the chip can't be registered, such as

 * because the chip->base is invalid or already associated with a

 * different chip.  Otherwise it returns zero as a success code.

 *

 * When gpiochip_add() is called very early during boot, so that GPIOs

 * can be freely used, the chip->dev device must be registered before

 * the gpio framework's arch_initcall().  Otherwise sysfs initialization

 * for GPIOs will fail rudely.

 *

 * If chip->base is negative, this requests dynamic assignment of

 * a range of valid GPIOs.

 */

int gpiochip_add(struct gpio_chip *chip) // 在gpio_desc[]中分配空间,并链接chip结构;注册一个gpio_chip对应的gpio_desc到全局数组gpio描述符中

{

    unsigned long    flags;

    int        status = 0;

    unsigned    id;

    int        base = chip->base;


    if ((!gpio_is_valid(base) || !gpio_is_valid(base + chip->ngpio - 1))

            && base >= 0) {

        status = -EINVAL;

        goto fail;

    }


    spin_lock_irqsave(&gpio_lock, flags);


    if (base < 0) {

        base = gpiochip_find_base(chip->ngpio);// 这个函数在gpiolib.c中,在gpio_desc[]中分配chip->ngpio个空间(从最后往前分配),返回第一个index

[1] [2]
关键字:Linux  GPIO驱动 引用地址:Linux下GPIO驱动(三) ----gpio_desc()的分析

上一篇:Linux下GPIO驱动(二) ----s3c_gpio_cfgpin();gpio_set_value();
下一篇:Linux下GPIO驱动(四) ----gpio_request();gpio_free();

推荐阅读最新更新时间:2026-03-25 11:02

LinuxGPIO驱动(二) ----s3c_gpio_cfgpin();gpio_set_value();
首先来看s3c_gpio_cfgpin(); int s3c_gpio_cfgpin(unsigned int pin, unsigned int config) { struct s3c_gpio_chip *chip = s3c_gpiolib_getchip(pin);//得到对应GPIO结构体首指针,里面包含了该GPIO的各种参数 unsigned long flags; int offset; int ret; if (!chip) return -EINVAL; offset = pin - chip- chip.base; s3c_gpio_lock(chip, f
[单片机]
LinuxGPIO驱动(一) ----一个简单的LED驱动
/******************************* * *杂项设备驱动:miscdevice *majior=10; * * *****************************/ #include linux/kernel.h #include linux/module.h #include linux/fs.h #include linux/types.h #include linux/init.h //#include linux/moduleparam.h //#include linux/slab.h //kcalloc,kzalloc等内存分配函数 //------
[单片机]
基于STM32Cubemx HAL 库实现 DMA 驱动 GPIO 高速翻转
说明:本文主要内容是从简单介绍有关STM32的DMAMUX模块-电子发烧友网 (elecfans.com)这篇文章摘录。我是小白,在索引HAL DMA GPIO 翻转时,没有找到本文,而在所有DMAMUX才索引到此文。为了方便后续小白能够及时找到此文。我重新做了编译。并做了相关程序的验证。对相关数据做了说明。感谢本文应用的3片文章的作者! 目前STM32家族中的很多系列,比如STM32G0/STM32G4/STM32L4+/STM32H7等都内置了DMAMUX模块。有了它一方面使得DMA请求与DMA控制器之间的映射关系更为灵活方便,另一方面也大大拓展了DMA请求事件,不再局限于外设事件,比方基于GPIO的外部中断事件、或者DM
[单片机]
基于STM32Cubemx HAL 库实现 DMA <font color='red'>驱动</font> <font color='red'>GPIO</font> 高速翻转
【改进Poll定时查询】IMX257实现GPIO-IRQ中断按键获取键值驱动程序
按键驱动程序中,如果不使用read函数中使程序休眠的,而是还是使用查询方式的话,可以使用Poll函数,来控制一定时间内,如果有按键发生,则立即返回键值。 同时,poll也可以同时监控多个(比如说按键,鼠标,等)一旦发生事件则立即返回。 我们在linux查看帮助: 从帮助中的说明得知, poll, ppoll - wait for some event on a file descriptor poll就是监控某个设备的事件。 修改驱动程序 1.增加头文件 #include linux/poll.h 2.增加key_poll 方法 static unsigned key_poll(struct file *fil
[单片机]
【改进Poll定时查询】IMX257实现<font color='red'>GPIO</font>-IRQ中断按键获取键值<font color='red'>驱动</font>程序
NO.7 MSP432使用GPIO驱动开发板Led
  这是最基本的单片机运用,点亮第一个LED。   由于存在TIDriver的帮助和SysConfigs的一键配置,我们的开发非常简单。   首先,我们要了解什么是GPIO。GPIO全称General-purpose input/output,指的是通用输入输出端口。指的是我们单片机上既能作为输出(输出电压),又能作为输入(检测电压)的端口称为GPIO。GPIO具有很多种用途,比如点亮LED,检测按键输入,甚至可以软件模拟通信协议(通过在不同时刻下,置不同端口的高低电平作为信号进行数据传输)。所以,了解通用的GPIO口对于我们单片机使用是非常重要的。   这里我不会具体介绍GPIO的常用模式,我会直接讲解GPIO在MS
[单片机]
NO.7 MSP432使用<font color='red'>GPIO</font><font color='red'>驱动</font>开发板Led
关于驱动中调用内核函数实现gpio寄存器的设置
系列函数 系列函数的定义在arch/arm/mach-s3c2410/gpio.c,相关的宏定义在include/asm-arm/arch-s3c2410/regs-gpio.h (1)void s3c2410_gpio_setpin(unsigned int pin, unsigned intto); 设置相应GPIO口的输出值,例如: pin=S3C2410_GPG2,to=0,则设置S3C2410_GPG2的输出值为0; pin=S3C2410_GPG2,to=1,则设置S3C2410_GPG2的输出值为1。 函数定义: viewplain void s3c2410_gpio_setpin(unsigned int pi
[单片机]
lPC1788的GPIO驱动
#include led.h void led_init(void) { //p1.14 p0.16 p1.13 p4.27 LPC_SC- PCONP |= (1 15);//打开时钟 //选择管脚模式,1788为每个管脚都设计了一个寄存器来选择管脚模式 LPC_IOCON- P1_14 = 0x00;//选择gpio功能,禁止迟滞 不反向 正常推挽 LPC_IOCON- P1_14 |= (2 3);//上拉 P1dir(14) = 1; //输出 P1low(14) = 1;//设置为低电平 LPC_IOCON- P0_16 = 0x00;//选择gpio功能,禁止迟滞 不反向
[单片机]
Linux嵌入式开发必备命令速查表
在中, 系统几乎成为必备的开发环境。不管你是在做 、Raspberry 、还是基于 的板子,熟练掌握 Linux 命令不仅能加快开发效率,还能让你在调试、交叉编译、文件管理等环节轻松应对各种问题。今天,我们整理了一份Linux 下开发必备命令速查表,让你一篇文章就能快速查阅。 一、文件与目录管理命令 在嵌入式开发中,你经常需要操作源码、Makefile、库文件等,文件管理命令必不可少。 命令 功能 示例 备注 ls 列出目录内容 ls-l/home/user/project -l 显示详细信息 cd 切换目录 cd/home/user/project 相对路径或绝
[嵌入式]
小广播
最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

厂商技术中心

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

 
机器人开发圈

电子工程世界版权所有 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2026 EEWORLD.com.cn, Inc. All rights reserved