GPIO驱动.docx
- 文档编号:11703217
- 上传时间:2023-03-30
- 格式:DOCX
- 页数:25
- 大小:60.39KB
GPIO驱动.docx
《GPIO驱动.docx》由会员分享,可在线阅读,更多相关《GPIO驱动.docx(25页珍藏版)》请在冰豆网上搜索。
GPIO驱动
GPIO驱动相关笔记
2011-03-2722:
54 529人阅读 评论
(2) 收藏 举报
打算跟着友善之臂的《mini2440linux移植开发指南》来做个LED驱动,虽然LED的原理简单得不能再简单了,但是要把kernel中针对于s3c24**的GPIO的一些数据结构,还有函数搞清楚也不是那么轻松的事,所以本文主要简单地说明下LED驱动中的相关数据结构以及函数/宏的定义,并对驱动加以验证
***************************************************************************
注意:
在/arch/arm/mach-s3c2410/include/mach/gpio-fns.h源代码中有如下说明:
16/*Thesefunctionsareintheto-be-removedcategoryanditisstrongly
17*encouragednottousetheseinnewcode.Theywillbemarkeddeprecated
18*verysoon.
19*
20*Mostofthefunctionalitycanbeeitherreplacedbythegpiocfgcalls
21*forthes3cplatformorbythegenericGPIOlibAPI.
22*
23*Asof2.6.35-rc,thesewillberemoved,withthefewdriversusingthem
24*eitherreplacedorgivenawrapperuntilthecallscanberemoved.
25*/
该头文件包括:
staticinlinevoids3c2410_gpio_cfgpin(unsignedintpin,unsignedintcfg)
该函数直接使用
linux/arch/arm/plat-s3c/gpio-config.c中的
ints3c_gpio_cfgpin(unsignedintpin,unsignedintconfig)
即可
***************************************************************************
首先看一下设备初始化程序:
85/*
86*设备初始化
87*/
88staticint__initdev_init(void)
89{
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"configpin%dfailed",i);
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
30 S3C2410_GPB(5)相当于37
31 S3C2410_GPB(6)相当于38
32 S3C2410_GPB(7)相当于39
33 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)
//#define s3c_gpio_unlock(_oc,_fl)spin_unlock_irqrestore(&(_oc)->lock,_fl)
//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,
};
int 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< 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情况 int s3c_gpio_setcfg_s3c24xx(structs3c_gpio_chip*chip, unsignedintoff,unsignedintcfg) { void__iomem*reg=chip->base; unsignedintshift=off*2; //每个GPX对应2位 u32con; if(s3c_gpio_is_cfg_special(cfg)){ cfg&=0xf; if(cfg>3) return-EINVAL; cfg<<=shift; //将cfg的0,1两位左移offset } con=__raw_readl(reg); //读对应的GPXCON值 con&=~(0x3< con|=cfg; //设置config值 __raw_writel(con,reg); //写入新的GPXCON return0; } returnret; } //end s3c_gpio_cfgpin 这里涉及到了一个重要的数据结构,s3c_gpio_chip,此数据结构比较复杂,我贴出这个数据结构的结构图: 、 这个重要的数据结构中可以记录每个GPIO所需要的所有数据,后面会遇到的s3c24xx_gpios[]结构体就是该结构体的集合,描述了芯片中所有的GPIO端口,之后我们需要时时回头看看这个结构。 我们先来看s3c_gpiolib_getchip ,它实现了返回对应pin值的GPIO结构体首指针的功能 #include 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: 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 11 9 *C16 15 16 16 16 *D16 16 16 16 16 *E16 16 16 16 16 *F8 8 8 8 8 *G16 16 16 16 8 *H11 11 9 15 15 *J-- -- 13 16 -- *K-- -- -- -- 16 *L-- -- -- 15 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*
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- GPIO 驱动
![提示](https://static.bdocx.com/images/bang_tan.gif)