omap4-gpio

GPIO是通用输入/输出端口,用于灵活控制数字信号。在应用层,通过echo命令设置GPIO的导出、方向和值。在驱动层,通过函数如omap_mux_init_gpio和gpio_direction_output进行配置。GPIO接口包括输入/输出设置、获取值、设置方向等,支持休眠和非休眠访问。GPIO可以映射到中断,模拟开漏信号,并且可以通过sysfs接口供用户空间控制。
摘要由CSDN通过智能技术生成

/**********************************
 应用层设置gpio
***********************************/
To bring out the gpio to userspace:echo 155 > /sys/class/gpio/export
To set as an output:echo out > /sys/class/gpio/gpio155/direction
To set high:echo 1 > /sys/class/gpio/gpio155/value
To set low:echo 0 > /sys/class/gpio/gpio155/value



/**************************************
    驱动层设置gpio
****************************************/
omap_mux_init_gpio(HDMI_GPIO_LS_OE, OMAP_PIN_OUTPUT);   //功能选择
gpio_direction_output(GPIO_WIFI_PMENA, 0);   //设置方向,好像也可以直接设置输出
gpio_set_value_cansleep(GPIO_WIFI_PMENA,1);    //设置输出
GPIO_WIFI_PMENA为一个整数,这里为39     (omap4,pandaboard)

//见过ap6xx的驱动中见过这么一句,gpio_direction_output(GPIO_WIFI_PMENA, 0);---power down    gpio_direction_output(GPIO_WIFI_PMENA, 1)------power up 应该也是可以的~~不过待验证


在drivers/gpio/gpiolib.c中定义了一个结构体:static struct gpio_desc gpio_desc[ARCH_NR_GPIOS];
每一个gpio_desc对应一个gpio端口
端口的输入/出,上/下拉电阻,否已经被用等信息都可以通过这个结构体中的函数来确定

以下结构体变量对应的函数赋值来自 /drivers/gpio/gpio-omap.c中相应的函数
struct gpio_chip {
    const char        *label;
    struct device        *dev;
    struct module        *owner;
    int            (*request)(struct gpio_chip *chip,   unsigned offset);                  //为了保证io口没有被其他的设备在使用,是否已经处于FLAG_REQUESTED
    void            (*free)(struct gpio_chip *chip,   unsigned offset);                    //用完以后释放io
    int            (*direction_input)(struct gpio_chip *chip,  unsigned offset);                            //omap4设置为gpio_input     //drivers/gpio/gpio-omap.c
    int            (*get)(struct gpio_chip *chip, unsigned offset);                            //omap4设置为gpio_get      
    int            (*direction_output)(struct gpio_chip *chip,    unsigned offset, int value);       //omap4设置为gpio_output     //drivers/gpio/gpio-omap.c
    int            (*set_debounce)(struct gpio_chip *chip,   unsigned offset, unsigned debounce);
    void            (*set)(struct gpio_chip *chip,  unsigned offset, int value);
    int            (*to_irq)(struct gpio_chip *chip,  unsigned offset);                   //通过io口号找到相应的中断号
    void            (*dbg_show)(struct seq_file *s,struct gpio_chip *chip);
    int            base;                                        内存器的基地址
    u16            ngpio;                       //IO端口号码
    const char        *const *names;
    unsigned        can_sleep:1;
    unsigned        exported:1;
};













//以下内容转自:http://blog.chinaunix.net/uid-27717694-id-3701921.html

什么是GPIO?
===============
GPIO----“通用目的输入/输出端口”----是一个灵活的软件控制的数字信号。许多种类的芯片都会提供,嵌入式linux开发者和硬件定制者会对此比较熟悉。每个GPIO提供一位与特定的管脚(或是“球”,BGA(Ball Grid Array)封装下)相连。单板电路图会显示外部硬件与GPIOs的连接关系。GPIO驱动可写成通用的,便于单板setup代码可以将这些管脚配置数据传递给驱动。

SOC处理器非常依赖于GPIO。某些情况下,普通管脚可以被配置为GPIO。大多数芯片至少拥有几组类似的GPIO。可编程逻辑器件(如FPGAs)可以很容易提供GPIO。一些多功能芯片,如电源管理、声音解码等经常具有一些这样的管脚来弥补SOC芯片上面管脚的不足。同样,也存在一些GPIO扩展芯片,连接用于I2C或是SPI串行总线。多数PC南桥拥有几组GPIO兼容的管脚(仅有BIOS固件知道如何使用它们)。


不同系统间的GPIO的确切作用不同。通用常有下面几种:
----输出值可写(高=1,低=0)。一些芯片也可以选择驱动这些值的方式,以便支持“线-或”或类似方案(开漏信号线)。

----输入值可读(1,0)。一些芯片支持输出管脚回读,这在线或的情况下非常有用(以支持双向信号线)。GPIO控制器可能具有一个输入防故障/防反跳逻辑,有时还会有软件控制。
----输入经常被用作中断信号,通常是边沿触发,但也有可能是电平触发。这些中断可以配置为系统唤醒事件,从而将系统从低功耗模式唤醒。

