linux驱动(七)gpiolib库详解

摘要:
---恢复内容的开始---1:什么是gpiolib,为什么需要gpiolib?gpiolib库从2.6.35开始在Linux中可用。gpiolib的作用是实现所有gpio的统一管理,因为当驱动程序工作时,几个驱动程序将使用相同的gpio;这会造成混乱。

---恢复内容开始---

1:什么是gpiolib,为什么要有gpiolib?

linux中从2.6.35以后就开始有gpiolib库了,gpiolib的作用是对所有的gpio实行统一管理,因为驱动在工作的时候,会出现好几个驱动共同使用同一个gpio的情况;

这会造成混乱。所以内核提供了一些方法来管理gpio资源;

2:如何学习gpiolib

第一:gpiolib库的建立;

第二:gpiolib库的使用方法:申请、使用、释放;

3:

  我们首先来看一下这个文件:mach-smdkc110.c这个文件:

smdkc110_map_io

    s5pv210_gpiolib_init  这个函数是gpiolib的初始化函数

__init int s5pv210_gpiolib_init(void)
{
    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;
}

gpiolib库的初始化实质就是对这个结构体数组进行赋值;

下面看一下这个结构体

struct s3c_gpio_chip {
    struct gpio_chip    chip;
    struct s3c_gpio_cfg    *config;
    struct s3c_gpio_pm    *pm;
    void __iomem        *base;
    int            eint_offset;
    spinlock_t         lock;
#ifdef CONFIG_PM
    u32            pm_save[7];
#endif
};

 chpi结构体:为主要结构体

关键几个元素

label

request    //申请gpio

free      //释放gpio

direction_input    //输入模式

direction_output    //输出模式

get          //读取gpio的值

set          //写入gpio的值

base        //gpio基地址 端口地址

ngpio        //引脚地址

names        //名字

 
struct gpio_chip {
    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;
};

 linux驱动(七)gpiolib库详解第1张

内核中建立了

static struct s3c_gpio_chip s5pv210_gpio_4bit[] 这个数组,将所有的gpio的.chip结构体中的一些元素初始化

 这个数组的所有元素是与数据手册中的所有gpio是一一对应的;

linux驱动(七)gpiolib库详解第2张

 我们首先来分析一下.chip->base中的值 通过一下几个宏定义我们可以知道gpa0中 chip->.chip->base中的值为 0 gpa1中chip->.chip->base中的值为9 这个数字数对应端口的io口的号码;

#define S5PV210_GPA0(_nr) (S5PV210_GPIO_A0_START + (_nr))
#define S5PV210_GPA1(_nr) (S5PV210_GPIO_A1_START + (_nr)) 

S5PV210_GPIO_A0_START = 0,
S5PV210_GPIO_A1_START = S5PV210_GPIO_NEXT(S5PV210_GPIO_A0),

