GPIO驱动Word文档下载推荐.docx
《GPIO驱动Word文档下载推荐.docx》由会员分享,可在线阅读,更多相关《GPIO驱动Word文档下载推荐.docx(25页珍藏版)》请在冰点文库上搜索。
90intret;
91inti;
92for(i=0;
i<
4;
i++){
93
//设置LED对应的端口寄存器为输出(OUTPUT)
94
if(s3c_gpio_cfgpin(led_table[i],led_cfg_table[i])<
0)
printk(KERN_INFO"
configpin%dfailed"
i);
95printk(KERN_INFO"
95
//设置LED对应的端口寄存器为低电平输出,在模块加载>
结束后,四个LED应该是全部都是发光
96
状态
97
s3c2410_gpio_setpin(led_table[i],0);
98}
99
ret=misc_register(&
misc);
//注册设备
100printk(DEVICE_NAME"
/tinitialized/n"
);
//打印初始化信息
101returnret;
102}
可以看到,这里涉及到两个函数,分别是s3c2410_gpio_cfgpin,s3c2410_gpio_setpin,这两个函数分别对四个LED进行配置,从函数名来看,cfgpin对引脚寄存器状态进行配置,而setpin应该是对寄存器数据值进行配置,我们在分析函数之前先弄清楚传入的参数到底是什么。
led_table[i]
28
//LED对应的GPIO端口列表
29staticunsignedlongled_table[]={
30
S3C2410_GPB(5),
31
S3C2410_GPB(6),
32
S3C2410_GPB(7),
33
S3C2410_GPB(8),
34};
这里S3C2410_GPB宏定义在mach/gpio-nrs.h中
/*GPIObanksizes*/
#defineS3C2410_GPIO_A_NR(32)
#defineS3C2410_GPIO_B_NR(32)
#defineS3C2410_GPIO_C_NR(32)
#defineS3C2410_GPIO_D_NR(32)
#defineS3C2410_GPIO_E_NR(32)
#defineS3C2410_GPIO_F_NR(32)
#defineS3C2410_GPIO_G_NR(32)
#defineS3C2410_GPIO_H_NR(32)
#defineS3C2410_GPIO_J_NR(32)/*technically16.*/
#defineS3C2410_GPIO_K_NR(32)/*technically16.*/
#defineS3C2410_GPIO_L_NR(32)/*technically15.*/
#defineS3C2410_GPIO_M_NR(32)/*technically2.*/
#ifCONFIG_S3C_GPIO_SPACE!
=0
#errorCONFIG_S3C_GPIO_SPACEcannotbezeroatthemoment
#endif
#defineS3C2410_GPIO_NEXT(__gpio)/
((__gpio##_START)+(__gpio##_NR)+CONFIG_S3C_GPIO_SPACE+0)
//这里的CONFIG_S3C_GPIO_SPAC是内核配置选项,在.config中可以找到,我的配置为:
CONFIG_S3C_GPIO_SPACE=0
enums3c_gpio_number{
S3C2410_GPIO_A_START
=0,
S3C2410_GPIO_B_START=S3C2410_GPIO_NEXT(S3C2410_GPIO_A),
S3C2410_GPIO_C_START=S3C2410_GPIO_NEXT(S3C2410_GPIO_B),
S3C2410_GPIO_D_START=S3C2410_GPIO_NEXT(S3C2410_GPIO_C),
S3C2410_GPIO_E_START=S3C2410_GPIO_NEXT(S3C2410_GPIO_D),
S3C2410_GPIO_F_START=S3C2410_GPIO_NEXT(S3C2410_GPIO_E),
S3C2410_GPIO_G_START=S3C2410_GPIO_NEXT(S3C2410_GPIO_F),
S3C2410_GPIO_H_START=S3C2410_GPIO_NEXT(S3C2410_GPIO_G),
S3C2410_GPIO_J_START=S3C2410_GPIO_NEXT(S3C2410_GPIO_H),
S3C2410_GPIO_K_START=S3C2410_GPIO_NEXT(S3C2410_GPIO_J),
S3C2410_GPIO_L_START=S3C2410_GPIO_NEXT(S3C2410_GPIO_K),
S3C2410_GPIO_M_START=S3C2410_GPIO_NEXT(S3C2410_GPIO_L),
};
#defineS3C2410_GPB(_nr)
(S3C2410_GPIO_B_START+(_nr))
因此,以S3C2410_GPB(5)为例,其宏展开为:
S3C2410_GPIO_NEXT(S3C2410_GPIO_A)+5
=>
(S3C2410_GPIO_A_START
+
S3C2410_GPIO_A_NR
+
CONFIG_S3C_GPIO_SPACE+0)+
5
很显然,
S3C2410_GPB(5)就是从GPA的首地址+GPA个数+GPB的offset就是当前GPB的IO偏移量,即
0+32+5=37,同理
S3C2410_GPB(0)相当于32
S3C2410_GPB(5)相当于37
S3C2410_GPB(6)相当于38
S3C2410_GPB(7)相当于39
S3C2410_GPB(8)相当于40
led_cfg_table[i]
36
//LED对应端口将要输出的状态列表
37staticunsignedintled_cfg_table[]={
38S3C2410_GPIO_OUTPUT,
39S3C2410_GPIO_OUTPUT,
40S3C2410_GPIO_OUTPUT,
41S3C2410_GPIO_OUTPUT,
42};
S3C2410_GPIO_OUTPUT定义在mach/regs-gpio.h
#defineS3C2410_GPIO_LEAVE(0xFFFFFFFF)
//最后两位是设置,11表示RESERVE
#defineS3C2410_GPIO_INPUT(0xFFFFFFF0)/*notavailableonA*/
//最后两位是设置,00表示INPUT
#defineS3C2410_GPIO_OUTPUT(0xFFFFFFF1)
//最后两位是设置,01表示OUTPUT
#defineS3C2410_GPIO_IRQ(0xFFFFFFF2)/*notavailableforall*/
#defineS3C2410_GPIO_SFN2(0xFFFFFFF2)/*bankA=>
addr/cs/nand*/
#defineS3C2410_GPIO_SFN3(0xFFFFFFF3)/*notavailableonA*/
根据前面的分析,s3c2410传入了当前GPIO的偏移地址,以及OUTPUT状态
现在我们深入前面的两个函数:
定义在linux/arch/arm/plat-s3c/gpio-config.c
int
s3c_gpio_cfgpin(unsignedintpin,unsignedintconfig)
{
structs3c_gpio_chip*chip=
s3c_gpiolib_getchip(pin);
//得到对应GPIO结构体首指针,里面包含了该GPIO的各种参数
unsignedlongflags;
intoffset;
intret;
if(!
chip)
return-EINVAL;
//没找到的话,返回invalid
offset=pin-chip->
chip.base;
//否则offset等于该GPIO引脚相对于GPX(0)的偏移量,每个偏移1
s3c_gpio_lock(chip,flags);
//自旋锁锁住该GPIO,通过chip指针指向lock,看下面的define和图
ret=
s3c_gpio_do_setcfg(chip,offset,config);
//设置该GPIO状态寄存器的数值为config
s3c_gpio_unlock(chip,flags);
//解锁
//自旋锁操作
/*lockingwrapperstodealwithmultipleaccesstothesamegpiobank*/
//#define
s3c_gpio_lock(_oc,_fl)spin_lock_irqsave(&
(_oc)->
lock,_fl)
s3c_gpio_unlock(_oc,_fl)spin_unlock_irqrestore(&
//s3c_gpio_do_setcfg操作
staticinlineint
s3c_gpio_do_setcfg(structs3c_gpio_chip*chip,
unsignedintoff,unsignedintconfig)
return(chip->
config->
set_config)(chip,off,config);
}
//这里的set_config是一个函数指针,由后面的分析知道,如果针对GPA,该函数指针指向s3c_gpio_setcfg_s3c24xx_a
如果针对GPX应该是指向s3c_gpio_setcfg_s3c24xx——但发现,如果是其他GPX,根本没有定义set_config!
!
(这个问题已经解决,见后文s3c24xx_gpiolib_init函数,事实上,其余的config的确指向s3c_gpio_do_setcfg函数)
struct
s3c_gpio_cfg
s3c24xx_gpiocfg_default={
.set_config=s3c_gpio_setcfg_s3c24xx,
.get_config=s3c_gpio_getcfg_s3c24xx,
s3c_gpio_setcfg_s3c24xx_a(structs3c_gpio_chip*chip,unsignedintoff,unsignedintcfg)
void__iomem*reg=chip->
base;
//GPXCON的物理基地址
unsignedintshift=off;
//每个GPA对应一位
u32con;
if(s3c_gpio_is_cfg_special(cfg)){
//OUTPUT状态是否为(0xfffffffX),是,返回1
cfg&
=0xf;
//cfg=0xX
/*Mapoutputto0,andSFN2to1*/
本实验不会运行到这
cfg-=1;
if(cfg>
1)
return-EINVAL;
cfg<
<
=shift;
con=__raw_readl(reg);
//先读出该GPXCON的值,32位
con&
=~(0x1<
shift);
//
con|=cfg;
//
__raw_writel(con,reg);
//将新值写入GPXCON
PS:
#define__raw_writeb(v,a)(__chk_io_ptr(a),*(volatileunsignedchar__force*)(a)=(v))
#define__raw_writew(v,a)(__chk_io_ptr(a),*(volatileunsignedshort__force*)(a)=(v))
#define__raw_writel(v,a)(__chk_io_ptr(a),*(volatileunsignedint__force*)(a)=(v))
#define__raw_readb(a)(__chk_io_ptr(a),*(volatileunsignedchar__force*)(a))
#define__raw_readw(a)(__chk_io_ptr(a),*(volatileunsignedshort__force*)(a))
#define__raw_readl(a)(__chk_io_ptr(a),*(volatileunsignedint__force*)(a))
return0;
如果针对GPX情况
s3c_gpio_setcfg_s3c24xx(structs3c_gpio_chip*chip,
unsignedintoff,unsignedintcfg)
unsignedintshift=off*2;
//每个GPX对应2位
if(s3c_gpio_is_cfg_special(cfg)){
cfg&
3)
cfg<
//将cfg的0,1两位左移offset
//读对应的GPXCON值
=~(0x3<
//将GPXCON(pin)的两bits请0
//设置config值
//写入新的GPXCON
returnret;
}
//end
s3c_gpio_cfgpin
这里涉及到了一个重要的数据结构,s3c_gpio_chip,此数据结构比较复杂,我贴出这个数据结构的结构图:
、
这个重要的数据结构中可以记录每个GPIO所需要的所有数据,后面会遇到的s3c24xx_gpios[]结构体就是该结构体的集合,描述了芯片中所有的GPIO端口,之后我们需要时时回头看看这个结构。
我们先来看s3c_gpiolib_getchip
,它实现了返回对应pin值的GPIO结构体首指针的功能
#include<
mach/gpio-core.h>
staticinlinestructs3c_gpio_chip*s3c_gpiolib_getchip(unsignedintpin)
structs3c_gpio_chip*chip;
if(pin>
S3C_GPIO_END)
//如果超过GPJ(32)就returnNULL
returnNULL;
chip=&
s3c24xx_gpios[pin/32];
//根据偏移,计算出对应pin的GPIO结构体指针
return((pin-chip->
chip.base)<
chip->
chip.ngpio)?
chip:
NULL;
//
这里验证,如果pin偏移超过了GPIO的个数,说明出错了,否则就返回该GPIO的结构体指针
回想以下之前s3c2410_gpio_cfgpin中,我们传入的参数是led_table[i]和
led_cfg_table[i],
/*GPIOsizesforvariousSoCs:
*
*
2442
*24102412244024432416
*--------------------
*A23
22
25
16
25
*B11
11
11
9
*C16
15
16
*D16
*E16
16
16
*F8
8
8
8
*G16
*H11
9
15
15
*J--
--
13
--
*K--
--
*L--
7
*M--
2
2
*/
structs3c_gpio_chip
s3c24xx_gpios[]={
[0]={
.base=S3C2410_GPACON,
//datasheet上地址为0x56000000
//#defineS3C2410_GPACON
S3C2410_GPIOREG(0x00)
#defineS3C2410_GPIOREG(x)((x)+S3C24XX_VA_GPIO)
#defineS3C24XX_VA_GPIO
((S3C24XX_PA_GPIO-S3C24XX_PA_UART)+S3C24XX_VA_UART)
S3C24XX_PA_GPIO相当于(0x15600000)
S3C24XX_PA_UART相当于(0x15000000)
#defineS3C_VA_UART
S3C_ADDR(0x01000000)
/*UART*/
#defineS3C_ADDR_BASE0xF6000000
#ifndef__ASSEMBLY__
#defineS3C_ADDR(x)((void__iomem__force*