Chinaunix首页 | 论坛 | 博客
  • 博客访问: 313411
  • 博文数量: 169
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 12
  • 用 户 组: 普通用户
  • 注册时间: 2013-07-10 12:00
文章分类

全部博文(169)

文章存档

2014年(38)

2013年(131)

我的朋友

分类: IT业界

2013-07-10 13:07:06

原文地址:值得参考的一篇linux gpio 作者:dyli2000

LINUX ARM平台的GPIO

2011-04-20 20:21:35|  分类: 默认分类 |  标签:define  pin  unsigned  int  0x10     字号: 

首先是代码中的几个宏定义:

 

2.6.31内核:arch/arm/mach-2410/include/mach/regs-gpio.h

 

#define S3C2410_GPIONO(bank,offset) ((bank) + (offset))

 

#define S3C2410_GPIO_BANKA (32*0)

#define S3C2410_GPIO_BANKB (32*1)

#define S3C2410_GPIO_BANKC (32*2)

....

 

#define S3C2410_GPIO_BASE(pin) ((((pin) & ~31) >> 1) + S3C24XX_VA_GPIO)

#define S3C2410_GPIO_OFFSET(pin) ((pin) & 31)

 

#define S3C2410_GPBCON S3C2410_GPIOREG(0x10)

#define S3C2410_GPBDAT S3C2410_GPIOREG(0x14)

#define S3C2410_GPBUP S3C2410_GPIOREG(0x18)

 

/* no i/o pin in port b can have value 3! */

 

#define S3C2410_GPB0 S3C2410_GPIONO(S3C2410_GPIO_BANKB, 0)

#define S3C2410_GPB0_INP (0x00 << 0)

#define S3C2410_GPB0_OUTP (0x01 << 0)

#define S3C2410_GPB0_TOUT0 (0x02 << 0)

 

#define S3C2410_GPB1 S3C2410_GPIONO(S3C2410_GPIO_BANKB, 1)

#define S3C2410_GPB1_INP (0x00 << 2)

#define S3C2410_GPB1_OUTP (0x01 << 2)

#define S3C2410_GPB1_TOUT1 (0x02 << 2)

....



driver
中有这样的代码:

s3c2410_gpio_cfgpin(led_table[i], led_cfg_table[i]);

s3c2410_gpio_setpin(led_table[i], 1);
其中

static unsigned long led_table [] = {
S3C2410_GPB5,
S3C2410_GPB6,
S3C2410_GPB7,
S3C2410_GPB8,
};

static unsigned int led_cfg_table [] = {
S3C2410_GPB5_OUTP,
S3C2410_GPB6_OUTP,
S3C2410_GPB7_OUTP,
S3C2410_GPB8_OUTP,
};


 

 

2.6.31内核:arch/arm/plat-s3c24xx/gpio.c

 

void s3c2410_gpio_cfgpin(unsigned int pin, unsigned int function)

{

void __iomem *base = S3C2410_GPIO_BASE(pin);

unsigned long mask;

unsigned long con;

unsigned long flags;

 

if (pin < S3C2410_GPIO_BANKB) {

mask = 1 << S3C2410_GPIO_OFFSET(pin);

} else {

mask = 3 << S3C2410_GPIO_OFFSET(pin)*2;

}

 

local_irq_save(flags);

 

con = __raw_readl(base + 0x00);

con &= ~mask;

con |= function;

 

__raw_writel(con, base + 0x00); //config the GPXCON

 

local_irq_restore(flags);

}

 

EXPORT_SYMBOL(s3c2410_gpio_cfgpin);

 

 

void s3c2410_gpio_setpin(unsigned int pin, unsigned int to)

