当前位置:   article > 正文

Linux内核gpiolib注册建立过程

芯片gpio注册到内核流程

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\n",
26                    gc->label);
27     } else
28         printk(KERN_ERR "gpio: %s has no PM function\n", 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数组中的某一个格子中。

 

转载于:https://www.cnblogs.com/deng-tao/p/6366905.html

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/AllinToyou/article/detail/128718
推荐阅读
相关标签
  

闽ICP备14008679号