gpio and gpio interrupt 一

这篇随笔将记录我对linux gpio库的实现分析及使用 ,作为备忘, 实例代码为高通8660,linux内核3.0。

关于gpio库的文档,kernel 中有一个文档。位于documentation 下的gpio.txt

http://www.linuxidc.com/Linux/2011-07/39632.htm 这个链接是一个网友对这个文档的翻译。可以参考

gpiolib.c中提供了gpio管理的框架。driver/gpio

一 实现自己的gpio库。

在8660 中gpio库的实现在gpio-v2.c中。我们来看一下是如何做的。

postcore_initcall(msm_gpio_init);

这行代码告诉我们从这里开始吧

 

1 static int __init msm_gpio_init(void)
2 {
3     msm_gpio_probe();
4     register_syscore_ops(&msm_gpio_syscore_ops);
5     return 0;
6 }

第3行是注册gpio chip 用的。第四行注册了电源管理的操作。

 

 1 static int __devinit msm_gpio_probe(void)
 2 {
 3     int i, irq, ret;
 4 
 5     spin_lock_init(&tlmm_lock);
 6     bitmap_zero(msm_gpio.enabled_irqs, NR_MSM_GPIOS);
 7     bitmap_zero(msm_gpio.wake_irqs, NR_MSM_GPIOS);
 8     bitmap_zero(msm_gpio.dual_edge_irqs, NR_MSM_GPIOS);
 9     ret = gpiochip_add(&msm_gpio.gpio_chip);
10     if (ret < 0)
11         return ret;
12 
13     for (i = 0; i < msm_gpio.gpio_chip.ngpio; ++i) {
14         irq = msm_gpio_to_irq(&msm_gpio.gpio_chip, i);
15         irq_set_chip_and_handler(irq, &msm_gpio_irq_chip,
16                      handle_level_irq);
17         set_irq_flags(irq, IRQF_VALID);
18     }
19 
20     ret = request_irq(TLMM_MSM_SUMMARY_IRQ, msm_summary_irq_handler,
21             IRQF_TRIGGER_HIGH, "msmgpio", NULL);
22     if (ret) {
23         pr_err("Request_irq failed for TLMM_MSM_SUMMARY_IRQ - %d\n",
24                 ret);
25         return ret;
26     }
27     return 0;
28 }

 

 这个函数虽然不是很长,但完成的功能却使开天劈地的,首先把我们的gpio chip也即是gpio 控制器添加到了系统中。接着把gpio关联在中断中。然后申请了一个中断处理函数。所以要想完整的理解gpio,还需要把中断系统搞明白才行。无论多么复杂,静下心来,仔细分析,思路就会好起来了。

让我们先来看    ret = gpiochip_add(&msm_gpio.gpio_chip);

这个函数的输入是一个叫做gpio_chip的变量

定义为

 

 1 struct gpio_chip {
 2     const char        *label;
 3     struct device        *dev;
 4     struct module        *owner;
 5 
 6     int            (*request)(struct gpio_chip *chip,
 7                         unsigned offset); 请求gpio
 8     void            (*free)(struct gpio_chip *chip,
 9                         unsigned offset);释放gpio
10 
11     int            (*direction_input)(struct gpio_chip *chip,
12                         unsigned offset);配置gpio为输入,返回当前gpio状态
13     int            (*get)(struct gpio_chip *chip,
14                         unsigned offset);获取gpio的状态
15     int            (*direction_output)(struct gpio_chip *chip,
16                         unsigned offset, int value);配置gpio为输出,并设置为value
17     int            (*set_debounce)(struct gpio_chip *chip,
18                         unsigned offset, unsigned debounce);设置消抖动时间,尤其是gpio按键时有用
19 
20     void            (*set)(struct gpio_chip *chip,
21                         unsigned offset, int value);设置gpio为value值
22 
23     int            (*to_irq)(struct gpio_chip *chip,
24                         unsigned offset);把gpio号转换为中断号
25 
26     void            (*dbg_show)(struct seq_file *s,
27                         struct gpio_chip *chip);调试用
28     int            base; 这个gpio控制器的gpio开始编号
29     u16            ngpio;这个gpio控制器说控制的gpio数
30     const char        *const *names;
31     unsigned        can_sleep:1;
32     unsigned        exported:1;
33 
34 #if defined(CONFIG_OF_GPIO)
35     /*
36      * If CONFIG_OF is enabled, then all GPIO controllers described in the
37      * device tree automatically may have an OF translation
38      */
39     struct device_node *of_node;
40     int of_gpio_n_cells;
41     int (*of_xlate)(struct gpio_chip *gc, struct device_node *np,
42                 const void *gpio_spec, u32 *flags);
43 #endif
44 };

这些函数都是chip级别的函数。linux的gpiolib会勾到这里进行实际的硬件操作。值得一提的是比如(*set)(struct gpio_chip *unsigned offset, int value);设置值是个int二不是bool,所以这个值可以不止是1或0.,从而给我们个机会把gpio配置为其他功能并设置驱动电流,上拉电阻等配置。

当我们定义了gpiochip的结构后,利用gpiochip_add加入gpio构架。以后就可以用linux标准的gpio函数操作gpio了。

