GPIO的几种模式:
mode | Are |
---|---|
高阻输入 | 保持高阻抗状态,彻底断开输出,避免干扰,对总线状态不起作用,此时总线可由其他器件占用。 |
推挽输出 | 可以输出高,低电平,连接数字器件。 |
开漏输出 | 输出端相当于三极管的集电极. 要得到高电平状态需要上拉电阻才行。 |
$软件上就是通过设置IO口的模式,然后控制IO的上拉下拉,写入对应寄存器,通过寄存器控制电路:
上拉寄存器是控制对应端口上拉使能(DE)的。当对应位为0时,设置对应引脚上拉使能,为1时,禁止对应引脚上拉使能。如果上拉寄存器使能,无论引脚功能寄存器如何设置(输入,输出,数据,中断等),对应引脚输出高电平。
上拉是一个电阻接到一个电压,其实就是增强IO的驱动能力,IO口是高电平。
下拉是一个电阻接到地,保证IO口是低电平。
Kernel 2.6.32版本以上提供了gpio口管理的库文件/kernel/drivers/gpio/gpiolib.c
一.相关的接口:
1.int gpio_request(unsigned gpio, const char *label)
申请一个pin脚作为gpio口,命名为 * label,如果经过判断空闲的 申请成功了做一些初始的bit位设置。
int gpio_request(unsigned gpio, const char *label)
{
struct gpio_desc *desc;
struct gpio_chip *chip;
int status = -EINVAL;
unsigned long flags;
spin_lock_irqsave(&gpio_lock, flags);
...
if (test_and_set_bit(FLAG_REQUESTED, &desc->flags) == 0)
...
}
2.void gpio_free(unsigned gpio)
释放这个gpio口
void gpio_free(unsigned gpio)
{
unsigned long flags;
struct gpio_desc *desc;
struct gpio_chip *chip;
might_sleep();
...
clear_bit(FLAG_ACTIVE_LOW, &desc->flags);
clear_bit(FLAG_REQUESTED, &desc->flags);
clear_bit(FLAG_OPEN_DRAIN, &desc->flags);
clear_bit(FLAG_OPEN_SOURCE, &desc->flags);
...
}
3.int gpio_direction_input(unsigned gpio)
设置gpio口为输入模式:
int gpio_direction_input(unsigned gpio)
{
unsigned long flags;
struct gpio_chip *chip;
struct gpio_desc *desc = &gpio_desc[gpio];
int status = -EINVAL;
spin_lock_irqsave(&gpio_lock, flags);
if (!gpio_is_valid(gpio))
goto fail;
chip = desc->chip;
...
status = chip->direction_input(chip, gpio);
...
}
其中的chip->direction_input(chip, gpio)为实现!
4.int gpio_direction_output(unsigned gpio, int value)
设置gpio口为输出模式 value为初始值 0为高电平/1为低电平:
int gpio_direction_output(unsigned gpio, int value)
{
unsigned long flags;
struct gpio_chip *chip;
struct gpio_desc *desc = &gpio_desc[gpio];
int status = -EINVAL;
/* Open drain pin should not be driven to 1 */
if (value && test_bit(FLAG_OPEN_DRAIN, &desc->flags))
return gpio_direction_input(gpio);
...
status = chip->direction_output(chip, gpio, value);
...
}
其中的chip->direction_output(chip, gpio, value)为实现!
5.void __gpio_set_value(unsigned gpio, int value)
设置gpio口的值:
void __gpio_set_value(unsigned gpio, int value)
{
struct gpio_chip *chip;
chip = gpio_to_chip(gpio);
WARN_ON(chip->can_sleep);
trace_gpio_value(gpio, 0, value);
if (test_bit(FLAG_OPEN_DRAIN, &gpio_desc[gpio].flags))
_gpio_set_open_drain_value(gpio, chip, value);
else if (test_bit(FLAG_OPEN_SOURCE, &gpio_desc[gpio].flags))
_gpio_set_open_source_value(gpio, chip, value);
else
chip->set(chip, gpio - chip->base, value);
}
6.int __gpio_get_value(unsigned gpio)
获取gpio口的值:
int __gpio_get_value(unsigned gpio)
{
struct gpio_chip *chip;
int value;
chip = gpio_to_chip(gpio);
WARN_ON(chip->can_sleep);
value = chip->get ? chip->get(chip, gpio - chip->base) : 0;
trace_gpio_value(gpio, 1, value);
return value;
}
二.对于有些挂载在I2C,SPI总线上的扩展GPIO,读写操作可能会导致睡眠,因此不能在中断函数中使用。
使用下面的函数以区别于正常的GPIO
int gpio_get_value_cansleep(unsigned gpio);//读GPIO
void gpio_set_value_cansleep(unsigned gpio, int value);//写GPIO
三、gpiolib.c关联芯片接口
以上为gpiolib.c的基本方法都是向下调用到对应芯片的gpio实现!
所以每个方法里面的实现都是通过 struct gpio_chip*chip 这个指针调用结构体中关联的相关接口!
下面是gplolib怎么关联到特定的芯片(mach-at91)的几个主要方法:
mach-at91的/kernel/arch/arm/mach-at91/gpio.c中的
static struct at91_gpio_chip gpio_chip[] = {
AT91_GPIO_CHIP("A", 0x00 + PIN_BASE, 32),
AT91_GPIO_CHIP("B", 0x20 + PIN_BASE, 32),
AT91_GPIO_CHIP("C", 0x40 + PIN_BASE, 32),
AT91_GPIO_CHIP("D", 0x60 + PIN_BASE, 32),
AT91_GPIO_CHIP("E", 0x80 + PIN_BASE, 32),
};
gpiolib.c中的接口与mach-at91函数接口对应关系如下:
#define AT91_GPIO_CHIP(name, base_gpio, nr_gpio) \
{ \
.chip = { \
.label = name, \
.direction_input = at91_gpiolib_direction_input, \
.direction_output = at91_gpiolib_direction_output, \
.get = at91_gpiolib_get, \
.set = at91_gpiolib_set, \
.dbg_show = at91_gpiolib_dbg_show, \
.base = base_gpio, \
.ngpio = nr_gpio, \
}, \
}
从上面可以看到 在gpiolib.c中的方法调用芯片(mach-at91)的映射关系:
比如:gpio_direction_output() 设置gpio口为输出模式中最终的实现调用chip->direction_output(chip, gpio, value)。
从上面可以看出来,也就是调用mach-at91的at91_gpiolib_direction_output()!
其它的类似。
gpiolib.c中的
int gpiochip_add(struct gpio_chip *chip)
{
unsigned long flags;
int status = 0;
unsigned id;
int base = chip->base;
if ((!gpio_is_valid(base) || !gpio_is_valid(base + chip->ngpio - 1))
&& base >= 0) {
status = -EINVAL;
goto fail;
}
spin_lock_irqsave(&gpio_lock, flags);
....
}
添加到结构体:
struct gpio_desc {
struct gpio_chip *chip;
unsigned long flags;
/* flag symbols are bit numbers */
#define FLAG_REQUESTED 0
#define FLAG_IS_OUT 1
#define FLAG_RESERVED 2
...
}
这就保存到了 chip 指针。
这一部分在Kernel初始化的时候调用执行!
四、芯片(mach-at91)gpio口的接口
由gpiolib.c根据映射调用对应接口
static int at91_gpiolib_direction_output(struct gpio_chip *chip,
unsigned offset, int val)
{
struct at91_gpio_chip *at91_gpio = to_at91_gpio_chip(chip);
void __iomem *pio = at91_gpio->regbase;
unsigned mask = 1 << offset;
__raw_writel(mask, pio + (val ? PIO_SODR : PIO_CODR));
__raw_writel(mask, pio + PIO_OER);
return 0;
}
定义为输出模式,初始设置val 上拉还是下拉 , 写入数据寄存器。
#define PIO_SODR 0x30 /* Set Output Data Register */
#define PIO_CODR 0x34 /* Clear Output Data Register */
#define PIO_ODR 0x14 /* Output Disable Register */
#define PIO_PDSR 0x3c /* Pin Data Status Register */
同样设置为输入:
static int at91_gpiolib_direction_input(struct gpio_chip *chip,
unsigned offset)
{
struct at91_gpio_chip *at91_gpio = to_at91_gpio_chip(chip);
void __iomem *pio = at91_gpio->regbase;
unsigned mask = 1 << offset;
__raw_writel(mask, pio + PIO_ODR);
return 0;
}
设置GPIO口的value 值 0或者1,已经设置为输出模式下:
static void at91_gpiolib_set(struct gpio_chip *chip, unsigned offset, int val)
{
struct at91_gpio_chip *at91_gpio = to_at91_gpio_chip(chip);
void __iomem *pio = at91_gpio->regbase;
unsigned mask = 1 << offset;
__raw_writel(mask, pio + (val ? PIO_SODR : PIO_CODR));
}
读寄存器获取该GPIO口的值:
static int at91_gpiolib_get(struct gpio_chip *chip, unsigned offset)
{
struct at91_gpio_chip *at91_gpio = to_at91_gpio_chip(chip);
void __iomem *pio = at91_gpio->regbase;
unsigned mask = 1 << offset;
u32 pdsr;
pdsr = __raw_readl(pio + PIO_PDSR);
return (pdsr & mask) != 0;
}
转载出处http://blog.csdn.net/jscese/article/details/16823519
此外:
static inline int of_get_gpio_flags(struct device_node *np, int index,
enum of_gpio_flags *flags)
static inline int of_get_gpio_flags(struct device_node *np, int index,
enum of_gpio_flags *flags)
{
return of_get_named_gpio_flags(np, "gpios", index, flags);
}
而of_get_named_gpio_flags()函数定义如下:
static inline int of_get_named_gpio_flags(struct device_node *np,
const char *list_name, int index, enum of_gpio_flags *flags)
{
return -ENOSYS;
}
enum of_gpio_flags {
OF_GPIO_ACTIVE_LOW = 0x1,
};
gpio_set_value(port_num,0/1)
这个函数一般只是在这个GPIO口的寄存器上写上某个值,至于这个端口是否设置为输出,它就管不了!
gpio_direction_output (port_num,0/1)
“`
在某个GPIO口写上某个值之后,还会把这个端口设置为输出模式。