s3c2440系统自带的管脚宏和函数


S3C2410_GPF(4)  


#define S3C2410_GPF(_nr) (S3C2410_GPIO_F_START + (_nr))  ==》变成:S3C2410_GPIO_F_START+4


S3C2410_GPIO_F_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_E) ==》变成:S3C2410_GPIO_NEXT(S3C2410_GPIO_E) + 4


#define S3C2410_GPIO_NEXT(__gpio) \
((__gpio##_START) + (__gpio##_NR) + CONFIG_S3C_GPIO_SPACE + 0)


分析:从后面开始分析

#define S3C2410_GPIO_NEXT(__gpio) \
((__gpio##_START) + (__gpio##_NR) + CONFIG_S3C_GPIO_SPACE + 0)

其中##在这里表示连接作用,字符串的连接而已;根据上面的可以得到:S3C2410_GPIO_E_START + S3C2410_GPIO_E_NR + CONFIG_S3C_GPIO_SPACE + 0 +4

S3C2410_GPIO_E_START == S3C2410_GPIO_NEXT(S3C2410_GPIO_D) == S3C2410_GPIO_D_START+S3C2410_GPIO_D_NR+ CONFIG_S3C_GPIO_SPACE + 0

写到这里应该明白了;

S3C2410_GPIO_E_NR+S3C2410_GPIO_D_NR+S3C2410_GPIO_C_NR+S3C2410_GPIO_B_NR+S3C2410_GPIO_A_NR + 5*CONFIG_S3C_GPIO_SPACE+0+4

其中:#define CONFIG_S3C_GPIO_SPACE 0

看的都乱了,其实就是从A类管脚个数开始计算到当前类引脚个数。S3C2410_GPB(0) 就是从A类引脚开始计算,所以为:32;依次类推;


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


//设置pin引进上的值为to,也就是设置输出值GPBDAT
void s3c2410_gpio_setpin(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 dat;

	local_irq_save(flags);

	dat = __raw_readl(base + 0x04);
	dat &= ~(1 << offs);
	dat |= to << offs;
	__raw_writel(dat, base + 0x04);

	local_irq_restore(flags);
}


1、void __iomem *base = S3C24XX_GPIO_BASE(pin); 用下面宏替换

#define S3C24XX_GPIO_BASE(x)  S3C2410_GPIO_BASE(x)  这里没做处理,还是简单替换下

#define S3C2410_GPIO_BASE(pin)   ((((pin) & ~31) >> 1) + S3C24XX_VA_GPIO) 这里就处理了下,根据上面的:S3C2410_GPF(4)  例子可以知道每一个类型组都有32个引脚数(实际不一定有那么多);比如GPB0:32;GPC0:64等等;(((pin) & ~31) >> 1) 就可以变成:0x10(GPB类),0x20(GPC类)。记住宏里面是十进制数,而我们要得到的是十六进制数,每4个二进制数对应一个十六进制数,这样就容易理解也容易分析了。至于为什么是0x10、0x20,这可以看下GPBCON/GPCCON的地址尾数;接下来就看看 S3C24XX_VA_GPIO了。

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

直接找到对应的数据就运算:

=((0x56000000 - 0x50000000) + (0xF4000000 + 0x01000000))

= (0x06000000 + 0xF5000000)

= (0xFB000000)

得到的这是虚拟地址,而物理地址GPIO=0x56000000 UART=0x50000000


可以参考这篇blog:http://www.phpfans.net/article/htmls/201004/MjgzODU5.html 这是虚拟地址的运算,我不是很懂,后面理解了再补上;


2、理解了上面的地址就好办了,下面是真正运算的

dat = __raw_readl(base + 0x04);// 从地址中读取数据,这是加了 0x04 则表示的是:GPBDAT位
dat &= ~(1 << offs); // 对pin指定位进行清零
dat |= to << offs; // 根据to设置pin相对应的位
__raw_writel(dat, base + 0x04);// 把数据再次写入到地址中


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


void s3c2410_gpio_cfgpin(unsigned int pin, unsigned int function)
{
	void __iomem *base = S3C24XX_GPIO_BASE(pin);// 得到虚拟地址
	unsigned long mask;
	unsigned long con;
	unsigned long flags;

	if (pin < S3C2410_GPIO_BANKB) { // GPA类端口是有一位数来控制的
		mask = 1 << S3C2410_GPIO_OFFSET(pin);
	} else { // 其他类的端口是有2个位数控制的。3表示 二进制  11;
		mask = 3 << S3C2410_GPIO_OFFSET(pin)*2;
	}

	switch (function) {
	case S3C2410_GPIO_LEAVE:
		mask = 0;
		function = 0;
		break;

	case S3C2410_GPIO_INPUT:
	case S3C2410_GPIO_OUTPUT:
	case S3C2410_GPIO_SFN2:
	case S3C2410_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;//function移动到相应位
		}
	}

	/* modify the specified 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);
}
使用方式:

如pin=S3C2410_GPB5    function=00   则:设置S3C2410_GPB5为输入口
如pin=S3C2410_GPB5    function=01 则:设置S3C2410_GPB5为输出口
如pin=S3C2410_GPB5    function=10   则:设置S3C2410_GPB5为多功能口


可以参考blog:http://blog.163.com/appreciate_y/blog/static/189250050201152911148847/


转载请注明作者和原文出处,原文地址:http://blog.csdn.net/yuzhihui_no1/article/details/45096159

若有不正确之处,望大家指正,共同学习!谢谢!!!

你可能感兴趣的:(Linux驱动,s3c2440引脚宏)