Chinaunix首页 | 论坛 | 博客
  • 博客访问: 30995467
  • 博文数量: 230
  • 博客积分: 2868
  • 博客等级: 少校
  • 技术积分: 2223
  • 用 户 组: 普通用户
  • 注册时间: 2009-10-08 21:48
个人简介

Live & Learn

文章分类

全部博文(230)

文章存档

2022年(2)

2019年(5)

2018年(15)

2017年(42)

2016年(24)

2015年(13)

2014年(1)

2012年(5)

2011年(58)

2010年(56)

2009年(9)

我的朋友

分类: LINUX

2017-05-18 15:20:35

Linux GPIO 的注册与申请

Linux Kernel, GPIO, ARM

在Linux kernel代码中,经常会使用 GPIO 来作为一个特殊的信号,如作为芯片的片选信号等。
GPIO 申请的函数,我们经常用到,如 gpio_request ,那么 GPIO 是何时,以及如何注册的,本文就来探索一下。
基于的平台上 freesccale 的 i.MX6

先从函数 gpio_request 的实现开始。

[objc] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. /* These "optional" allocation calls help prevent drivers from stomping 
  2.  * on each other, and help provide better diagnostics in debugfs. 
  3.  * They're called even less than the "set direction" calls. 
  4.  */  
  5. int gpio_request(unsigned gpio, const charchar *label)  
  6. {  
  7.     struct gpio_desc    *desc;  
  8.     struct gpio_chip    *chip;  
  9.     int         status = -EINVAL;  
  10.     unsigned long       flags;  
  11.   
  12.     spin_lock_irqsave(&gpio_lock, flags);  
  13.   
  14.     if (!gpio_is_valid(gpio))  
  15.         goto done;  
  16.     // 这儿从 gpio_desc 数组中取了一个 gpio_desc 结构体  
  17.     // 后面的代码基本上都是基于这个结构体进行的操作  
  18.     // 我们是从数组中取了一个 gpio 的描述,这个描述应该是在 gpio 注册的时候添加到这个数组的  
  19.     // 以这个数组为线索,看看 gpio 是如何注册的  
  20.     desc = &gpio_desc[gpio];  
  21.     chip = desc->chip;  
  22.     if (chip == NULL)  
  23.         goto done;  
  24.   
  25.     if (!try_module_get(chip->owner))  
  26.         goto done;  
  27.   
  28.     /* NOTE:  gpio_request() can be called in early boot, 
  29.      * before IRQs are enabled, for non-sleeping (SOC) GPIOs. 
  30.      */  
  31.   
  32.     if (test_and_set_bit(FLAG_REQUESTED, &desc->flags) == 0) {  
  33.         desc_set_label(desc, label ? : "?");  
  34.         status = 0;  
  35.     } else {  
  36.         status = -EBUSY;  
  37.         module_put(chip->owner);  
  38.         goto done;  
  39.     }  
  40.   
  41.     if (chip->request) {  
  42.         /* chip->request may sleep */  
  43.         spin_unlock_irqrestore(&gpio_lock, flags);  
  44.         status = chip->request(chip, gpio - chip->base);  
  45.         spin_lock_irqsave(&gpio_lock, flags);  
  46.   
  47.         if (status < 0) {  
  48.             desc_set_label(desc, NULL);  
  49.             module_put(chip->owner);  
  50.             clear_bit(FLAG_REQUESTED, &desc->flags);  
  51.         }  
  52.     }  
  53.   
  54. done:  
  55.     if (status)  
  56.         pr_debug("gpio_request: gpio-%d (%s) status %d\n",  
  57.             gpio, label ? : "?", status);  
  58.     spin_unlock_irqrestore(&gpio_lock, flags);  
  59.     return status;  
  60. }  


以数组 gpio_desc 为线索。
既然我们申请 GPIO 的时候是从这个数字中取数据,那么注册 GPIO 的时候就应该往这个数字中添加数据了。
反过来,往这个数组添加数据的地方应该也就是注册 GPIO 的地方了。
这个数组定义在 Gpiolib.c 文件中:

[objc] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. static struct gpio_desc gpio_desc[ARCH_NR_GPIOS];  


搜索发现, gpiochip_add 函数中有给数组 gpio_desc 赋值。
 
看看谁调用了函数 gpiochip_add 。
平台相关目录下的 Gpio.c 文件中的 mxc_gpio_init 函数调用了 gpiochip_add :

[objc] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. if (!initialed)  
  2.     /* its a serious configuration bug when it fails */  
  3.     BUG_ON(gpiochip_add(&port[i].chip) < 0);  


继续往上找,平台相关目录下的 Devices.c 有如下函数:

[objc] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. int mx6q_register_gpios(void)  
  2. {  
  3.     /* 7 ports for Mx6 */  
  4.     return mxc_gpio_init(mxc_gpio_ports, 7);  
  5. }  