----一个GPIO经常被配置为输入/输出双向,根据不同的产品单板需求,但也存在单向的情况。

----大多是GPIO可以在获取到spinlock自旋锁时访问,但那些通过串行总线访问的通常不能如此操作(休眠的原因)。一些系统中会同时存在这两种形式的GPIO。

----在一个给定单板上,每个GPIO用于一个特定的目的,如监控MMC/SD卡的插入/移除,检查卡写保护状态,驱动LED,配置发送器,串行总线位拆,触发一个硬件看门狗,触发一个开关之类的。


GPIO约定
================

注意,它被称为一个约定,因为你不是必须要遵守它。如果你不使用此种方式操作,也不会遭到任何惩罚。存在一些可移植性不是关键的应用场景:GPIO经常用作板级胶合逻辑,这些逻辑甚至在单板的不同版本之间都会改变,且不能用在那些连接不同的单板上。只有极少通用的标准功能可以是可移植的。其余的特性是平台特有的,且对于胶合逻辑是关键(且危险)的。

另外,这不需要任何实现框架,只是一个接口。一个平台可以将它实现为一个简单的inline函数来存取芯片寄存器,另一个可能通过一个多个不同GPIO控制器的抽象委托实现。
(有一些可选的代码支持这种实施策略,这在本文后面会讲到,但担任客户的GPIO接口驱动不要关心他是如何实现的。)

也就是说,如果平台支持约定,驱动应当尽可能使用它。平台必须在Kconfig中声明GENERIC_GPIO来支持,并且提供一个<asm/gpio.h>文件。那些不能离开标准GPIO调用的驱动应该具有一个依赖于GENERIC_GPIO的条目。要使GPIO调用有效,无论是“真实代码”或是作为“optimized-away stubs”,驱动需要使用包含文件:
#include <linux/gpio.h>

如果你坚持此约定,这样别的开发者理解你的代码会比较容易且可以帮助维护它。

注意:在那些需要的平台上,这些操作包括I/0操作间隔(barriers);驱动不需要显式添加它们。

标识GPIO
-----------------
GPIO使用一个无符号整型数进行标识,范围0到MAX_INT。那些保留的“negative”(负)数用于其他的目的,如标识信号为“在此单板上无效”,或是指出错误。那些不涉及到基本硬件操作的代码将这些整型数视为不透明的。

平台定义了它们如何使用这些接口,并且通常为每个GPIO线使用#define宏定义符号,以便单板的启动代码与相关设计直接保持一致。与此相反,驱动应该只使用从setup代码传递给他们的GPIO号码,使用platform_data来保存单板特定的管脚配置数据(与其它所需的单板特定数据一起)。这避免了移植问题。

例如:一个平台给GPIOs使用号码32-159,同时另一个使用0-63支持一个GPIO控制器集合,64-79支持另一个类型的GPIO控制器,且在一个特定的单板上80-95支持一个FPGA。号码不必是连续的,这些单板也可以使用2000-2063来标识一组用于I2CGPIO扩展

如果你想要使用一个无效的GPIO号码初始化一个结构体,使用一些负数(可以为“-EINVAL”),它将永远不会有效。为了测试来自这样一个结构的这样一个号码是否能够引用一个GPIO,你需要使用:
int gpio_is_valid(int number);

一个无效的号码将被调用(可以是申请或释放GPIO)拒绝。别的号码也可能被拒绝。例如,一个号码可能是有效的,但在给定的单板上临时未使用。

平台是否支持多个GPIO控制器是平台特定实现的关键,同样是否支持GPIO号码空间的“空洞”,是否支持在运行时增加新控制器也是关键。这些关键会影响多个事情,包括相邻的GPIO号码是否都有效。


使用GPIOs
-----------

要使用GPIO,系统首先要分配一个GPIO,使用gpio_request() 为系统分配一个GPIO。


接下来要做的一件事是标示GPIO的方向,通常在使用GPIO建立一个platform_device时(位于单板的setup代码中):
/* set as input or output, returning 0 or negative errno */
int gpio_direction_input(unsigned gpio);
int gpio_direction_output(unsigned gpio, int value);


返回0标示成功,或是一个负的errno错误码。它应该被检查,因为get/set调用没有错误返回,且可能会有错误配置。你通常应该在线程上下文中使用这些调用。虽然如此,对于spinlock-safe的GPIO,在tasking使能之前使用也是可以的,作为一个早期的单板建立。

对于输出GPIO,value参数提供了初始输出值。这有助于避免系统启动过程中的信号干扰。

为了与GPIO早期的接口兼容,设置一个GPIO的方向,隐性要求申请GPIO。这个兼容性从可选的gpiolib架构中移除了。


如果GPIO号码无效或是指定的GPIO不能使用对应模式操作的话,设置方向会失败。依靠boot固件设置好GPIO的方向通常不是一个好主意,因为boot的功能可能没有通过验证(除了boot linux)。(类似的,单板setup代码可能需要将管脚复用为一个GPIO,和配置为合适的上拉/下拉。)


Spinlock-Safe GPIO访问
-------------------------
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值