分类: 嵌入式
2009-11-20 17:45:22
/*s3c2410_gpio_cfgpin()函数*/
/*在寄存器的相应位添加功能值的函数*/
/*这个函数非常重要*/
/*比如,在寄存器GPH的[13:12]位添加10,就要用到此函数*/
/*[13:12]两位共有4种状态,10是S3C2410_GPH6_TXD2,00是S3C2410_GPH6_INP,
01是S3C2410_GPH6_OUTP,11是S3C2410_GPH6_nRTS1*/
/*
#define S3C2410_GPIO_BASE(pin) ((((pin) & ~31) >> 1) + S3C24XX_VA_GPIO)
#define S3C24XX_VA_GPIO S3C2410_ADDR(0x00E00000) /*00E0 0000 + F000 0000= F0E0 0000*/
#define S3C2410_ADDR(x) (0xF0000000 + (x))
#define S3C2410_GPIO_BANKB (32*1)
#define S3C2410_GPIO_OFFSET(pin) ((pin) & 31)
#define local_irq_save(flags) do { (flags) = swpipl(IPL_MAX); barrier(); } while(0)
#define local_irq_restore(flags) do { barrier(); setipl(flags); barrier(); } while(0)
*/
void s3c2410_gpio_cfgpin(unsigned int pin, unsigned int function)
{
/*基地址的获取*/
/*11111 ~11111=1110 0000 (pin) & ~31 即是屏蔽掉末5位,保留其余位*/
/*然后右移1位*/
/*为什么要右移一位呢?*/
/*因为偏移值只需要占用4位就可以了,能表示16以内的就行,可以一次改变2位寄存器的值*/
/*最终就是找到寄存器的基地址*/
void __iomem *base = S3C2410_GPIO_BASE(pin);
/*S3C2410_GPH6 = 32*7+6 = 230 = 1110 0110*/
/*S3C2410_GPH6 & ~31 = 1110 0000 = 224 = 32*7 */
/*(S3C2410_GPH6 & ~31) >> 1 = 0111 0000 = 112 = 16*7 = 0x70*/
/*((S3C2410_GPH6 & ~31) >> 1) + S3C2410_VA_GPIO = 0xF0E0 0000 + 0x70 = 0xF0E0 0070 */
/*也就是寄存器GPH的地址为0xF0E0 0070*/
/*而其偏移值6,表示要对[13:12]两位赋值*/
/*掩码*/
unsigned long mask;
/*控制字*/
unsigned long con;
/*标志*/
unsigned long flags;
/*掩码的设置*/
/*bankA是一位一位的改变寄存器的值*/
/*而之后的bank则是两位两位地改变寄存器的值*/
/*这些都是通过设置掩码来实现的*/
/*如bankA的掩码设置可以在[31:0]的任一位设置为1*/
/*而其余bank则只能在偶数位开始的两位设置为1*/
if (pin < S3C2410_GPIO_BANKB) /*如果pin < 32,即为bankA*/
{
mask = 1 << S3C2410_GPIO_OFFSET(pin); /*则只保留末5位*/
/*32,很值得推敲的数字,即为寄存器的32位,而S3C2410_GPIO_OFFSET(pin)表示寄存器的哪一位*/
/*如果是0 0110,就表示是[6]位*/
}
else /*pin >= 32,bankH=32*7=224 */
{
mask = 3 << S3C2410_GPIO_OFFSET(pin)*2; /*掩码,一次处理两位*/
/*S3C2410_GPIO_OFFSET(230) = 6 */
/* 6*2 = 12 */
/* 3 << 12 即 [13:12] = 11 */
/*就是处理两位*/
}
/*中断保留*/
local_irq_save(flags);
/*读取寄存器的值*/
/*如读取寄存器GPH的值*/
con = __raw_readl(base + 0x00);
/*掩码处理*/
con &= ~mask; /*把[13:12]位置0,其余位保留*/
/*就是空出[13:12]位,好用来添加功能值*/
/*添加功能*/
con |= function; /*把[13:12]位添加为10*/
/*可见,bankB以后的寄存器,都是一次处理两位*/
/*写入寄存器*/
__raw_writel(con, base + 0x00); /*往bankH寄存器里写值*/
/*中断恢复*/
local_irq_restore(flags);