mxc_gpio_ports 的定义:

[objc] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. static struct mxc_gpio_port mxc_gpio_ports[] = {  
  2.     {  
  3.         .chip.label = "gpio-0",  
  4.         .base = IO_ADDRESS(GPIO1_BASE_ADDR),  
  5.         .irq = MXC_INT_GPIO1_INT15_0_NUM,  
  6.         .irq_high = MXC_INT_GPIO1_INT31_16_NUM,  
  7.         .virtual_irq_start = MXC_GPIO_IRQ_START  
  8.     },  
  9.     {  
  10.         .chip.label = "gpio-1",  
  11.         .base = IO_ADDRESS(GPIO2_BASE_ADDR),  
  12.         .irq = MXC_INT_GPIO2_INT15_0_NUM,  
  13.         .irq_high = MXC_INT_GPIO2_INT31_16_NUM,  
  14.         .virtual_irq_start = MXC_GPIO_IRQ_START + 332 * 1  
  15.     },  
  16.     {  
  17.         .chip.label = "gpio-2",  
  18.         .base = IO_ADDRESS(GPIO3_BASE_ADDR),  
  19.         .irq = MXC_INT_GPIO3_INT15_0_NUM,  
  20.         .irq_high = MXC_INT_GPIO3_INT31_16_NUM,  
  21.         .virtual_irq_start = MXC_GPIO_IRQ_START + 332 * 2  
  22.     },  
  23.     {  
  24.         .chip.label = "gpio-3",  
  25.         .base = IO_ADDRESS(GPIO4_BASE_ADDR),  
  26.         .irq = MXC_INT_GPIO4_INT15_0_NUM,  
  27.         .irq_high = MXC_INT_GPIO4_INT31_16_NUM,  
  28.         .virtual_irq_start = MXC_GPIO_IRQ_START + 332 * 3  
  29.     },  
  30.     {  
  31.         .chip.label = "gpio-4",  
  32.         .base = IO_ADDRESS(GPIO5_BASE_ADDR),  
  33.         .irq = MXC_INT_GPIO5_INT15_0_NUM,  
  34.         .irq_high = MXC_INT_GPIO5_INT31_16_NUM,  
  35.         .virtual_irq_start = MXC_GPIO_IRQ_START + 332 * 4  
  36.     },  
  37.     {  
  38.         .chip.label = "gpio-5",  
  39.         .base = IO_ADDRESS(GPIO6_BASE_ADDR),  
  40.         .irq = MXC_INT_GPIO6_INT15_0_NUM,  
  41.         .irq_high = MXC_INT_GPIO6_INT31_16_NUM,  
  42.         .virtual_irq_start = MXC_GPIO_IRQ_START + 332 * 5  
  43.     },  
  44.     {  
  45.         .chip.label = "gpio-6",  
  46.         .base = IO_ADDRESS(GPIO7_BASE_ADDR),  
  47.         .irq = MXC_INT_GPIO7_INT15_0_NUM,  
  48.         .irq_high = MXC_INT_GPIO7_INT31_16_NUM,  
  49.         .virtual_irq_start = MXC_GPIO_IRQ_START + 332 * 6  
  50.     },  
  51. };  


继续往上,找到了同目录下 Irq.c 文件中的 mx6_init_irq 函数调用了 mx6q_register_gpios 。
board.c 文件中将 mx6_init_irq 函数赋值给了 machine_desc 结构体的 init_irq 函数:

[objc] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. MACHINE_START(MX6XXXX, "Freescale i.MX 6 Board")  
  2.     .boot_params    = MX6_PHYS_OFFSET + 0x100,  
  3.     .fixup      = fixup_mxc_board,  
  4.     .map_io     = mx6_map_io,  
  5.     .init_irq   = mx6_init_irq,  
  6.     .init_machine   = mx6_board_init,  
  7.     .timer      = &mxc_timer,  
  8.     .reserve    = mx6q_reserve,  
  9. MACHINE_END  


arch/arm/kernel/irq.c 文件中有以下函数:

[objc] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. void __init init_IRQ(void)  
  2. {  
  3.     machine_desc->init_irq();  
  4. }  


 

init/main.c 文件中的 start_kernel 函数调用了 init_IRQ 。

至于 start_kernel 函数何时被调用,有时间再作研究。

总结一下 GPIO 的注册过程:
start_kernel 函数会调用 init_IRQ 函数。
init_IRQ 函数调用了 machine_desc 结构体的 init_irq 函数。
machine_desc 结构体在 board.c 文件中定义,其中 init_irq 被赋值为 mx6_init_irq 。
mx6_init_irq 函数中调用了 mx6q_register_gpios 函数。
mx6q_register_gpios 函数的定义见前文,其中调用了函数 mxc_gpio_init 。

