LINUX ARM平台的GPIO
来源:互联网 发布:与电脑网络相关的单词 编辑:程序博客网 时间:2024/06/02 06:37
首先是代码中的几个宏定义:
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的设置为是紧接着的第3,4位(没有第0位的说法),所以要移2位。
===========================================================================================================
A
有个GPIO的虚拟地址base,接下来分析下面的:
#define S3C2410_GPIO_BASE(pin) ((((pin) & ~31) >> 1) + S3C24XX_VA_GPIO)
关于((pin) & ~31) >> 1)的计算:由上面算出的宏S3C2410_GPB5值37(既是pin值)来计算出((pin) & ~31) >> 1)的值,因为
pin =S3C2410_GPB5 = 37, 37 的二进制是10,0101,~31的二进制是10,0000所以(pin) & ~31) 的值是 32(0x20),((pin) & ~31) >> 1)的结果是16(0x10),其实无论是B组内的第几个端口,如果是B组端口的话, ((pin) & ~31) >> 1)的结果都是16(0x10),这就是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,GPB是0x10+S3C24XX_VA_GPIO,GPC是 0x20+S3C24XX_VA_GPIO...
为什么相邻的端口组地址相差0x10呢?
因为每一组端口都有四个寄存器,举GPA和GPB例子:
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/
- LINUX ARM平台的GPIO
- 这一个在OMAP3530/DM3730 ARM A8平台上,LINUX系统下,对GPIO的操作
- ARM-Linux下的GPIO中断程序
- linux 4412平台GPIO的初始化
- ARM GPIO的解析
- ARM的GPIO设置
- 【嵌入式Linux+ARM】GPIO操作
- ARM-Linux应用程序读写GPIO
- 【嵌入式Linux+ARM】GPIO操作
- arm-linux-2.6.29的GPIO宏与…
- 基于ARM的Linux嵌入式系统如何操作GPIO口
- linux的GPIO平台适配模型(结合8810讲解)
- 在DM355平台上如何在应用层直接控制GPIO----操作arm的寄存器
- 基于ARM的嵌入式Linux开发平台
- 基于ARM的嵌入式Linux开发平台
- 基于ARM的嵌入式Linux开发平台
- ARM-Linux平台的Busybox交叉编译
- ARM平台开发常用的Linux命令
- 使用安全json parser防止json注入
- WebKit之HTML元素支持流程
- JQuery 常见用法
- Browser Security Handbook
- [转][数论]Farey Sequence深入学习
- LINUX ARM平台的GPIO
- 新W3C标准中 AJAX 跨域实现以及隐患
- P3P Header Tips
- 年假总述
- 【后缀数组求可重叠的k 次最长重复子串】POJ 3261
- 关于 extern “C”
- CSDN精选iPhone开发博客
- Linux下spi驱动开发(1)
- Ext JS 4.1 Beta 2发布