自己翻译的内核gpiolib文档,是2.6.38版本的。原文在:http://lxr.linux.no/linux+v2.6.38/Documentation/gpio.txt 内核文档 2011/05/08
标识端口 -------------
gpio使用0~MAX_INT之间的整数标识,不能使用负数。 使用以下函数检查一个端口号的合法性: int gpio_is_valid(int number);
? 使用gpio ------------- 使用io的第一步是分配端口,使用 gpio_request()。 接下来要做的是标记它的方向。 /*设为输入或者输出,成功返回零或者失败返回负的错误值*/ int gpio_direction_input(unsigned gpio); int gpio_direction_output(unsigned gpio, int value); 通常应该检查它们的返回值。通常应该假定这两个接口会在线程上下文中调用。但是 对于自旋锁安全的gpio也可以在线程出现之前的早期初始化之间使用。
对于输出的gpio,提供的值作为输出的初始值。
? 使用自旋锁安全的gpio ---------------------------------- 大部分gpio控制器可以使用内存读写指令来访问,不需要睡眠,可以在中断上下文访问。
对于gpio_cansleep返回假的gpio可以使用下面的接口访问: /*读取输入,返回零或非零*/ int gpio_get_value(unsigned gpio); /*输出*/ void gpio_set_value(unsigned gpio, int value); 返回的值是布尔值,零代表低,非零代表搞电平。当读取输出引脚的值,返回值应该是引脚上的实际状态, 这个值不一定等于配置的输出值,因为从设定信号到信号稳定需要一定时间。
不是所有的平台可以读取输出的引脚值,这些平台不能总是返回零。用这两这两个函数访问 不能非在睡眠的上下文中安全访问的gpio将是一个错误。
? 可被休眠上下文中访问的GPIO ---------------------------------------------- 一些gpio控制器必须使用基于信息的总线,比如i2c和spi.读写gpio值的命令需要在队列中等待。 操作这些gpio可能会睡眠,不能在中断上下文中调用。
支持这种gpio的平台为了通过在这个函数中返回非零来区分其它 类型的gpio(需要一个已经被gpio_request申请的gpio号): int gpio_cansleep(unsigned gpio);
为了访问这些端口,定义了另一组函数接口: /*输入端口:返回零或非零,可能睡眠*/ int gpio_get_value_cansleep(unsigned gpio); /*输出端口:可能睡眠*/ void gpio_set_value_cansleep(unsigned gpio, int value); 只能在允许睡眠的上下文中访问这些端口,比如线程化的中断中, 必须使用这些接口而不是没有cansleep前缀的自旋锁安全接口。
除了这些接口可能睡眠这个事实之外,它们操作那些不能在中断处理函数中访问的端口,这些调用的表现和 自旋锁安全的调用表现一致。
另外:调用安装和配置这样的gpio必须是在可睡眠的上下文中,因为他们可能需要访问gpio控制器。 gpio_direction_input() gpio_direction_output() gpio_request()
## gpio_request_one() ## gpio_request_array() ## gpio_free_array()
gpio_free() gpio_set_debounce()
? 申请和释放gpio ------------------------ 为了获取系统配置错误,定义了两个调用: /*申请gpio,返回0或负的错误值 * 非空的lables指针有助于诊断*/ int gpio_request(unsigned gpio, const char *label); /*释放之前申请的gpio*/ void gpio_free(unsigned gpio); 应该假设这两个函数实在进程上下文中调用的,但对于自旋锁安全的gpio也可从 在进程建立之前的早期启动过程中调用。
考虑到大多数情况下gpio会在申请过后立即需要被配置,下面三个接口负责这些工作: /*申请一个单独的gpio,使用“flag”作为初始的配置参数*/ int gpio_request_one(unsigned gpio, unsigned long flags, const char *label); /*在一个调用中申请多个gpio*/ int gpio_request_array(struct gpio *array, size_t num); /*释放多个端口*/ void gpio_free_array(struct gpio *array, size_t num);
“falg”用来配置下面的特性: * GPIOF_DIR_IN - 配置方向为输入 * GPIOF_DIR_OUT -配置方向为输出 * GPIOF_INIT_LOW - 做输出引脚,输出低电平 * GPIOF_INIT_HIGH - 做输出引脚,输出高电平
为了同时处理多个gpio,定义了一个专门结构体: struct gpio { unsigned gpio; unsigned long flags; const char *label; };
典型的使用如下: 327 static struct gpio leds_gpios[] = { 328 { 32, GPIOF_OUT_INIT_HIGH, "Power LED" }, /* default to ON */ 329 { 33, GPIOF_OUT_INIT_LOW, "Green LED" }, /* default to OFF */ 330 { 34, GPIOF_OUT_INIT_LOW, "Red LED" }, /* default to OFF */ 331 { 35, GPIOF_OUT_INIT_LOW, "Blue LED" }, /* default to OFF */ 332 { ... }, 333 }; 334 335 err = gpio_request_one(31, GPIOF_IN, "Reset Button"); 336 if (err) 337 ... 338 339 err = gpio_request_array(leds_gpios, ARRAY_SIZE(leds_gpios)); 340 if (err) 341 ... 342 343 gpio_free_array(leds_gpios, ARRAY_SIZE(leds_gpios));
---------------------------- 352 /* map GPIO numbers to IRQ numbers */ 353 int gpio_to_irq(unsigned gpio); 354 355 /* map IRQ numbers to GPIO numbers (avoid using this) */ 356 int irq_to_gpio(unsigned irq); 返回值是对应的编号或者是负的错误码。使用未用gpio_direction_input()安装的gpio编号或者不是从 gpio_to_irq()得到的中断号是不会被gpio检查的错误。
gpio_to_irq()返回的中断编号可以传给request_irq()和free_irq()。 irq_to_gpio()返回的gpio编号通常用来调用gpio_get_value(),比如在沿触发的中断中获取引脚的状态。 有些平台不支持这种映射,应该避免调用映射函数。
模拟漏极开路 ------------------ gpio可能支持也可能不支持漏极开路输出。如果硬件不支持,可以模拟漏极开路输出的输入或者输出: LOW: gpio_direction_output(gpio, 0) 忽略上拉电阻。 HIGH: gpio_direction_input(gpio) 关闭输出,上拉电阻控制信号。 如果驱动输出高电平但是gpio_get_value(gpio)报告的电平是低电平(经过一定延迟之后),可以断定 其它部分正在信号线上输出低电平。
GPIO 的框架(可选) =============== GPIO的框架在gpiolib中实现。 如果使能了 debugfs,系统下会出现 /sys/kernel/debug/gpio这个文件。这个文件内 将会列出所有注册在框架内的控制器和当前使用的gpio的状态。