{

void __iomem *base = S3C2410_GPIO_BASE(pin);

unsigned long offs = S3C2410_GPIO_OFFSET(pin);

unsigned long flags;

unsigned long dat;

 

local_irq_save(flags);

 

dat = __raw_readl(base + 0x04);

dat &= ~(1 << offs);

dat |= to << offs;

__raw_writel(dat, base + 0x04); //config the GPXDAT

 

local_irq_restore(flags);

}

 

EXPORT_SYMBOL(s3c2410_gpio_setpin);


===========================================================================================================

对传给s3c2410_gpio_cfgpin 函数的pin参数由来解释:pin就是如S3C2410_GPB0(表示B组第五个端口),S3C2410_GPA0之类的宏,而这些宏表示着什么呢?如宏S3C2410_GPB0就是通过宏

#define S3C2410_GPB0 S3C2410_GPIONO(S3C2410_GPIO_BANKB, 0)

得到的,S3C2410_GPIONO(S3C2410_GPIO_BANKB, 0)宏是这样定义的

#define S3C2410_GPIONO(bank,offset) ((bank) + (offset))

很明显,S3C2410_GPIONO(S3C2410_GPIO_BANKB, 0)就是计算两个参数的和,第一个参数表示第几组,第二个参数0表示0端口,如果是计算第一个端口的话,第二个参数就是1

对于S3C2410_GPIO_BANKB宏的定义是

#define S3C2410_GPIO_BANKB (32*1)

而类似GPA的定义是

#define S3C2410_GPIO_BANKA (32*0)

所以最后算出来的S3C2410_GPB5的值是:37 = S3C2410_GPIO_BANKB + 5=32*1 + 5

 

===========================================================================================================

关于s3c2410_gpio_cfgpin的第二个参数function其实是由宏定义的,如

#define S3C2410_GPB0_INP (0x00 << 0)

#define S3C2410_GPB0_OUTP (0x01 << 0)

#define S3C2410_GPB0_TOUT0 (0x02 << 0)

#define S3C2410_GPB1_INP (0x00 << 2)

#define S3C2410_GPB1_OUTP (0x01 << 2)

#define S3C2410_GPB1_TOUT1 (0x02 << 2)

他们是用来设置端口的功能的,就是设置GPACON、GPBCON、GPCCON、GPDCON等配置寄存器的,因为端口0的设置位占了两位,而端口1的设置为是紧接着的第34位(没有第0位的说法),所以要移2位。

 

===========================================================================================================

 

A   

有个GPIO的虚拟地址base,接下来分析下面的:
#define S3C2410_GPIO_
BASE(pin) ((((pin) & ~31) >> 1) + S3C24XX_VA_GPIO)

关于((pin) & ~31) >> 1)的计算:由上面算出的宏S3C2410_GPB537(既是pin值)来计算出((pin) & ~31) >> 1)的值,因为

pin = S3C2410_GPB5 = 37 37 的二进制是10,0101~31的二进制是10,0000所以(pin) & ~31) 的值是 320x20((pin) & ~31) >> 1)的结果是160x10,其实无论是B组内的第几个端口,如果是B组端口的话, ((pin) & ~31) >> 1)的结果都是160x10,这就是S3C2410_GPIO_BASE(pin)的功能,即算出端口的基地址,~31主要是为了清除S3C2410_GPB5的后5位。

B    

相对于

#define S3C2410_GPIO_BASE(pin) ((((pin) & ~31) >> 1) + S3C24XX_VA_GPIO)

有个

#define S3C2410_GPIO_OFFSET(pin) ((pin) & 31)

对比这两个宏,宏S3C2410_GPIO_OFFSET(pin)功能很明显了:计算出是组内的端口号,如S3C2410_GPB5算出的就是5了。

===========================================================================================================

关于S3C2410芯片的S3C24XX_VA_GPIO的计算

#define S3C24XX_VA_GPIO ((S3C24XX_PA_GPIO - S3C24XX_PA_UART) + S3C24XX_VA_UART)

#define S3C24XX_PA_GPIO     S3C2410_PA_GPIO

