首页 > 代码库 > 驱动学习之gpiolib的建立过程
驱动学习之gpiolib的建立过程
1:gpiolib的学习重点
(1)gpiolib的建立过程:gpiolib和虚拟地址映射类似,也是需要一个建立
过程的,因此在学习的时候,我们需要明白gpiolib是什么时候建立的,建立函数在哪被调用的。
(2)gpiolib的使用方法:申请、使用、释放
(3)gpiolib的架构:涉及哪些目录的哪些文件
2:什么是gpiolib,为什么需要使用gpiolib
linux中从2.6.35以后就开始有gpiolib库了,gpiolib的作用是对所有的gpio实行统一管理,因为驱动在工作的时候,会出现好几个驱动共同使用同一个gpio的情况;这会造成混乱。所以内核提供了一些方法来管理gpio资源;
3:gpiolib的初始化函数
在我们的mach-smdkc110.c文件中的
smdkc110_map_io
s5pv210_gpiolib_init 这个函数是gpiolib的初始化函数
smdkc110_map_io这个函数的调用过程,在我们分析静态映射的时候已经分析了。
4:结构体struct s3c_gpio_chip
struct s3c_gpio_chip { struct gpio_chipchip; struct s3c_gpio_cfg*config; struct s3c_gpio_pm*pm; void __iomem*base; inteint_offset; spinlock_t lock; #ifdef CONFIG_PM u32pm_save[7]; #endif };
(1)这个结构体在arch/arm/palt-samsung/include/plat/gpio-core.h中
(2)一个s3c_gpio_chip结构体类型的变量就可以用来描述一个gpio端口(注意这里是一个端口,而不是一个IO口,一个端口里面可以有多个IO口(一般是一个端口有8个IO))
(3)需要struct gpio_chip结构体中的元素
const char *label;
这个元素是用来记录当前IO坐在的IO端口的名字,比如IO口GPA0.0所在的IO端口就是GPA0
(4)int base;
当前IO口所属的IO端口的编号,我们的gpiolib中 记录IO的方法是通过记录每一组IO的端口基础编号,然后通过一个IO的端口就在这个基准端口上叠加即可。
比如:
端口GPA0共有8个IO,IO口编号为0 -7,那么基准号就是0,也就是base = 0;
端口GPA1共有4个IO,IO口编号为8-11,那么基准号就是8,也就是base = 8;
5:s5pv210_gpio_4bit
(1)s5pv210_gpio_4bit是一个s3c_gpio_chip类型的结构体数组。
(2)将所有的gpio的.chip结构体中的一些元素初始化,这个数组的所有元素是与数据手册中的所有gpio是一一对应的。
(4)分析可知,这个数组就是对当前MPU中的所有的IO端口和每个端口的IO口进行了统一的描述,有了这个数组, 我们就知道当前开发板有多少个端口,有多少个IO口,以及每个IO口的编号。
6:s5pv210_gpiolib_init
__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; }
(1)通过上面的分析可知,s5pv210_gpiolib_init这个函数的作用是将我们开发板中所有GPIO的端口进行一个配置,并且为所有GPIO端口分配一个基准端口的虚拟地址,通过这个基准地址就能得到这组端口中所有IO口的寄存器的地址。
(2)我们之前讲过,在我们的s5pv210_gpio_4bit这个数组中绑定了开发板中所有IO口的信息,int nr_chips = ARRAY_SIZE(s5pv210_gpio_4bit);得到我们s5pv210_gpio_4bit数组的元素个数,然后调用samsung_gpiolib_add_4bit_chips这个函数,将开发板中的所有信息向我们的系统进行注册,这样系统就能知道当前系统中的所以IO口的信息。
7:samsung_gpiolib_add_4bit_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); //这里的chip指针+1实际上加的是一个元素 s3c_gpiolib_add(chip); } }
(1)经过分析,发现samsung_gpiolib_add_4bit内部其实并没有做gpiolib的注册工作,而是还在做填充,填充的是每一个GPIO被设置成输入模式/输出模式的操作方法。
(2)s3c_gpiolib_add
__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); 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; #ifdef CONFIG_PM if (chip->pm != NULL) { if (!chip->pm->save || !chip->pm->resume) printk(KERN_ERR "gpio: %s has missing PM functions\n",gc->label); } else printk(KERN_ERR "gpio: %s has no PM function\n", gc->label); #endif /* gpiochip_add() prints own failure message on error. */ ret = gpiochip_add(gc); if (ret >= 0) s3c_gpiolib_track(chip); }
(1)首先我们在前面的分析可知,在samsung_gpiolib_add_4bit函数中,已经添加了我们的input和output方法,所以这里的if不会成立,并且分析函数可知,这里挂接的input和output方法是针对2bit的CON寄存器的芯片(2440)。
(2)这个函数首先是对我们的GPIO进行进一步的填充,主要是添加set和get的方法。
(3)调用gpiochip_add函数来完成真真的注册。
驱动学习之gpiolib的建立过程