杭州良工装饰口碑如何:S3C24XX体系的Linux GPIO控制相关API实现

来源:百度文库 编辑:中财网 时间:2024/05/06 04:45:39
2010-07-20 17:01:16|  分类:Linux |  标签: |字号大中小
GPIO(General Purpose Input/Output的缩写)就是芯片的引脚,引脚是可编程的可对引脚的工作模式进行设置:输入模式(检测输入信号),输出模式(输出0或1),高阻状态(常用于AD转换),还有禁止或允许上内部下拉电阻(上拉:管脚通过电阻接高电平,下拉:管脚通过电阻接地,也可以外部接上拉或下拉电阻),还有管脚复用等功能,即通过对内部寄存器的设置使引脚既可以工作在一般模式,作为普通的GPIO口使用,也可以工作在特殊模式,比如作为外部中断信号输入引脚等等。如果不设置GPIO引脚,CPU工作时有一个初始化模式,可以从datasheet(芯片手册)上了解。对GPIO的控制是编写驱动程序最常见和重要的一项工作内容。
在Linux< xmlnamespace prefix ="st1" ns ="urn:schemas-microsoft-com:office:smarttags" />2.6.25内核代码中,已经提供了针对三星S3C2410/S3C2440等芯片GPIO的控制,下面来分别介绍一般如何配置、管理GPIO。
下面的函数是用来根据新的功能需求配置一个GPIO引脚(定义在arch/arm/plat-s3c24xx/gpio.c):
1    void s3c2410_gpio_cfgpin(unsigned int pin, unsigned int function)
2    {< xmlnamespace prefix ="o" ns ="urn:schemas-microsoft-com:office:office" />
3           void __iomem *base = S3C24XX_GPIO_BASE(pin);
4           unsigned long mask;
5           unsigned long con;
6           unsigned long flags;
7
8           if (pin < S3C2410_GPIO_BANKB) {
9                  mask = 1 << S3C2410_GPIO_OFFSET(pin);
10           } else {
11                  mask = 3 << S3C2410_GPIO_OFFSET(pin)*2;
12           }
13
14           switch (function) {
15           case S3C2410_GPIO_LEAVE:
16                  mask = 0;
17                  function = 0;
18                  break;
19
20           case S3C2410_GPIO_INPUT:
21           case S3C2410_GPIO_OUTPUT:
22           case S3C2410_GPIO_SFN2:
23           case S3C2410_GPIO_SFN3:
24                  if (pin < S3C2410_GPIO_BANKB) {
25                         function -= 1;
26                         function &= 1;
27                         function <<= S3C2410_GPIO_OFFSET(pin);
28                  } else {
29                         function &= 3;
30                         function <<= S3C2410_GPIO_OFFSET(pin)*2;
31                  }
32           }
33
34           /* modify the specified register wwith IRQs off */
35
36           local_irq_save(flags);
37
38           con  = __raw_readl(base + 0x00);
39           con &= ~mask;
40           con |= function;
41
42           __raw_writel(con, base + 0x00);
43
44           local_irq_restore(flags);
45    }
其中参数pin是要配置的GPIO引脚,参数function是要配置的功能。第3行,其中S3C2410_GPIO_BASE是内核代码中定义的宏,定义在include/asm-arm/arch-s3c2410/regs-gpio.h文件,定义如下:
#define S3C2410_GPIO_BASE(pin)   ((((pin) & ~31) >> 1) + S3C24XX_VA_GPIO)
其中S3C24XX_VA_GPIO= ((S3C2410_PA_GPIO - S3C24XX_PA_UART) + S3C24XX_VA_UART)= 0x56000000-0x50000000+0xF5000000= 0xF9000000,即通过S3C2410_GPIO_BASE宏可获得物理地址到虚拟地址的转化。第8~12行,计算要设置寄存器的掩码位,当引脚为GPIO的A端口时,它的掩码位是1位,通过芯片手册(如下)即可获得此信息。

< xmlnamespace prefix ="v" ns ="urn:schemas-microsoft-com:vml" />
如果引脚为A端口之外GPIO端口时,它是用两位来配置具体的引脚,故掩码为2位,通过芯片手册即可获得此信息。

其中S3C2410_GPIO_OFFSET宏被定义为:S3C2410_GPIO_OFFSET(pin) ((pin) & 31) 获得引脚的偏移位。第14~30行,根据参数function的值来修改设置特定function的值。第38~42行,是对寄存器操作最常见的做法:首先通过__raw_readl来读取寄存器原有的内容,第39、40行是根据新的需求修改原有的寄存器特定位的值(确保其他位保持不变),第42行,调用__raw_writel将修改后的寄存器值重新写入相应的寄存器。
对于s3c2410_gpio_cfgpin()的应用具体,如s3c2410_gpio_cfgpin(S3C2410_GPB5, S3C2410_GPB5_OUTP); 其中S3C2410_GPB5对应的引脚为芯片手册上的GPB5,如下所示:

根据芯片手册,GPB5是由位[11:10]来控制,当该两位值为01时,则配置为输出。S3C2410_GPB5_OUTP的定义在include/asm-arm/arch-s3c2410/regs-gpio.h文件,定义如下:
#define S3C2410_GPB5_OUTP    (0x01 << 10)
即[11:10]为01。如要要配置该GPIO为输入时,那么该两位的值就必须设置为00。
下面s3c2410_gpio_getcfg()函数用来读取一个GPIO引脚的配置,该函数实现代码如下:
unsigned int s3c2410_gpio_getcfg(unsigned int pin)
{
void __iomem *base = S3C24XX_GPIO_BASE(pin);
unsigned long val = __raw_readl(base);
if (pin < S3C2410_GPIO_BANKB) {
val >>= S3C2410_GPIO_OFFSET(pin);
val &= 1;
val += 1;
} else {
val >>= S3C2410_GPIO_OFFSET(pin)*2;
val &= 3;
}
return val | S3C2410_GPIO_INPUT;
}
该函数根据引脚获得指定引脚配置的功能值。对于s3c2410_gpio_getcfg()函数的应用事例如:s3c2410_gpio_getcfg(S3C2410_GPF0);获得GPF0的功能值。
下面的s3c2410_gpio_pullup()函数用来配置一个上拉电阻,其实现代码如下:
void s3c2410_gpio_pullup(unsigned int pin, unsigned int to)
{
void __iomem *base = S3C24XX_GPIO_BASE(pin);
unsigned long offs = S3C2410_GPIO_OFFSET(pin);
unsigned long flags;
unsigned long up;
if (pin < S3C2410_GPIO_BANKB)
return;
local_irq_save(flags);
up = __raw_readl(base + 0x08);  //偏移的0x08是由于配置上拉寄存器的物理地址偏移
up &= ~(1L << offs);
up |= to << offs;
__raw_writel(up, base + 0x08);
local_irq_restore(flags);
}
除此之外,还有其他的GPIO相关函数,如s3c2410_gpio_getpull,s3c2410_gpio_setpin,s3c2410_gpio_getpin等,其实现方式与上述代码类似,有兴趣的读者可仔细阅读其实现代码。
来源:http://idc81.net/qrspx/jiaoshi/html/?537.html