GPIO(GeneralPurpose Input/Output的縮寫)就是晶片的引腳,引腳是可程式化的可對引腳的工作模式進行設定:輸入模式(檢測輸入訊號),輸出模式(輸出0或1),高阻狀態(常用於AD轉換),還有禁止或允許上內部下拉電阻(上拉:管腳通過電阻接高電平,下拉:管腳通過電阻接地,也可以外部接上拉或下拉電阻),還有針腳多工處理等功能,即通過對內部寄存器的設定使引腳既可以工作在一般模式,作為普通的GPIO口使用,也可以工作在特殊模式,比如作為外部中斷訊號輸入引腳等等。如果不設定GPIO引腳,CPU工作時有一個初始化模式,可以從datasheet(晶片手冊)上瞭解。對GPIO的控制是編寫驅動程式最常見和重要的一項工作內容。在Linux核心代碼中,已經提供了針對三星S3C2410/S3C2440等晶片GPIO的控制。
*******************************************************************************
linux-2.6.30.4\arch\arm\plat-s3c\include\plat\ map-base.h
#defineS3C_ADDR_BASE (0xF4000000)
#ifndef __ASSEMBLY__
#define S3C_ADDR(x) ((void__iomem __force *)S3C_ADDR_BASE+ (x))
#else
#defineS3C_ADDR(x) (S3C_ADDR_BASE+ (x))
#endif
#define S3C_VA_IRQ S3C_ADDR(0x00000000) /* irq controller(s) */
#define S3C_VA_SYS S3C_ADDR(0x00100000) /* system control */
#define S3C_VA_MEM S3C_ADDR(0x00200000) /* system control */
#define S3C_VA_TIMER S3C_ADDR(0x00300000) /* timer block */
#define S3C_VA_WATCHDOG S3C_ADDR(0x00400000) /* watchdog */
#define S3C_VA_UART S3C_ADDR(0x01000000) /*UART */
linux-2.6.30.4\arch\arm\plat-s3c24xx\include\plat\ map.h
/* UARTs */
#defineS3C24XX_VA_UART S3C_VA_UART
#define S3C2410_PA_UART (0x50000000)
#define S3C24XX_SZ_UART SZ_1M
#define S3C_UART_OFFSET (0x4000)
UART映射後的虛擬位址是0xF4000000+0x01000000
linux-2.6.30.4\arch\arm\plat-s3c24xx\include\plat\ map.h
/* GPIO ports */
#define S3C2410_PA_GPIO (0x56000000)
#defineS3C24XX_VA_GPIO ((S3C24XX_PA_GPIO- S3C24XX_PA_UART) + S3C24XX_VA_UART)//GPIO的虛擬位址
#define S3C24XX_SZ_GPIO SZ_1M
GPIO的基地址為 0xfb000000
S3C24XX_VA_GPIO在不同的linux版本中可能不一樣,2.6.30.4是按照上面的方式,是2.6.22.6的實現方法
linux/include/asm-arm/arch-s3c2410/map.h #ifndef __ASSEMBLY__ #define S3C2410_ADDR(x) ((void __iomem *)0xF0000000 + (x)) #else #define S3C2410_ADDR(x) (0xF0000000 + (x)) #endif #define S3C2400_ADDR(x) S3C2410_ADDR(x) /* GPIO ports */ #define S3C24XX_VA_GPIO S3C2410_ADDR(0x00E00000) #define S3C2400_PA_GPIO (0x15600000) #define S3C2410_PA_GPIO (0x56000000) #define S3C24XX_SZ_GPIO SZ_1M |
arch/arm/mach-s3c2410/include/mach/regs-gpio.h
#defineS3C2410_GPIOREG(x) ((x) + S3C24XX_VA_GPIO)//在GPIO的虛擬位址上直接位移
#define S3C24XX_GPIOREG2(x) ((x) + S3C24XX_VA_GPIO2)
linux-2.6.30.4/arch/arm/mach-s3c2410/include/mach/gpio-nrs.h
#defineS3C2410_GPIONO(bank,offset)((bank) + (offset))
#defineS3C2410_GPIO_BANKA (32*0)//每組最多32個連接埠
#define S3C2410_GPIO_BANKB (32*1)
#define S3C2410_GPIO_BANKC (32*2)
#define S3C2410_GPIO_BANKD (32*3)
#define S3C2410_GPIO_BANKE (32*4)
#define S3C2410_GPIO_BANKF (32*5)
#define S3C2410_GPIO_BANKG (32*6)
#define S3C2410_GPIO_BANKH (32*7)
arch/arm/mach-s3c2410/include/mach/regs-gpio.h
#defineS3C2410_GPACON S3C2410_GPIOREG(0x00)//A組GPIO的控制寄存器
#define S3C2410_GPADAT S3C2410_GPIOREG(0x04)//A組GPIO的資料寄存器
#define S3C2400_GPACON S3C2410_GPIOREG(0x00)
#define S3C2400_GPADAT S3C2410_GPIOREG(0x04)
#defineS3C2410_GPA0 S3C2410_GPIONO(S3C2410_GPIO_BANKA, 0)//A組GPIO的第0個的pin數
#define S3C2410_GPA0_OUT (0<<0)//設定A0為輸出功能
#define S3C2410_GPA0_ADDR0 (1<<0)//設定A0作為地址線ADDR0
*******************************************************************************
#define S3C2410_GPBCON S3C2410_GPIOREG(0x10)
#define S3C2410_GPBDAT S3C2410_GPIOREG(0x14)
#define S3C2410_GPBUP S3C2410_GPIOREG(0x18)
#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 S3C2400_GPB0_DATA16 (0x02 << 0)
*******************************************************************************
#define S3C2410_GPCCON S3C2410_GPIOREG(0x20)
#define S3C2410_GPCDAT S3C2410_GPIOREG(0x24)
#define S3C2410_GPCUP S3C2410_GPIOREG(0x28)
#define S3C2410_GPC0 S3C2410_GPIONO(S3C2410_GPIO_BANKC, 0)
#define S3C2410_GPC0_INP (0x00<< 0)
#define S3C2410_GPC0_OUTP (0x01<< 0)
#define S3C2410_GPC0_LEND (0x02<< 0)
#define S3C2400_GPC0_VD0 (0x02<< 0)
*******************************************************************************
#define S3C2410_GPDCON S3C2410_GPIOREG(0x30)
#define S3C2410_GPDDAT S3C2410_GPIOREG(0x34)
#define S3C2410_GPDUP S3C2410_GPIOREG(0x38)
— Port A(GPA): 25-output port — Port B(GPB): 11-input/out port — Port C(GPC): 16-input/output port — Port D(GPD): 16-input/output port — Port E(GPE): 16-input/output port — Port F(GPF): 8-input/output port — Port G(GPG): 16-input/output port — Port H(GPH): 9-input/output port — Port J(GPJ): 13-input/output port 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 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 Register Address R/W Description Reset Value GPCCON 0x56000020 R/W Configures the pins of port C 0x0 GPCDAT 0x56000024 R/W The data register for port C Undef. GPCUP 0x56000028 R/W Pull-up disable register for port C 0x0 Reserved 0x5600002c – – – Register Address R/W Description Reset Value GPDCON 0x56000030 R/W Configures the pins of port D 0x0 GPDDAT 0x56000034 R/W The data register for port D Undef. GPDUP 0x56000038 R/W Pull-up disable register for port D 0xf000 Reserved 0x5600003c – – – |
*******************************************************************************
void s3c2410_gpio_cfgpin(unsignedint pin, unsigned int function)// 其中參數pin是要配置的GPIO引腳,參數function是要配置的功能
{
void __iomem *base = S3C24XX_GPIO_BASE(pin);
unsignedlong mask;
unsignedlong con;
unsignedlong flags;
if(pin < S3C2410_GPIO_BANKB){
mask= 1 << S3C2410_GPIO_OFFSET(pin);
}else {
mask= 3 << S3C2410_GPIO_OFFSET(pin)*2;
}
//如果引腳為A連接埠之外GPIO連接埠時,它是用兩位來配置具體的引腳,故掩碼為2位
switch(function) {
caseS3C2410_GPIO_LEAVE:
mask= 0;
function= 0;
break;
caseS3C2410_GPIO_INPUT:
caseS3C2410_GPIO_OUTPUT:
caseS3C2410_GPIO_SFN2:
caseS3C2410_GPIO_SFN3:
if(pin < S3C2410_GPIO_BANKB){
function-= 1;
function&= 1;
function<<= S3C2410_GPIO_OFFSET(pin);
}else {
function&= 3;
function<<= S3C2410_GPIO_OFFSET(pin)*2;
}
}
/* modify thespecified register wwith IRQs off */
local_irq_save(flags);// 關中斷
con = __raw_readl(base + 0x00);
con &= ~mask;
con |= function;
__raw_writel(con, base + 0x00);
local_irq_restore(flags);// 開中斷
}
arch/arm/mach-s3c2410/include/mach/regs-gpio.h
#define S3C2410_GPIO_BASE(pin) ((((pin) & ~31) >> 1) + S3C24XX_VA_GPIO)
//每組GPIO的虛擬基地址(要先屏蔽最低的5位)根據連接埠編號pin,算出連接埠所在組的虛擬基址。((pin) & ~31)是去掉pin當中小於等於31的零頭(清0低5位),>>1的原因是每組GPIO中最多可以有32個連接埠,控制這些連接埠需要4個寄存器空間,4個寄存器空間就需要4*4=16個位元組進行編址,32/16=2,左移一位剛好滿足。也就是說,上一組連接埠和下一組連接埠的編號相差32,而控制寄存器的地址相差16。
#define S3C2410_GPIO_OFFSET(pin) ((pin) & 31)
//根據連接埠編號pin,算出連接埠所在組的位移量。((pin) & 31)即去掉比31大的數
linux/arch/arm/plat-s3c24xx/gpio.c
s3c2410_gpio_cfgpin //配置連接埠的GPIO的功能
s3c2410_gpio_getcfg //讀取功能配置
s3c2410_gpio_pullup //配置上拉電阻
s3c2410_modify_misccr //雜項配置
s3c2410_gpio_getirq //給定連接埠,轉換出IRQ號
s3c2410_gpio_irqfilter //配置IRQ過濾使能與否
s3c2410_gpio_setpin //寫資料到連接埠
s3c2410_gpio_getpin //從連接埠讀資料
以下代碼摘自Leds的驅動程式,旨在說明linux下如何訪問寄存器
static unsigned long led_table [] =
{
S3C2410_GPB5,
S3C2410_GPB6,
S3C2410_GPB7,
S3C2410_GPB8,
};
/* 用來指定GPIO引腳的功能:輸出 */
static unsigned int led_cfg_table [] =
{
S3C2410_GPB5_OUTP,
S3C2410_GPB6_OUTP,
S3C2410_GPB7_OUTP,
S3C2410_GPB8_OUTP,
};
static int gt2440_leds_ioctl(
structinode *inode,
structfile *file,
unsignedint cmd,
unsignedlong arg)
{
if(arg > 4)
{
return-EINVAL;
}
switch(cmd)
{
caseIOCTL_LED_ON:
//設定指定引腳的輸出電平為0
s3c2410_gpio_setpin(led_table[arg], 0);
return0;
caseIOCTL_LED_OFF:
//設定指定引腳的輸出電平為1
s3c2410_gpio_setpin(led_table[arg], 1);
return0;
default:
return-EINVAL;
}
}
static struct file_operations dev_fops = {
.owner = THIS_MODULE,
.ioctl = gt2440_leds_ioctl,
};
static struct miscdevice misc = {
.minor= MISC_DYNAMIC_MINOR,
.name= DEVICE_NAME,
.fops= &dev_fops,
};
static int __init dev_init(void)
{
intret;
inti;
for(i = 0; i < 4; i++)
{
s3c2410_gpio_cfgpin(led_table[i],led_cfg_table[i]);
s3c2410_gpio_setpin(led_table[i],0);// 設定相應GPIO口的值
}
ret= misc_register(&misc);
printk(DEVICE_NAME" initialized\n");
returnret;
}
static void __exit dev_exit(void)
{
misc_deregister(&misc);
}
module_init(dev_init);
module_exit(dev_exit); *******************************************************************************