mini2440 led驱动程序经典分析(4)

((((pin) & ~31) >> 1)到底是神马意思?这个主要靠理解,刚才上面说了每组端口定义为32个,((pin) & ~31)相当于就是把低五位全部清零,而第五位所能代表的范围正好是32,有点以大小32进行对其的意思。如果将得到的数值右移5位的话,得到的数值(设为ppvalue)能正好代表是哪组I/O口。这里为什么右移1位呢,我们看下

几个GPXCON寄存器的物理地址。

GPACON 0X56000000

GPBCON 0X56000010

GPCCON 0X56000020

GPDCON 0X56000030

其他的以此类推,可以看出这个I/O口控制寄存器的规律,如果将ppvalue左移四位,加上GPIO虚拟基地址,就能得到GPXCON控制寄存器的虚拟地址了。顺便说下,这里的虚实地址的映射只是相差了一个偏移量。

分析:if (pin < S3C2410_GPIO_BANKB)

S3C2410_GPIO_BANKB的定义如下

#define S3C2410_GPIO_BANKA  (32*0)

#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)

用于判断此I/O口是否为GPA端口,这是为了区分开GPA与其他各组端口,因为GPA控制寄存器的操作和其他的有点区别,另外要注意,它是没有输入功能的。看datasheet能够更好的了解。

分析:S3C2410_GPIO_OFFSET(pin)

#define S3C2410_GPIO_OFFSET(pin) ((pin) & 31)    //用此宏能得出偏移量

if (pin < S3C2410_GPIO_BANKB) {  //判断I/O口是不是属于GPA,    mask = 1 << S3C2410_GPIO_OFFSET(pin);//设置屏蔽码

} else {

mask = 3 << S3C2410_GPIO_OFFSET(pin)*2;//设置屏蔽码

}

分析:local_irq_save(flags);

这个与下面出现的local_irq_restore(flags);成对使用,用于关闭、打开中断,同时将中断的标志存储在flags中。

分析:__raw_readl(base + 0x00);  __raw_writel(con, base + 0x00);

con  = __raw_readl(base + 0x00);  //读取控制寄存器数据

con &= ~mask;                  //屏蔽掉相应的位

con |= function;              //设置要设置的位

__raw_writel(con, base + 0x00);//把改变后的数据写回控制寄存器

上面的是两个函数宏,定义如下

#define __raw_writeb(v,a) (__chk_io_ptr(a), *(volatile unsigned char __force *)(a) = (v))
#define __raw_writew(v,a) (__chk_io_ptr(a), *(volatile unsigned short __force *)(a) = (v))
#define __raw_writel(v,a) (__chk_io_ptr(a), *(volatile unsigned int __force *)(a) = (v))
PS(ZXX):先检查指针a是否合法,然后将数值v写入a所指向的空间。

三种类型分别对应char,short,int
#define __raw_readb(a) (__chk_io_ptr(a), *(volatile unsigned char __force *)(a))
#define __raw_readw(a) (__chk_io_ptr(a), *(volatile unsigned short __force *)(a))
#define __raw_readl(a) (__chk_io_ptr(a), *(volatile unsigned int __force *)(a))
PS(ZXX):先检查指针a是否合法,然后读取a所指向的空间的数值。
三种类型分别对应char,short,int

5.分析s3c2410_gpio_setpin(led_table[i], 0);

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);

}

有了上述的对s3c2410_gpio_cfgpin(led_table[i], led_cfg_table[i])的分析,上面的代码大同小异罢了,只是说一下__raw_readl(base + 0x04);这个,这是对数据寄存器进行操作,看datasheet就知道,每组的GPXDAT的地址值都比GPXCON的地址值大4。

总结:到此这个led驱动分析就结束了,程序虽小,里面涉及到的东西还是不少的,主要是刚入门者感觉很乱主要是对刚入门的同志有一定的帮助。关于这个驱动程序有几个版本,内核也在不断改变。我同时贴出另一个转载来的也是led驱动程序的文章,但里面涉及的结构数据比这个要复杂点,在我的博客里面可以找到,看懂的话还是能学到不少东西的。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:http://www.heiqu.com/d562f68641e0e5c5b0954599b055a0c0.html