函数 mxc_gpio_init 的实现:

[objc] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. int mxc_gpio_init(struct mxc_gpio_port *port, int cnt)  
  2. {  
  3.     int i, j;  
  4.     static bool initialed;  
  5.   
  6.     /* save for local usage */  
  7.     // port 是前面定义的数组 mxc_gpio_ports , cnt 是数组中元素的个数  
  8.     mxc_gpio_ports = port;  
  9.     gpio_table_size = cnt;  
  10.   
  11.     printk(KERN_INFO "MXC GPIO hardware\n");  
  12.   
  13.     for (i = 0; i < cnt; i++) {  
  14.         /* disable the interrupt and clear the status */  
  15.         __raw_writel(0, port[i].base + GPIO_IMR);  
  16.         __raw_writel(~0, port[i].base + GPIO_ISR);  
  17.         for (j = port[i].virtual_irq_start;  
  18.             j < port[i].virtual_irq_start + 32; j++) {  
  19.             irq_set_lockdep_class(j, &gpio_lock_class);  
  20.             /* 
  21.             static struct irq_chip gpio_irq_chip = { 
  22.                 .name = "GPIO", 
  23.                 .irq_ack = gpio_ack_irq, 
  24.                 .irq_mask = gpio_mask_irq, 
  25.                 .irq_unmask = gpio_unmask_irq, 
  26.                 .irq_set_type = gpio_set_irq_type, 
  27.                 .irq_set_wake = gpio_set_wake_irq, 
  28.             }; 
  29.             */  
  30.             /** 
  31.              *  handle_level_irq - Level type irq handler 
  32.              *  @irq:   the interrupt number 
  33.              *  @desc:  the interrupt description structure for this irq 
  34.              * 
  35.              *  Level type interrupts are active as long as the hardware line has 
  36.              *  the active level. This may require to mask the interrupt and unmask 
  37.              *  it after the associated handler has acknowledged the device, so the 
  38.              *  interrupt line is back to inactive. 
  39.              */  
  40.             irq_set_chip_and_handler(j, &gpio_irq_chip,  
  41.                          handle_level_irq);  
  42.             set_irq_flags(j, IRQF_VALID);  
  43.         }  
  44.   
  45.         /* register gpio chip */  
  46.         // mxc_gpio_direction_input 将对应 gpio 设置为输入, mxc_gpio_direction_output 将对应 gpio 设置为输出,并会设置一个初始值  
  47.         // 这儿的输入/输出是对 cpu 来说的  
  48.         port[i].chip.direction_input = mxc_gpio_direction_input;  
  49.         port[i].chip.direction_output = mxc_gpio_direction_output;  
  50.         // 获取/设置 gpio 状态  
  51.         port[i].chip.get = mxc_gpio_get;  
  52.         port[i].chip.set = mxc_gpio_set;  
  53.         port[i].chip.base = i * 32;  
  54.         port[i].chip.ngpio = 32;  
  55.   
  56.         spin_lock_init(&port[i].lock);  
  57.   
  58.         if (!initialed)  
  59.             /* its a serious configuration bug when it fails */  
  60.             // 添加 gpio chip , 调用的是我们前面用到的一个线索函数, 该函数中有给 gpio_desc 数组赋值  
  61.             BUG_ON(gpiochip_add(&port[i].chip) < 0);  
  62.   
  63.         if (cpu_is_mx1() || cpu_is_mx3() || cpu_is_mx25() ||  
  64.             cpu_is_mx51() || cpu_is_mx53() || cpu_is_mx6q() ||  
  65.             cpu_is_mx6dl() || cpu_is_mx6sl()) {  
  66.             /* setup one handler for each entry */  
  67.             irq_set_chained_handler(port[i].irq,  
  68.                         mx3_gpio_irq_handler);  
  69.             irq_set_handler_data(port[i].irq, &port[i]);  
  70.             if (port[i].irq_high) {  
  71.                 /* setup handler for GPIO 16 to 31 */  
  72.                 irq_set_chained_handler(port[i].irq_high,  
  73.                             mx3_gpio_irq_handler);  
  74.                 irq_set_handler_data(port[i].irq_high,  
  75.                              &port[i]);  
  76.             }  
  77.         }  
  78.     }  
  79.     initialed = true;  
  80.     if (cpu_is_mx2()) {  
  81.         /* setup one handler for all GPIO interrupts */  
  82.         irq_set_chained_handler(port[0].irq, mx2_gpio_irq_handler);  
  83.         irq_set_handler_data(port[0].irq, port);  
  84.     }  
  85.   
  86.     return 0;  
  87. }  


gpiochip_add 函数的实现:

