赞
踩
最近在调试一个新板子的LED驱动,LED灯用到了特定的GPIO引脚,而驱动中有一项工作就是需要占用某个GPIO资源并设置为输出引脚,调用的接口类似如下:
- #define GPIOAO_3 (3) /* GPIOAO_3这个引脚的id为3 */
- gpio_request(GPIOAO_3, OWNER_NAME); /* 占用GPIOAO_3这个GPIO的资源 */
- gpio_direction_output(GPIOAO_3, 0); /* 将GPIOAO_3这个GPIO设置为输出引脚并拉低 */
上面的代码比较常见,应该很多同学都看过类似的,现在问题就来了,为什么GPIOAO_3这个GPIO定义为3呢?这个就是我今天要讨论的问题。
前面提出的问题,下面我们会跟着代码来一步步找出答案。每个平台都有自己的GPIO驱动,下面我用到的芯片平台是amlogic s805。虽然代码有差异,但是基本架构是不变的,一般都从probe函数开始,并调用gpiochip_add()函数将自己的驱动注册进系统,在这个过程就决定了GPIO的编号到描述符的映射关系。
1、
代码路径:
amlogic_gpio_probe:arch\arm\mach-meson8b\gpio.c
函数调用:
- struct amlogic_gpio_desc amlogic_pins[]=
- {
- PIN_AOMAP(GPIOAO_0,6,0,6,16,6,0),
- PIN_AOMAP(GPIOAO_1,6,1,6,17,6,1),
- PIN_AOMAP(GPIOAO_2,6,2,6,18,6,2),
- PIN_AOMAP(GPIOAO_3,6,3,6,19,6,3),
- PIN_AOMAP(GPIOAO_4,6,4,6,20,6,4),
- ...
- };
-
- static int amlogic_gpio_probe(struct platform_device *pdev)
- {
- ...
- amlogic_gpio_chip.base=0; /* base这个变量值很重要,奠定了后续gpio编号的起始值 */
- amlogic_gpio_chip.ngpio=ARRAY_SIZE(amlogic_pins); /* amlogic_pins是一个数组,里面按顺序列出了平台所有的GPIO引脚 */
- gpiochip_add(&amlogic_gpio_chip); /* 注册进系统 */
- ...
- return 0;
- }
2、
代码路径:
gpiochip_add:drivers\gpio\gpiolib.c
函数调用:
- int gpiochip_add(struct gpio_chip *chip)
- {
- ...
- int base = chip->base;
-
- if ((!gpio_is_valid(base) || !gpio_is_valid(base + chip->ngpio - 1)) /* 判断编号和GPIO数是否超过了规定的范围,我这里是0~256 */
- && base >= 0) {
- status = -EINVAL;
- goto fail;
- }
-
- spin_lock_irqsave(&gpio_lock, flags);
-
- if (base < 0) { /* 我这个平台的base值是0,不会走到下面的分支 */
- base = gpiochip_find_base(chip->ngpio); -------------------- 2.1小节
- if (base < 0) {
- status = base;
- goto unlock;
- }
- chip->base = base;
- }
-
- status = gpiochip_add_to_list(chip); /* 将自己平台的GPIO注册进系统的链表 */
-
- if (status == 0) {
- chip->desc = &gpio_desc[chip->base]; /* GPIO编号和描述符是一个线性映射的关系,而gpio_desc这个数组就保存这个映射关系,并从base这个偏移位置开始保存每个GPIO的描述符信息 */
-
- for (id = 0; id < chip->ngpio; id++) { /* 这个for循环里就为每一个GPIO描述符赋值 */
- struct gpio_desc *desc = &chip->desc[id]; /* 描述符的首地址指向gpio_desc数组偏移base的位置 */
- desc->chip = chip;
-
- desc->flags = !chip->direction_input
- ? (1 << FLAG_IS_OUT)
- : 0;
- }
- }
- ...
- return status;
- }
2.1、
如果你的平台的base小于0,会走到下面的函数去为这组GPIO引脚自动分配一个base值
代码路径:
gpiochip_add:drivers\gpio\gpiolib.c
函数调用:
- static int gpiochip_find_base(int ngpio)
- {
- struct gpio_chip *chip;
- int base = ARCH_NR_GPIOS - ngpio; /* ARCH_NR_GPIOS一般是平台中GPIO数量的最大值 */
-
- list_for_each_entry_reverse(chip, &gpio_chips, list) { /* 倒序遍历链表(因为GPIO引脚可能分为了好几个bank),目的是找出gpio_desc数组中已经被占用的位置 */
- /* found a free space? */
- if (chip->base + chip->ngpio <= base) /* 如果已经被占用的数组位置和准备分配的位置不重合,自然就直接跳出循环了 */
- break;
- else
- /* nope, check the space right before the chip */
- base = chip->base - ngpio;
- }
-
- if (gpio_is_valid(base)) { /* 检查是否在规定的范围内 */
- pr_debug("%s: found new base at %d\n", __func__, base);
- return base;
- } else {
- pr_err("%s: cannot find free range\n", __func__);
- return -ENOSPC;
- }
- }
3、
从上面两步可以看出来,GPIO编号和描述符之间的关系是由gpio_desc这个数组决定的。所以我们想通过GPIO编号找到对应的描述符,就必须知道这个描述符在数组中的偏移位置,而偏移多少可以根据GPIO在amlogic_pins这个数组的位置加上base值得到。
代码路径:
drivers\gpio\gpiolib.c
函数调用关系:
- gpio_request
- gpiod_request
- gpio_to_desc
-
- static struct gpio_desc *gpio_to_desc(unsigned gpio)
- {
- if (WARN(!gpio_is_valid(gpio), "invalid GPIO %d\n", gpio))
- return NULL;
- else
- return &gpio_desc[gpio]; /* 就是根据传递过来的GPIO编号在数组中找到描述符 */
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。