现在来分析一下这个gpiochip_add,  部分分析在code中

 

 1 int gpiochip_add(struct gpio_chip *chip)
 2 {
 3     unsigned long    flags;
 4     int        status = 0;
 5     unsigned    id;
 6     int        base = chip->base;
 7 
 8     if ((!gpio_is_valid(base) || !gpio_is_valid(base + chip->ngpio - 1))
 9             && base >= 0) {
10         status = -EINVAL;
11         goto fail;
12     }
      检测gpio的有效性,判断gpio是否在0 到 ARCH_NR_GPIOS中,这个宏被定义在gpio.h 中 目前为255
13 
14     spin_lock_irqsave(&gpio_lock, flags);
15 
16     if (base < 0) {
17         base = gpiochip_find_base(chip->ngpio);
18         if (base < 0) {
19             status = base;
20             goto unlock;
21         }
22         chip->base = base;
23     }
24 以上代码动态的分配gpio的开始索引。
25     /* these GPIO numbers must not be managed by another gpio_chip */
26     for (id = base; id < base + chip->ngpio; id++) {
27         if (gpio_desc[id].chip != NULL) {
28             status = -EBUSY;
29             break;
30         }
31     }
   确保这些分配的gpio号没有被其他chip占用
32     if (status == 0) {
33         for (id = base; id < base + chip->ngpio; id++) {
34             gpio_desc[id].chip = chip;
35 
36             /* REVISIT:  most hardware initializes GPIOs as
37              * inputs (often with pullups enabled) so power
38              * usage is minimized.  Linux code should set the
39              * gpio direction first thing; but until it does,
40              * we may expose the wrong direction in sysfs.
41              */
42             gpio_desc[id].flags = !chip->direction_input
43                 ? (1 << FLAG_IS_OUT)
44                 : 0;
45         }
46     }
47 填充gpio_desc,并设置某些属性
48     of_gpiochip_add(chip);
49 
50 unlock:
51     spin_unlock_irqrestore(&gpio_lock, flags);
52 
53     if (status)
54         goto fail;
55 
56     status = gpiochip_export(chip);这时gpio sysfs的一些code 对调试很有用
57     if (status)
58         goto fail;
59 
60     return 0;
61 fail:
62     /* failures here can mean systems won't boot... */
63     pr_err("gpiochip_add: gpios %d..%d (%s) failed to register\n",
64         chip->base, chip->base + chip->ngpio - 1,
65         chip->label ? : "generic");
66     return status;
67 }

 

对于每一个gpio,都有一个gpio描述符,这个描述符包含了这个gpio所属的控制器即chip和一些标志,label等。在gpiolib 构架中,linux没有使用惯用的链表来管理gpio描述符,二是采用了一个具有ARCH_NR_GPIOS大小的gpio描述符数组。这个描述符数组便代表了系统所有的gpio。于是我们可以通过gpio号找到对应gpio的描述符,通过描述符找到这个gpio对应的chip,利用chip就可以对gpio进行各种操作了。下面典型的分析几个函数

 1 int gpio_request(unsigned gpio, const char *label)
 2 {
 3     struct gpio_desc    *desc;
 4     struct gpio_chip    *chip;
 5     int            status = -EINVAL;
 6     unsigned long        flags;
 7 
 8     spin_lock_irqsave(&gpio_lock, flags);
 9 
10     if (!gpio_is_valid(gpio))
11         goto done;
12     desc = &gpio_desc[gpio]; gpio描述符是线性的,所以用gpio好取得描述符
13     chip = desc->chip;然后取到chip
14     if (chip == NULL)
15         goto done;
16 
17     if (!try_module_get(chip->owner))
18         goto done;
19 
20     /* NOTE:  gpio_request() can be called in early boot,
21      * before IRQs are enabled, for non-sleeping (SOC) GPIOs.
22      */
23 
24     if (test_and_set_bit(FLAG_REQUESTED, &desc->flags) == 0) {设置这个gpio已经被申请了
25         desc_set_label(desc, label ? : "?");
26         status = 0;
27     } else {
28         status = -EBUSY;
29         module_put(chip->owner);
30         goto done;
31     }
32 
33     if (chip->request) {调用底层的请求函数,在这里我们可以配置gpio的电流,上下拉电阻等
34         /* chip->request may sleep */
35         spin_unlock_irqrestore(&gpio_lock, flags);
36         status = chip->request(chip, gpio - chip->base);
37         spin_lock_irqsave(&gpio_lock, flags);
38 
39         if (status < 0) {
40             desc_set_label(desc, NULL);
41             module_put(chip->owner);
42             clear_bit(FLAG_REQUESTED, &desc->flags);
43         }
44     }
45 
46 done:
47     if (status)
48         pr_debug("gpio_request: gpio-%d (%s) status %d\n",
49             gpio, label ? : "?", status);
50     spin_unlock_irqrestore(&gpio_lock, flags);
51     return status;
52 }

其他函数类同

 


 

 

 

 

 

 

posted @ 2012-07-11 16:54  camera&tunning  阅读(2258)  评论(0编辑  收藏  举报