zoukankan      html  css  js  c++  java
  • Linux内核gpiolib注册建立过程

    1、相关的数据结构

     1 struct s3c_gpio_chip {                  //  这个结构体是三星在移植gpiolib时封装的一个结构体  用来描述一组gpio端口信息
     2     struct gpio_chip    chip;         
     3     struct s3c_gpio_cfg    *config;    //  三星封装的用来配置一个gpio端口的结构体    主要是上下拉模式配置
     4     struct s3c_gpio_pm    *pm;         //   这个是电源管理相关的数据结构
     5     void __iomem        *base;      //  gpio相关寄存器的虚拟基地址
     6     int            eint_offset;      
     7     spinlock_t         lock;
     8 #ifdef CONFIG_PM
     9     u32            pm_save[7];
    10 #endif
    11 };
     1 struct gpio_chip {                                 //  内核提供的用来描述一组gpio端口信息的结构体
     2     const char        *label;              //  一个标号  也就是gpio端口的名字 
     3     struct device        *dev;                //  device指针指向这个gpio端口设备
     4     struct module        *owner;
     5 
     6     int            (*request)(struct gpio_chip *chip,         //  请求gpio   申请
     7                         unsigned offset); 
     8     void            (*free)(struct gpio_chip *chip,             //  释放
     9                         unsigned offset);
    10 
    11     int            (*direction_input)(struct gpio_chip *chip,      //  用于将gpio配置为输入模式
    12                         unsigned offset);
    13     int            (*get)(struct gpio_chip *chip,                 //  获取gpio电平状态 
    14                         unsigned offset);
    15     int            (*direction_output)(struct gpio_chip *chip,  //  用于将gpio配置为输出模式
    16                         unsigned offset, int value);
    17     int            (*set_debounce)(struct gpio_chip *chip,     //  用于消抖
    18                         unsigned offset, unsigned debounce);
    19 
    20     void            (*set)(struct gpio_chip *chip,           // 设置gpio的电平
    21                         unsigned offset, int value);
    22 
    23     int            (*to_irq)(struct gpio_chip *chip,   //  如果该gpio是一个外部中断源,则使用这个函数来获取对应的中断号
    24                         unsigned offset);
    25 
    26     void            (*dbg_show)(struct seq_file *s,
    27                         struct gpio_chip *chip);
    28     int            base;                     //  这组gpio端口的  基准编号 (这个编号是内核设计的)
    29     u16            ngpio;                   //  这组端口的gpio数量
    30     const char        *const *names;
    31     unsigned        can_sleep:1;
    32     unsigned        exported:1;
    33 };
     1 struct s3c_gpio_cfg {
     2     unsigned int    cfg_eint;     //  用于外部中断源时的一个配置值
     3 
     4     s3c_gpio_pull_t    (*get_pull)(struct s3c_gpio_chip *chip, unsigned offs);   //  读取下拉状态时gpio的电流
     5     int        (*set_pull)(struct s3c_gpio_chip *chip, unsigned offs,           // 设置下拉状态gpio电流
     6                     s3c_gpio_pull_t pull);
     7 
     8     int        (*set_pin)(struct s3c_gpio_chip *chip, unsigned offs,
     9                     s3c_gpio_pull_t level);
    10 
    11     unsigned (*get_config)(struct s3c_gpio_chip *chip, unsigned offs);   //  获取gpio的当前配置
    12     int     (*set_config)(struct s3c_gpio_chip *chip, unsigned offs,           //  设置gpio的当前配置
    13                    unsigned config);
    14 };

    2、函数调用关系图

    smdkc110_map_io

        s5pv210_gpiolib_init

            samsung_gpiolib_add_4bit_chips

                samsung_gpiolib_add_4bit

                s3c_gpiolib_add

                    gpiochip_add        //  这个函数就是内核的gpiolib驱动框架提供的用来注册gpiolib的函数

    3、函数详解

    smdkc110_map_io:

     1 static void __init smdkc110_map_io(void)
     2 {
     3     s5p_init_io(NULL, 0, S5P_VA_CHIPID);                 //  静态物理地址到虚拟地址的映射初始化
     4     s3c24xx_init_clocks(24000000);                          //   系统时钟初始化
     5     s5pv210_gpiolib_init();                                       //   gpiolib管理器初始化
     6     s3c24xx_init_uarts(smdkc110_uartcfgs, ARRAY_SIZE(smdkc110_uartcfgs));
     7     s5p_reserve_bootmem(smdkc110_media_devs, ARRAY_SIZE(smdkc110_media_devs));
     8 #ifdef CONFIG_MTD_ONENAND
     9     s5pc110_device_onenand.name = "s5pc110-onenand";
    10 #endif
    11 #ifdef CONFIG_MTD_NAND
    12     s3c_device_nand.name = "s5pv210-nand";
    13 #endif
    14     s5p_device_rtc.name = "smdkc110-rtc";
    15 }

    s5pv210_gpiolib_init:

     1 __init int s5pv210_gpiolib_init(void)
     2 {
     3     struct s3c_gpio_chip *chip = s5pv210_gpio_4bit;    //  4bit表示的是一个gpio使用4位来配置描述     s5pv210_gpio_4bit是一个struct s3c_gpio_chip数组,是三星移植时写好的
     4     int nr_chips = ARRAY_SIZE(s5pv210_gpio_4bit);     //  获取端口数量(注意一组端口和一个具体的gpio)
     5     int i = 0;
     6 
     7     for (i = 0; i < nr_chips; i++, chip++) {
     8         if (chip->config == NULL)              //  如果我们的gpio端口没有  配置方法  则使用  gpio_cfg  进行默认配置
     9             chip->config = &gpio_cfg;
    10         if (chip->base == NULL)                 //  如果我们的gpio端口结构体中没有填充 基准编号   则使用下面进行填充
    11             chip->base = S5PV210_BANK_BASE(i);
    12     }
    13 
    14     samsung_gpiolib_add_4bit_chips(s5pv210_gpio_4bit, nr_chips);   //  添加gpiolib
    15 
    16     return 0;
    17 }

    samsung_gpiolib_add_4bit_chips:

     1 void __init samsung_gpiolib_add_4bit_chips(struct s3c_gpio_chip *chip,
     2                        int nr_chips)
     3 {
     4     for (; nr_chips > 0; nr_chips--, chip++) {    // 对于每一个gpio端口组都调用下面的两个函数
     5         samsung_gpiolib_add_4bit(chip);      //   给gpio端口配置输入输出模式配置方法           
     6         s3c_gpiolib_add(chip);       //  最终是通过这个函数去添加gpiolib
     7     }
     8 }
     9 
    10 
    11 void __init samsung_gpiolib_add_4bit(struct s3c_gpio_chip *chip)
    12 {
    13     chip->chip.direction_input = samsung_gpiolib_4bit_input;             //  给gpio端口加入配置gpio为输入模式的方法
    14     chip->chip.direction_output = samsung_gpiolib_4bit_output;       //  给gpio端口加入配置gpio为输出模式的方法
    15     chip->pm = __gpio_pm(&s3c_gpio_pm_4bit);            //  电源管理相关
    16 }

    s3c_gpiolib_add:

     1 __init void s3c_gpiolib_add(struct s3c_gpio_chip *chip)
     2 {
     3     struct gpio_chip *gc = &chip->chip;          //  使用gc指针指向 chip->chip
     4     int ret;
     5 
     6     BUG_ON(!chip->base);
     7     BUG_ON(!gc->label);
     8     BUG_ON(!gc->ngpio);
     9 
    10     spin_lock_init(&chip->lock);
    11 
    12 //  如果我们的结构体中还没有加入相应的方法  则在下面加入方法
    13     if (!gc->direction_input)
    14         gc->direction_input = s3c_gpiolib_input;
    15     if (!gc->direction_output)
    16         gc->direction_output = s3c_gpiolib_output;
    17     if (!gc->set)
    18         gc->set = s3c_gpiolib_set;
    19     if (!gc->get)
    20         gc->get = s3c_gpiolib_get;
    21 
    22 #ifdef CONFIG_PM         //  电源管理相关
    23     if (chip->pm != NULL) {
    24         if (!chip->pm->save || !chip->pm->resume)
    25             printk(KERN_ERR "gpio: %s has missing PM functions
    ",
    26                    gc->label);
    27     } else
    28         printk(KERN_ERR "gpio: %s has no PM function
    ", gc->label);
    29 #endif
    30 
    31     /* gpiochip_add() prints own failure message on error. */
    32     ret = gpiochip_add(gc);     //  最终又是通过这个函数去注册我们的gpiolib管理器    这个函数就是内核gpiolib驱动框架提供的了
    33     if (ret >= 0)
    34         s3c_gpiolib_track(chip);
    35 }

    总结:

    其实我们的gpiolib虽然说是一个gpio的管理者,同样他也是一个设备,在/sys目录下是能够去通过设备的属性方法对具体的gpio进行设置的,三星在移植gpiolib时是使用内核

    提供的gpiolib驱动框架来实现的。

    其实这个注册就是将我们的封装了一个GPIO端口的所有信息的chip结构体变量挂接到内核gpiolib模块定义的一个gpio_desc数组中的某一个格子中。

  • 相关阅读:
    1、第一个JSP
    eclipse汉化
    学习计划与目标
    还在用系统自带的?那你那就OUT了!
    zabbix api调用
    C#中使用泛型对照使用通用基础类型效率减少近一倍
    Android应用架构之MVP---&gt;天气实例
    JavaFX打包到Android上
    2015 Multi-University Training Contest 3
    用Android Studio 执行ndk 程序
  • 原文地址:https://www.cnblogs.com/deng-tao/p/6366905.html
Copyright © 2011-2022 走看看