[objc] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. /** 
  2.  * gpiochip_add() - register a gpio_chip 
  3.  * @chip: the chip to register, with chip->base initialized 
  4.  * Context: potentially before irqs or kmalloc will work 
  5.  * 
  6.  * Returns a negative errno if the chip can't be registered, such as 
  7.  * because the chip->base is invalid or already associated with a 
  8.  * different chip.  Otherwise it returns zero as a success code. 
  9.  * 
  10.  * When gpiochip_add() is called very early during boot, so that GPIOs 
  11.  * can be freely used, the chip->dev device must be registered before 
  12.  * the gpio framework's arch_initcall().  Otherwise sysfs initialization 
  13.  * for GPIOs will fail rudely. 
  14.  * 
  15.  * If chip->base is negative, this requests dynamic assignment of 
  16.  * a range of valid GPIOs. 
  17.  */  
  18. int gpiochip_add(struct gpio_chip *chip)  
  19. {  
  20.     unsigned long   flags;  
  21.     int     status = 0;  
  22.     unsigned    id;  
  23.     int     base = chip->base;  
  24.   
  25.     if ((!gpio_is_valid(base) || !gpio_is_valid(base + chip->ngpio - 1))  
  26.             && base >= 0) {  
  27.         status = -EINVAL;  
  28.         goto fail;  
  29.     }  
  30.   
  31.     spin_lock_irqsave(&gpio_lock, flags);  
  32.   
  33.     if (base < 0) {  
  34.         base = gpiochip_find_base(chip->ngpio);  
  35.         if (base < 0) {  
  36.             status = base;  
  37.             goto unlock;  
  38.         }  
  39.         chip->base = base;  
  40.     }  
  41.   
  42.     /* these GPIO numbers must not be managed by another gpio_chip */  
  43.     for (id = base; id < base + chip->ngpio; id++) {  
  44.         if (gpio_desc[id].chip != NULL) {  
  45.             status = -EBUSY;  
  46.             break;  
  47.         }  
  48.     }  
  49.     if (status == 0) {  
  50.         for (id = base; id < base + chip->ngpio; id++) {  
  51.             // 发现这儿只是赋值了 gpio_desc 成员的 chip 成员  
  52.             gpio_desc[id].chip = chip;  
  53.   
  54.             /* REVISIT:  most hardware initializes GPIOs as 
  55.              * inputs (often with pullups enabled) so power 
  56.              * usage is minimized.  Linux code should set the 
  57.              * gpio direction first thing; but until it does, 
  58.              * we may expose the wrong direction in sysfs. 
  59.              */  
  60.             gpio_desc[id].flags = !chip->direction_input  
  61.                 ? (1 << FLAG_IS_OUT)  
  62.                 : 0;  
  63.         }  
  64.     }  
  65.   
  66.     of_gpiochip_add(chip);  
  67.   
  68. unlock:  
  69.     spin_unlock_irqrestore(&gpio_lock, flags);  
  70.   
  71.     if (status)  
  72.         goto fail;  
  73.   
  74.     // 创建设备, 并添加对应的 sysfs  
  75.     status = gpiochip_export(chip);  
  76.     if (status)  
  77.         goto fail;  
  78.   
  79.     return 0;  
  80. fail:  
  81.     /* failures here can mean systems won't boot... */  
  82.     pr_err("gpiochip_add: gpios %d..%d (%s) failed to register\n",  
  83.         chip->base, chip->base + chip->ngpio - 1,  
  84.         chip->label ? : "generic");  
  85.     return status;  
  86. }  


gpio_desc 结构体的定义:

[objc] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. struct gpio_desc {  
  2.     struct gpio_chip    *chip;  
  3.     unsigned long       flags;  
  4. /* flag symbols are bit numbers */  
  5. #define FLAG_REQUESTED  0  
  6. #define FLAG_IS_OUT 1  
  7. #define FLAG_RESERVED   2  
  8. #define FLAG_EXPORT 3   /* protected by sysfs_lock */  
  9. #define FLAG_SYSFS  4   /* exported via /sys/class/gpio/control */  
  10. #define FLAG_TRIG_FALL  5   /* trigger on falling edge */  
  11. #define FLAG_TRIG_RISE  6   /* trigger on rising edge */  
  12. #define FLAG_ACTIVE_LOW 7   /* sysfs value has active low */  
  13.   
  14. #define ID_SHIFT    16  /* add new flags before this one */  
  15.   
  16. #define GPIO_FLAGS_MASK     ((1 << ID_SHIFT) - 1)  
  17. #define GPIO_TRIGGER_MASK   (BIT(FLAG_TRIG_FALL) | BIT(FLAG_TRIG_RISE))  
  18.   
  19. #ifdef CONFIG_DEBUG_FS  
  20.     const char      *label;  
  21. #endif  
  22. };  
阅读(2320) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~