#define S3C2410_PA_GPIO (0x56000000)
#define
S3C24XX_PA_UART S3C2410_PA_UART

#define
S3C2410_PA_UART (0x50000000)

 

#define S3C24XX_VA_UART        S3C_VA_UART

#define S3C_VA_UART        S3C_ADDR(0x01000000)    /* UART */

#define S3C_ADDR(x)        ((void __iomem __force *)S3C_ADDR_BASE + (x))

#define S3C_ADDR(x)        (S3C_ADDR_BASE + (x))

#define S3C_ADDR_BASE      (0xF4000000)

S3C24XX_VA_GPIO的结果是0xFB000000 = 0x56000000 - 0x50000000 + 0xF4000000 + 0x01000000

以上的宏是在2.6.31内核的。

===========================================================================================================

以下是一些访问通用I/O的方法:

void s3c2410_gpio_cfgpin(unsigned int pin, unsigned int function)

unsigned int s3c2410_gpio_getcfg(unsigned int pin)

void s3c2410_gpio_pullup(unsigned int pin, unsigned int to)

int s3c2410_gpio_getpull(unsigned int pin)

void s3c2410_gpio_setpin(unsigned int pin, unsigned int to)

unsigned int s3c2410_gpio_getpin(unsigned int pin)

unsigned int s3c2410_modify_misccr(unsigned int clear, unsigned int change)

int s3c2410_gpio_getirq(unsigned int pin)

===========================================================================================================

 

有以上对宏define S3C2410_GPIO_BASE(pin)的解释,可推断出

GPA基地址的是0x0+S3C24XX_VA_GPIO,GPB0x10+S3C24XX_VA_GPIO,GPC 0x20+S3C24XX_VA_GPIO...

为什么相邻的端口组地址相差0x10呢?

因为每一组端口都有个寄存器,举GPAGPB例子:

GPA:

Register

Address

R/W        

Description

Reset Value

GPACON

0x56000000  

R/W

Configures the pins of port A

0xffffff

GPADAT

0x56000004   

R/W

The data register for port A

Undef.

Reserved

0x56000008    

-

 

Reserved Undef

Reserved

0x5600000c    

-

 

Reserved Undef

GPB:

Register

Address

R/W

Description

Reset Value

GPBCON

0x56000010

R/W

Configures the pins of port B

0x0

GPBDAT

0x56000014

R/W

The data register for port B.

Undef

GPBUP

0x56000018

R/W

pull-up disable register for port B

0x0

Reserved

0x5600001c

 

 

 

由上两个表可知:每组四个寄存器是为了方便起见,组内相邻的寄存器之间相差4个字节,既是4*8=32bit,组与组之间相差0x10个字节。

==================================================================================================

关于宏

#define S3C2410_GPBCON     S3C2410_GPIOREG(0x10)

#define S3C2410_GPBDAT      S3C2410_GPIOREG(0x14)

#define S3C2410_GPBUP       S3C2410_GPIOREG(0x18)

#define S3C2410_GPCCON        S3C2410_GPIOREG(0x20)

#define S3C2410_GPCDAT         S3C2410_GPIOREG(0x24)

#define S3C2410_GPCUP        S3C2410_GPIOREG(0x28)

S3C2410_GPIOREG的定义是:

#define S3C2410_GPIOREG(x) ((x) + S3C24XX_VA_GPIO)

所以而

GPBCON

0x56000010

GPBDAT

0x56000014

==========================================================================================================

 

其实想想这代码也不难理解,只是宏定义和函数的实现分散在kernel包的各个文件内,因此不太容易寻找。线索齐了后,就一目了然了。

 

 转载请说明出处:http://blog.163.com/yjie_life/blog/static/163198337201132082135276/

阅读(864) | 评论(0) | 转发(0) |
0

上一篇:没有了

下一篇:Linux内核驱动之llseek 实现

给主人留下些什么吧!~~