#define S5PV210_GPIO_NEXT(__gpio)
((__gpio##_START) + (__gpio##_NR) + CONFIG_S3C_GPIO_SPACE + 1) 

#define S5PV210_GPIO_A0_NR (8)
#define S5PV210_GPIO_A1_NR (4)
#define S5PV210_GPIO_B_NR (8)
#define S5PV210_GPIO_C0_NR (5)

 ----------------------------------------------------------------------------------------------------------------------------------------------

 接下来是对

chip->config = &gpio_cfg;

chip->config结构体赋值;

然后是对chip->base 赋值

chip->base = S5PV210_BANK_BASE(i);

 #define S5PV210_BANK_BASE(bank_nr) (S5P_VA_GPIO + ((bank_nr) * 0x20)

 可以看出chip->base是把gpio的虚拟地址赋值给chip->base,每个gpio的地址差0x20;

 下面看一下

samsung_gpiolib_add_4bit_chips(s5pv210_gpio_4bit, nr_chips); 这个函数

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

这个函数中调用了两个函数

samsung_gpiolib_add_4bit_chips

    samsung_gpiolib_add_4bit

    s3c_gpiolib_add

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

这个函数的作用是对每个chip->chip的direction_input direction_output两个函数赋值

下面看一下s3c_gpiolib_add函数都做了什么:

    if (!gc->direction_input)
        gc->direction_input = s3c_gpiolib_input;
    if (!gc->direction_output)
        gc->direction_output = s3c_gpiolib_output;
    if (!gc->set)
        gc->set = s3c_gpiolib_set;
    if (!gc->get)
        gc->get = s3c_gpiolib_get;

继续对chip->中的元素进行赋值,set get赋值,

ret = gpiochip_add(gc);

最后注册这些gpio_chip结构体;

注册的实质是:在linux内核中有一个gpio_desc结构体数组,注册就是把我们封装的gpio的所有信息的结构体放到数组的格子中;

static struct gpio_desc gpio_desc[ARCH_NR_GPIOS];   

gpiolib库是linux内核工程师以及三星芯片厂商工程师共同完成的,内核工程师提供搭建好底层框架,三星工程师

把自己开发板的gpio初始化并注册到内核提供的数组中去;

---------------------------------------------------------------------------------------------------------------

上面讲了gpiolib库的构建,构建的实质是把所有的gpio结构体进行初始化,并且放到内核中gpio_desc这个结构体数组中;

下面看一下我们在开发驱动的时候如何使用gpiolib库

首先要了解一下linux内核工程师给我们开发的接口:
文件:/drivers/gpio/gpiolib.c文件中提供所有的接口

1:gpio_request:向内核申请gpio

int gpio_request(unsigned gpio, const char *label)

2:gpio_free对应gpio_request,是使用完gpio以后把gpio释放掉

void gpio_free(unsigned gpio)

3:gpiochip_add:向内核注册gpio

int gpiochip_add(struct gpio_chip *chip)

4:gpio_request_one  申请gpio

int gpio_request_one(unsigned gpio, unsigned long flags, const char *label)

5:gpio_request_one申请gpio

int gpio_request_one(unsigned gpio, unsigned long flags, const char *label)

6:gpiochip_is_requested:用来看gpio是否已经使用

const char *gpiochip_is_requested(struct gpio_chip *chip, unsigned offset)

7:gpio_direction_input :设置gpio输入

int gpio_direction_input(unsigned gpio)

8:gpio_direction_output:gpio输出

int gpio_direction_output(unsigned gpio, int value)

9:__gpio_get_value :获取寄存器的值    这里注意由于前面加了__是内核用的函数所以我们不能用这个函数

在/arch/arm/mach-s5pv210/include/mach/gpio.h中定义了以下宏;所以我们使用的时候直接包含这个头文件使用gpio_get_value 函数即可

#define gpio_get_value __gpio_get_value
#define gpio_set_value __gpio_set_value
#define gpio_cansleep __gpio_cansleep
#define gpio_to_irq __gpio_to_irq

int __gpio_get_value(unsigned gpio)

10:__gpio_get_value :设置寄存器的值

int __gpio_get_value(unsigned gpio)

http://blog.csdn.net/tongxinv/article/details/54790792

---------------------------------------------------------------------------------------------------------------------------------

代码实战:

免责声明:文章转载自《linux驱动(七)gpiolib库详解》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇ASCII Generator dotNet可以把图片转换为ASCII组成的字符文本[转载+原创]Emgu CV on C# (一) —— Emgu CV on Visual C# 2010下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

STM32 串口采用DMA方式收发

FROM:https://blog.csdn.net/gdjason/article/details/51019219 什么是DMA —- Directional Memory Access, 直接存储器存取用来提供在外设和存储器之间或者存储器和存储器之间的高速数据传输。无须CPU干预,数据可以通过DMA快速地移动,这就节省了CPU的资源来做其他操作 我...

(stm32f103学习总结)—ADC模数转换实验

一、STM32F1 ADC介绍  TM32F103 系列一般都有 3 个 ADC,这些 ADC 可以独立使用,也可 以使用双重(提高采样率)。STM32F1 的 ADC 是 12 位逐次 逼近型的模拟数字转换器。它具有多达 18个复用通道,可测量来自16 个外部源、2 个内部源信号。 这些通道的 A/D 转换可 以单次、连续、扫描或间断模式执行。ADC 的...

基于MCP2515的Linux CAN总线驱动程序设计(三)

基于MCP2515的Linux CAN总线驱动程序设计(三) 作者:李老师,华清远见嵌入式学院讲师。 1.前言 上篇文章介绍了使用SPI子系统设计的基于MCP2515的Linux CAN总线驱动程序,这篇文章主要介绍MCP2515的字符设备驱动功能函数的实现。 2.硬件设计 MCP2515与S3C2416的硬件连接图如图3所示。如硬件原理图可知MCP251...

树莓派AI视觉云台——8、WiringPi库函数

一.wiringPi简介wiringPi是应用于树莓派平台的GPIO控制库函数,wiringPi中的函数类似于Arduino的wiringPi系统,wiringPi库包含了丰富的库函数,如GPIO库,I2C库,SPI库,UART库和软件PWM库。 二.wiringPi的版本信息查看其实我们的树莓派系统里面已经自带了wiringPi库,打开命令终端,可以通过...

Linux学习 : 总线-设备-驱动模型

  platform总线是一种虚拟的总线,相应的设备则为platform_device,而驱动则为platform_driver。Linux 2.6的设备驱动模型中,把I2C、RTC、LCD等都归纳为platform_device。总线将设备和驱动绑定,在系统每注册一个设备的时候,会寻找与之匹配的驱动;相反的,在系统每注册一个驱动的时候,会寻找与之匹配的设...

ESP32开发(2)esp32-cam采集图像

ESP32-CAM摄像头开发板 USB转串口下载器 杜邦连接线若干        注意:GPIO0连接GND(下拉)的作用是让ESP32-CAM进入下载启动模式,这个模式里,才能利用Arduino IDE给ESP32编程,否则IDE会报错,代码烧录完成后,我们需要断开GPIO0和GND的连接,让ESP32进入正常的内存启动模式。 配置ESP32环...